org.cauldron.execution.ContextImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.cauldron.execution.ContextImpl.java

Source

/*
 * Copyright (c) 2004 - 2006, Jonathan Ross <jonross@alum.mit.edu>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

package org.cauldron.execution;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;

import org.cauldron.Context;
import org.cauldron.DataException;
import org.cauldron.Task;
import org.cauldron.TaskException;
import org.cauldron.TaskFactory;
import org.cauldron.data.Conversions;
import org.cauldron.data.TextTemplate;

/**
 * <p>
 * The default implementation of {@link Context}. Create instances through
 * {@link TaskFactory}, not by using the constructors.
 * </p>
 * <p>
 * Context execution variables are supported with a two-level Map-of-Maps;
 * syntax for accessing subcontext Map is <code>"level1key:level2key"</code>.
 * Lack of <code>"level1key:"</code> prefix denotes a default Map.
 * </p>
 */

public class ContextImpl implements Context {
    /** List of tasks on which to run {@link Task#finish} after execution. */
    private ArrayList cleanups;

    /** Is this context running any tasks. */
    private boolean running = false;

    /** Is this context running any async tasks. */
    private boolean async = false;

    /** Map of Maps to store context variables. */
    private HashMap subcontexts;

    /** Task configuration source */
    private TaskConfig config;

    final static Log log = LogFactory.getLog(ContextImpl.class);

    public ContextImpl() {
        subcontexts = new HashMap();
        subcontexts.put("", new HashMap());
    }

    /**
     * Set task configuration source; used by {@link TaskFactory#newContext}.
     */

    public void setSource(Object source) {
        if (source == null)
            config = null;
        else if (source instanceof BeanFactory)
            config = new SpringTaskConfig((BeanFactory) source);
        else if (source instanceof String)
            config = new JNDITaskConfig((String) source);
        else
            throw new IllegalArgumentException("Unsupported task configuration source");
    }

    /**
     * @inheritdoc
     */

    public Object run(Task task, Object input) throws TaskException {
        if (!running)
            cleanups = new ArrayList();

        if (!async)
            cleanups.add(task);
        else
            synchronized (this) {
                cleanups.add(task);
            }

        Object output;

        // Save state for recursive call.
        // running will be set back to false after last task completes.
        // async will be set back to false after last async task completes.

        boolean wasRunning = running;
        boolean wasAsync = async;

        running = true;
        async = async || task instanceof Task.Asynchronous;

        try {
            if (task instanceof Task.Stateful)
                task = (Task) ((Task.Stateful) task).clone();
            output = task.run(this, input);
        } finally {
            running = wasRunning;
            async = wasAsync;
        }

        if (!running)
            for (Iterator ci = cleanups.iterator(); ci.hasNext();)
                ((Task) ci.next()).finish();

        return output;
    }

    /** @inheritDoc */

    public Task find(String name) {
        if (config != null)
            return config.find(name);
        else
            return null;
    }

    /** @inheritDoc */

    public Object get(String key) {
        SubContext sc = getSub(key);
        if (async)
            synchronized (sc.map) {
                return sc.map.get(sc.suffix);
            }
        else
            return sc.map.get(sc.suffix);
    }

    /** @inheritDoc */

    public Object put(String key, Object value) {
        SubContext sc = getSub(key);
        if (async)
            synchronized (sc.map) {
                return sc.map.put(sc.suffix, value);
            }
        else
            return sc.map.put(sc.suffix, value);
    }

    /** @inheritDoc */

    public Object remove(String key) {
        SubContext sc = getSub(key);
        if (async)
            synchronized (sc.map) {
                return sc.map.remove(sc.suffix);
            }
        else
            return sc.map.remove(sc.suffix);
    }

    /** @inheritDoc */

    public Iterator getKeys(String name) {
        SubContext sc = getSub(name);
        List keys = new ArrayList();
        if (async)
            synchronized (sc.map) {
                keys.addAll(sc.map.keySet());
            }
        else
            keys.addAll(sc.map.keySet());
        return keys.iterator();
    }

    /** @inheritDoc */

    public void addSubContext(String name, Map map) throws DataException {
        if (running)
            throw new DataException("Cannot add subcontexts during execution");
        subcontexts.put(name, map);
    }

    /** @inheritDoc */

    public Map getSubContext(String name) throws DataException {
        Map map = getSub(name).map;
        if (async)
            return Collections.synchronizedMap(map);
        else
            return map;
    }

    /** @inheritDoc */

    public String substitute(String s) {
        return TextTemplate.substitute(s, new ContextMap(this));
    }

    /** @inheritDoc */

    public Object convert(Object obj, Class targetType) {
        return Conversions.convert(obj, targetType);
    }

    /**
     * Return subcontext information for the given key.
     * 
     * @throws DataException if the named subcontext does not exist.
     */

    private SubContext getSub(String key) {
        SubContext sc = new SubContext();
        int index = key.indexOf(':');

        if (index == -1) {
            sc.prefix = "";
            sc.suffix = key;
        } else {
            sc.prefix = key.substring(0, index);
            sc.suffix = key.substring(index + 1);
        }

        sc.map = (Map) subcontexts.get(sc.prefix);
        if (sc.map == null)
            throw new DataException("No subcontext Map named " + sc.prefix);

        return sc;
    }

    /*
     * Compound return value used above.
     */

    private class SubContext {
        String prefix, suffix;
        Map map;
    }

}