package io.liveoak.spi.resource;

import java.util.Collection;
import java.util.Map;

import io.liveoak.spi.RequestContext;
import io.liveoak.spi.resource.async.PropertySink;
import io.liveoak.spi.resource.async.Resource;
import io.liveoak.spi.resource.async.ResourceSink;
import io.liveoak.spi.resource.async.Responder;
import io.liveoak.spi.state.ResourceState;

/**
 * @author Bob McWhirter
 */
public interface SynchronousResource extends Resource {

    default Collection<? extends Resource> members(RequestContext ctx) throws Exception {
        return null;
    }

    default Resource member(RequestContext ctx, String id) throws Exception {
        Collection<? extends Resource> members = members(ctx);
        if (members == null) {
            return null;
        }
        for (Resource member: members) {
            if (id.equals(member.id())) {
                return member;
            }
        }
        return null;
    }

    default Map<String, ?> properties(RequestContext ctx) throws Exception {
        return null;
    }

    default void properties(ResourceState props) throws Exception {
        // nothing
    }

    @Override
    default void readMembers(RequestContext ctx, ResourceSink sink) throws Exception {
        try {
            Collection<? extends Resource> members = members(ctx);
            if (members != null) {
                for (Resource each : members) {
                    sink.accept(each);
                }
            }
        } catch (Throwable e) {
            sink.error(e);
        } finally {
            sink.complete();
        }
    }

    @Override
    default void readMember(RequestContext ctx, String id, Responder responder) throws Exception {
        Resource member = member(ctx, id);
        if (member == null) {
            responder.noSuchResource(id);
            return;
        }

        responder.resourceRead(member);
    }

    @Override
    default void readProperties(RequestContext ctx, PropertySink sink) throws Exception {
        Map<String, ?> props = properties(ctx);

        if (props != null) {
            for (Map.Entry<String, ?> entry : props.entrySet() ) {
                sink.accept(entry.getKey(), entry.getValue());
            }
        }

        sink.complete();
    }

    @Override
    default void updateProperties(RequestContext ctx, ResourceState state, Responder responder) throws Exception {
        properties( state );
        responder.resourceUpdated( this );
    }
}

@@ -391,12 +391,36 @@
 ter%0A
+ * @author Ken Finnigan%0A
  */%0A
-
 publ
@@ -825,16 +825,17 @@
 e member
+ 
 : member
@@ -1061,32 +1061,130 @@
 rn null;%0A    %7D%0A%0A
+    default void initProperties(ResourceState props) throws Exception %7B%0A        // nothing%0A    %7D%0A%0A
     default void
@@ -2272,17 +2272,16 @@
 trySet()
- 
 ) %7B%0A    
@@ -2388,32 +2388,244 @@
 plete();%0A    %7D%0A%0A
+    @Override%0A    default void initializeProperties(RequestContext ctx, ResourceState state, Responder responder) throws Exception %7B%0A        initProperties(state);%0A        responder.resourceUpdated(this);%0A    %7D%0A%0A
     @Override%0A  
@@ -2760,15 +2760,13 @@
 ies(
- 
 state
- 
 );%0A 
@@ -2802,14 +2802,12 @@
 ted(
- 
 this
- 
 );%0A 

Add synchronous initProperties() to match properties() for update on SynchronousResource