view artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java @ 58:39fec7d714dc

Added a real artifact proxy class to be more flexible with artifact replacements in artifact databases. artifacts/trunk@359 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 23 Nov 2009 11:15:44 +0000
parents 9a29899b31e5
children 89e3de0ee05f
line wrap: on
line source
package de.intevation.artifactdatabase;

import java.util.HashMap;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.List;

import de.intevation.artifacts.ArtifactDatabaseException;
import de.intevation.artifacts.ArtifactDatabase;
import de.intevation.artifacts.ArtifactFactory;
import de.intevation.artifacts.Artifact;
import de.intevation.artifacts.CallContext;
import de.intevation.artifacts.CallMeta;

import de.intevation.artifactdatabase.Backend.PersistentArtifact;

import org.apache.log4j.Logger;

import org.w3c.dom.Document;

import java.io.OutputStream;
import java.io.IOException;

/**
 *  @author Sascha L. Teichmann
 */
public class ArtifactDatabaseImpl
implements   ArtifactDatabase, Id.Filter, Backend.FactoryLookup
{
    private static Logger logger =
        Logger.getLogger(ArtifactDatabaseImpl.class);

    public static final String NO_SUCH_FACTORY =
        "No such factory";

    public static final String NO_SUCH_ARTIFACT =
        "No such artifact";

    public static final String NOT_IN_BACKGROUND =
        "Not in background";

    public static final String INVALID_CALL_STATE =
        "Invalid after call state";

    public static final String CREATION_FAILED =
        "Creation of artifact failed";

    public static final String INTERNAL_ERROR =
        "Creation of artifact failed";

    public class CallContextImpl
    implements   CallContext
    {
        protected PersistentArtifact artifact;
        protected int                action;
        protected CallMeta           callMeta;
        protected HashMap            customValues;

        public CallContextImpl(
            PersistentArtifact artifact, 
            int                action,
            CallMeta           callMeta
        ) {
            this.artifact = artifact;
            this.action   = action;
            this.callMeta = callMeta;
        }

        public void afterCall(int action) {
            this.action = action;
            if (action == BACKGROUND) {
                addIdToBackground(artifact.getId());
            }
        }

        public void afterBackground(int action) {
            if (this.action != BACKGROUND) {
                throw new IllegalStateException(NOT_IN_BACKGROUND);
            }
            fromBackground(artifact, action);
        }

        public Object globalContext() {
            return context;
        }

        public CallMeta getMeta() {
            return callMeta;
        }

        public void postCall() {
            switch (action) {
                case NOTHING:
                    break;
                case TOUCH:
                    artifact.touch();
                    break;
                case STORE:
                    artifact.store();
                    break;
                case BACKGROUND:
                    logger.warn("BACKGROUND processing is not fully implemented, yet!");
                    artifact.store();
                    break;
                default:
                    logger.error(INVALID_CALL_STATE + ": " + action);
                    throw new IllegalStateException(INVALID_CALL_STATE);
            }
        }

        public Object getContextValue(Object key) {
            return customValues != null
                ? customValues.get(key)
                : null;
        }

        public Object putContextValue(Object key, Object value) {
            if (customValues == null) {
                customValues = new HashMap();
            }
            return customValues.put(key, value);
        }
    } // class CallContextImpl

    public class DeferredOutputImpl
    implements   DeferredOutput
    {
        protected PersistentArtifact artifact;
        protected Document           format;
        protected CallMeta           callMeta;

        public DeferredOutputImpl() {
        }

        public DeferredOutputImpl(
            PersistentArtifact artifact,
            Document           format,
            CallMeta           callMeta
        ) {
            this.artifact = artifact;
            this.format   = format;
            this.callMeta = callMeta;
        }

        public void write(OutputStream output) throws IOException {

            CallContextImpl cc = new CallContextImpl(
                artifact, CallContext.TOUCH, callMeta);

            try {
                artifact.getArtifact().out(format, output, cc);
            }
            finally {
                cc.postCall();
            }
        }
    } // class DeferredOutputImpl

    protected String [][] factoryNamesAndDescription;
    protected HashMap     name2factory;

    protected Backend     backend;
    protected Object      context;

    protected HashSet     backgroundIds;

    public ArtifactDatabaseImpl() {
    }

    public ArtifactDatabaseImpl(FactoryBootstrap bootstrap) {
        this(bootstrap, null);
    }

    public ArtifactDatabaseImpl(FactoryBootstrap bootstrap, Backend backend) {

        backgroundIds = new HashSet();
        name2factory  = new HashMap();

        ArtifactFactory [] factories = bootstrap.getArtifactFactories();
        factoryNamesAndDescription = new String[factories.length][];

        for (int i = 0; i < factories.length; ++i) {

            ArtifactFactory factory = factories[i];

            String name        = factory.getName();
            String description = factory.getDescription();

            factoryNamesAndDescription[i] =
                new String [] { name, description };

            name2factory.put(name, factory);
        }

        context = bootstrap.getContext();

        wireWithBackend(backend);
    }

    public void wireWithBackend(Backend backend) {
        if (backend != null) {
            this.backend = backend;
            backend.setFactoryLookup(this);
        }
    }

    protected void fromBackground(PersistentArtifact artifact, int action) {
        logger.warn("BACKGROUND processing is not fully implemented, yet!");
        switch (action) {
            case CallContext.NOTHING:
                break;
            case CallContext.TOUCH:
                artifact.touch();
                break;
            case CallContext.STORE:
                artifact.store();
                break;
            default:
                logger.warn("operation not allowed in fromBackground");
        }
        removeIdFromBackground(artifact.getId());
    }

    protected void removeIdFromBackground(int id) {
        synchronized (backgroundIds) {
            backgroundIds.remove(Integer.valueOf(id));
        }
    }

    protected void addIdToBackground(int id) {
        synchronized (backgroundIds) {
            backgroundIds.add(Integer.valueOf(id));
        }
    }

    public List filterIds(List ids) {
        int N = ids.size();
        ArrayList out = new ArrayList(N);
        synchronized (backgroundIds) {
            for (int i = 0; i < N; ++i) {
                Id id = (Id)ids.get(i);
                if (!backgroundIds.contains(Integer.valueOf(id.getId()))) {
                    out.add(id);
                }
            }
        }
        return out;
    }

    public String [][] artifactFactoryNamesAndDescriptions() {
        return factoryNamesAndDescription;
    }

    public ArtifactFactory getArtifactFactory(String factoryName) {
        return (ArtifactFactory)name2factory.get(factoryName);
    }

    public Document createArtifactWithFactory(
        String   factoryName, 
        CallMeta callMeta
    )
    throws ArtifactDatabaseException
    {
        ArtifactFactory factory = getArtifactFactory(factoryName);

        if (factory == null) {
            throw new ArtifactDatabaseException(NO_SUCH_FACTORY);
        }

        Artifact artifact = factory.createArtifact(
            backend.newIdentifier(),
            context);

        if (artifact == null) {
            throw new ArtifactDatabaseException(CREATION_FAILED);
        }

        PersistentArtifact persistentArtifact;

        try {
            persistentArtifact = backend.storeInitially(
                artifact,
                factory,
                factory.timeToLiveUntouched(artifact, context));
        }
        catch (Exception e) {
            logger.error(e.getLocalizedMessage(), e);
            throw new ArtifactDatabaseException(CREATION_FAILED);
        }

        CallContextImpl cc = new CallContextImpl(
            persistentArtifact, CallContext.NOTHING, callMeta);

        try {
            return artifact.describe(null, cc);
        }
        finally {
            cc.postCall();
        }
    }

    public Document describe(String identifier, Document data, CallMeta callMeta)
        throws ArtifactDatabaseException
    {
        // TODO: Handle background tasks
        PersistentArtifact artifact = backend.getArtifact(identifier);

        if (artifact == null) {
            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
        }

        CallContextImpl cc = new CallContextImpl(
            artifact, CallContext.TOUCH, callMeta);

        try {
            return artifact.getArtifact().describe(data, cc);
        }
        finally {
            cc.postCall();
        }
    }

    public Document advance(String identifier, Document target, CallMeta callMeta)
        throws ArtifactDatabaseException
    {
        // TODO: Handle background tasks
        PersistentArtifact artifact = backend.getArtifact(identifier);

        if (artifact == null) {
            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
        }

        CallContextImpl cc = new CallContextImpl(
            artifact, CallContext.STORE, callMeta);

        try {
            return artifact.getArtifact().advance(target, cc);
        }
        finally {
            cc.postCall();
        }
    }

    public Document feed(String identifier, Document data, CallMeta callMeta)
        throws ArtifactDatabaseException
    {
        // TODO: Handle background tasks
        PersistentArtifact artifact = backend.getArtifact(identifier);

        if (artifact == null) {
            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
        }

        CallContextImpl cc = new CallContextImpl(
            artifact, CallContext.STORE, callMeta);

        try {
            return artifact.getArtifact().feed(data, cc);
        }
        finally {
            cc.postCall();
        }
    }

    public DeferredOutput out(String identifier, Document format, CallMeta callMeta)
        throws ArtifactDatabaseException
    {
        // TODO: Handle background tasks
        PersistentArtifact artifact = backend.getArtifact(identifier);

        if (artifact == null) {
            throw new ArtifactDatabaseException(NO_SUCH_ARTIFACT);
        }

        return new DeferredOutputImpl(artifact, format, callMeta);
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8:

http://dive4elements.wald.intevation.org