sascha@13: package de.intevation.artifactdatabase;
sascha@13: 
sascha@13: import java.util.HashMap;
sascha@32: import java.util.HashSet;
sascha@32: import java.util.ArrayList;
sascha@32: import java.util.List;
sascha@13: 
sascha@32: import de.intevation.artifacts.ArtifactDatabaseException;
sascha@13: import de.intevation.artifacts.ArtifactDatabase;
sascha@13: import de.intevation.artifacts.ArtifactFactory;
sascha@13: import de.intevation.artifacts.Artifact;
sascha@32: import de.intevation.artifacts.CallContext;
sascha@32: 
sascha@32: import de.intevation.artifactdatabase.Backend.PersistentArtifact;
sascha@32: 
sascha@32: import org.apache.log4j.Logger;
sascha@32: 
sascha@32: import org.w3c.dom.Document;
sascha@32: 
sascha@32: import java.io.OutputStream;
sascha@32: import java.io.IOException;
sascha@13: 
sascha@13: /**
sascha@13:  *  @author Sascha L. Teichmann
sascha@13:  */
sascha@13: public class ArtifactDatabaseImpl
sascha@32: implements   ArtifactDatabase, Id.Filter
sascha@13: {
sascha@32:     private static Logger logger =
sascha@32:         Logger.getLogger(ArtifactDatabaseImpl.class);
sascha@13: 
sascha@32:     public static final String NO_SUCH_FACTORY =
sascha@32:         "No such factory";
sascha@32: 
sascha@32:     public static final String NO_SUCH_ARTIFACT =
sascha@32:         "No such artifact";
sascha@32: 
sascha@32:     public static final String NOT_IN_BACKGROUND =
sascha@32:         "Not in background";
sascha@32: 
sascha@32:     public static final String INVALID_CALL_STATE =
sascha@32:         "Invalid after call state";
sascha@32: 
sascha@32:     public static final String CREATION_FAILED =
sascha@32:         "Creation of artifact failed";
sascha@32: 
sascha@32:     public static final String INTERNAL_ERROR =
sascha@32:         "Creation of artifact failed";
sascha@32: 
sascha@32:     public class CallContextImpl
sascha@32:     implements   CallContext
sascha@32:     {
sascha@32:         protected PersistentArtifact artifact;
sascha@32:         protected int                action;
sascha@32: 
sascha@32:         public CallContextImpl(PersistentArtifact artifact, int action) {
sascha@32:             this.artifact = artifact;
sascha@32:             this.action   = action;
sascha@32:         }
sascha@32: 
sascha@32:         public void afterCall(int action) {
sascha@32:             this.action = action;
sascha@32:             if (action == BACKGROUND) {
sascha@32:                 addIdToBackground(artifact.getId());
sascha@32:             }
sascha@32:         }
sascha@32: 
sascha@32:         public void afterBackground(int action) {
sascha@32:             if (this.action != BACKGROUND) {
sascha@32:                 throw new IllegalStateException(NOT_IN_BACKGROUND);
sascha@32:             }
sascha@32:             fromBackground(artifact, action);
sascha@32:         }
sascha@32: 
sascha@32:         public Object globalContext() {
sascha@32:             return context;
sascha@32:         }
sascha@32: 
sascha@32:         public void postCall() {
sascha@32:             switch (action) {
sascha@32:                 case NOTHING:
sascha@32:                     break;
sascha@32:                 case TOUCH:
sascha@32:                     artifact.touch();
sascha@32:                     break;
sascha@32:                 case STORE:
sascha@32:                     artifact.store();
sascha@32:                     break;
sascha@32:                 case BACKGROUND:
sascha@32:                     logger.warn("BACKGROUND processing is not fully implemented, yet!");
sascha@32:                     artifact.store();
sascha@32:                     break;
sascha@32:                 default:
sascha@32:                     logger.error(INVALID_CALL_STATE + ": " + action);
sascha@32:                     throw new IllegalStateException(INVALID_CALL_STATE);
sascha@32:             }
sascha@32:         }
sascha@32:     } // class CallContextImpl
sascha@32: 
sascha@32:     public class DeferredOutputImpl
sascha@32:     implements   DeferredOutput
sascha@32:     {
sascha@32:         protected PersistentArtifact artifact;
sascha@32:         protected Document           format;
sascha@32: 
sascha@32:         public DeferredOutputImpl() {
sascha@32:         }
sascha@32: 
sascha@32:         public DeferredOutputImpl(
sascha@32:             PersistentArtifact artifact, 
sascha@32:             Document           format
sascha@32:         ) {
sascha@32:             this.artifact = artifact;
sascha@32:             this.format   = format;
sascha@32:         }
sascha@32: 
sascha@32:         public void write(OutputStream output) throws IOException {
sascha@32: 
sascha@32:             CallContextImpl cc = new CallContextImpl(
sascha@32:                 artifact, CallContext.TOUCH);
sascha@32: 
sascha@32:             try {
sascha@32:                 artifact.getArtifact().out(format, output, cc);
sascha@32:             }
sascha@32:             finally {
sascha@32:                 cc.postCall();
sascha@32:             }
sascha@32:         }
sascha@32:     } // class DeferredOutputImpl
sascha@32: 
sascha@32:     protected String [][] factoryNamesAndDescription;
sascha@32:     protected HashMap     name2factory;
sascha@32: 
sascha@32:     protected Backend     backend;
sascha@32:     protected Object      context;
sascha@32: 
sascha@32:     protected HashSet     backgroundIds;
sascha@13: 
sascha@13:     public ArtifactDatabaseImpl() {
sascha@13:     }
sascha@13: 
sascha@13:     public ArtifactDatabaseImpl(FactoryBootstrap bootstrap, Backend backend) {
sascha@32: 
sascha@32:         backgroundIds = new HashSet();
sascha@32:         name2factory  = new HashMap();
sascha@13: 
sascha@13:         ArtifactFactory [] factories = bootstrap.getArtifactFactories();
sascha@32:         factoryNamesAndDescription = new String[factories.length][];
sascha@13: 
sascha@13:         for (int i = 0; i < factories.length; ++i) {
sascha@32: 
sascha@13:             ArtifactFactory factory = factories[i];
sascha@32: 
sascha@32:             String name        = factory.getName();
sascha@32:             String description = factory.getDescription();
sascha@32: 
sascha@32:             factoryNamesAndDescription[i] =
sascha@32:                 new String [] { name, description };
sascha@32: 
sascha@32:             name2factory.put(name, factory);
sascha@13:         }
sascha@13: 
sascha@13:         context = bootstrap.getContext();
sascha@26: 
sascha@26:         this.backend = backend;
sascha@13:     }
sascha@13: 
sascha@32:     protected void fromBackground(PersistentArtifact artifact, int action) {
sascha@32:         logger.warn("BACKGROUND processing is not fully implemented, yet!");
sascha@32:         switch (action) {
sascha@32:             case CallContext.NOTHING:
sascha@32:                 break;
sascha@32:             case CallContext.TOUCH:
sascha@32:                 artifact.touch();
sascha@32:                 break;
sascha@32:             case CallContext.STORE:
sascha@32:                 artifact.store();
sascha@32:                 break;
sascha@32:             default:
sascha@32:                 logger.warn("operation not allowed in fromBackground");
sascha@32:         }
sascha@32:         removeIdFromBackground(artifact.getId());
sascha@13:     }
sascha@13: 
sascha@32:     protected void removeIdFromBackground(int id) {
sascha@32:         synchronized (backgroundIds) {
sascha@32:             backgroundIds.remove(Integer.valueOf(id));
sascha@32:         }
sascha@13:     }
sascha@13: 
sascha@32:     protected void addIdToBackground(int id) {
sascha@32:         synchronized (backgroundIds) {
sascha@32:             backgroundIds.add(Integer.valueOf(id));
sascha@32:         }
sascha@32:     }
sascha@32: 
sascha@32:     public List filterIds(List ids) {
sascha@32:         int N = ids.size();
sascha@32:         ArrayList out = new ArrayList(N);
sascha@32:         synchronized (backgroundIds) {
sascha@32:             for (int i = 0; i < N; ++i) {
sascha@32:                 Id id = (Id)ids.get(i);
sascha@32:                 if (!backgroundIds.contains(Integer.valueOf(id.getId()))) {
sascha@32:                     out.add(id);
sascha@32:                 }
sascha@32:             }
sascha@32:         }
sascha@32:         return out;
sascha@32:     }
sascha@32: 
sascha@32:     public String [][] artifactFactoryNamesAndDescriptions() {
sascha@32:         return factoryNamesAndDescription;
sascha@32:     }
sascha@32: 
sascha@32:     public Document createArtifactWithFactory(String factoryName)
sascha@32:         throws ArtifactDatabaseException 
sascha@32:     {
sascha@32:         ArtifactFactory factory = (ArtifactFactory)name2factory.get(
sascha@32:             factoryName);
sascha@32: 
sascha@32:         if (factory == null) {
sascha@32:             throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
sascha@32:         }
sascha@32: 
sascha@32:         Artifact artifact = factory.createArtifact(
sascha@32:             backend.newIdentifier(),
sascha@32:             context);
sascha@32: 
sascha@32:         if (artifact == null) {
sascha@32:             throw new ArtifactDatabaseException(CREATION_FAILED);
sascha@32:         }
sascha@32: 
sascha@32:         PersistentArtifact persistentArtifact;
sascha@32: 
sascha@32:         try {
sascha@32:             persistentArtifact = backend.storeInitially(
sascha@32:                 artifact,
sascha@32:                 factory.timeToLiveUntouched(artifact, context));
sascha@32:         }
sascha@32:         catch (Exception e) {
sascha@32:             logger.error(e.getLocalizedMessage(), e);
sascha@32:             throw new ArtifactDatabaseException(CREATION_FAILED);
sascha@32:         }
sascha@32: 
sascha@32:         CallContextImpl cc = new CallContextImpl(
sascha@32:             persistentArtifact, CallContext.NOTHING);
sascha@32: 
sascha@32:         try {
sascha@32:             return artifact.describe(cc);
sascha@32:         }
sascha@32:         finally {
sascha@32:             cc.postCall();
sascha@32:         }
sascha@32:     }
sascha@32: 
sascha@32:     public Document describe(String identifier)
sascha@32:         throws ArtifactDatabaseException
sascha@32:     {
sascha@32:         // TODO: Handle background tasks
sascha@32:         PersistentArtifact artifact = backend.getArtifact(identifier);
sascha@32: 
sascha@32:         if (artifact == null) {
sascha@32:             throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
sascha@32:         }
sascha@32: 
sascha@32:         CallContextImpl cc = new CallContextImpl(
sascha@32:             artifact, CallContext.TOUCH);
sascha@32: 
sascha@32:         try {
sascha@32:             return artifact.getArtifact().describe(cc);
sascha@32:         }
sascha@32:         finally {
sascha@32:             cc.postCall();
sascha@32:         }
sascha@32:     }
sascha@32: 
sascha@32:     public Document advance(String identifier, Document target)
sascha@32:         throws ArtifactDatabaseException
sascha@32:     {
sascha@32:         // TODO: Handle background tasks
sascha@32:         PersistentArtifact artifact = backend.getArtifact(identifier);
sascha@32: 
sascha@32:         if (artifact == null) {
sascha@32:             throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
sascha@32:         }
sascha@32: 
sascha@32:         CallContextImpl cc = new CallContextImpl(
sascha@32:             artifact, CallContext.STORE);
sascha@32: 
sascha@32:         try {
sascha@32:             return artifact.getArtifact().advance(target, cc);
sascha@32:         }
sascha@32:         finally {
sascha@32:             cc.postCall();
sascha@32:         }
sascha@32:     }
sascha@32: 
sascha@32:     public Document feed(String identifier, Document data)
sascha@32:         throws ArtifactDatabaseException
sascha@32:     {
sascha@32:         // TODO: Handle background tasks
sascha@32:         PersistentArtifact artifact = backend.getArtifact(identifier);
sascha@32: 
sascha@32:         if (artifact == null) {
sascha@32:             throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
sascha@32:         }
sascha@32: 
sascha@32:         CallContextImpl cc = new CallContextImpl(
sascha@32:             artifact, CallContext.STORE);
sascha@32: 
sascha@32:         try {
tim@36:             return artifact.getArtifact().feed(data, cc);
sascha@32:         }
sascha@32:         finally {
sascha@32:             cc.postCall();
sascha@32:         }
sascha@32:     }
sascha@32: 
sascha@32:     public DeferredOutput out(String identifier, Document format)
sascha@32:         throws ArtifactDatabaseException
sascha@32:     {
sascha@32:         // TODO: Handle background tasks
sascha@32:         PersistentArtifact artifact = backend.getArtifact(identifier);
sascha@32: 
sascha@32:         if (artifact == null) {
sascha@32:             throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
sascha@32:         }
sascha@32: 
sascha@32:         return new DeferredOutputImpl(artifact, format);
sascha@13:     }
sascha@13: }
sascha@13: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: