001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements.  See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing, software
013 *  distributed under the License is distributed on an "AS IS" BASIS,
014 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 *  See the License for the specific language governing permissions and
016 *  limitations under the License.
017 */
018package org.apache.xbean.recipe;
019
020import java.util.*;
021
022public class DefaultExecutionContext extends ExecutionContext {
023    /**
024     * The source of recipes and existing objects.
025     */
026    private Repository repository;
027
028    /**
029     * Before each recipe is executed it is pushed on the stack.  The
030     * stack is used to detect circular dependencies and so a recipe can
031     * access the caller recipe (e.g. UnsetPropertiesRecipe returns a
032     * map of the caller's unset properties)
033     */
034    private final LinkedList<Recipe> stack = new LinkedList<Recipe>();
035
036    /**
037     * The unresolved references by name.
038     */
039    private final SortedMap<String, List<Reference>> unresolvedRefs = new TreeMap<String, List<Reference>>();
040
041    public DefaultExecutionContext() {
042        this(new DefaultRepository());
043    }
044
045    public DefaultExecutionContext(Repository repository) {
046        if (repository == null) throw new NullPointerException("repository is null");
047        this.repository = repository;
048    }
049
050    public void push(Recipe recipe) {
051        if (stack.contains(recipe)) {
052            ArrayList<Recipe> circularity = new ArrayList<Recipe>(stack.subList(stack.indexOf(recipe), stack.size()));
053
054            // remove anonymous nodes from circularity list
055            for (Iterator<Recipe> iterator = circularity.iterator(); iterator.hasNext();) {
056                Recipe item = iterator.next();
057                if (item != recipe && item.getName() == null) {
058                    iterator.remove();
059                }
060            }
061
062            // add ending node to list so a full circuit is shown
063            circularity.add(recipe);
064
065            throw new CircularDependencyException(circularity);
066        }
067        stack.add(recipe);
068    }
069
070    public Recipe pop() {
071        return stack.removeLast();
072    }
073
074    public LinkedList<Recipe> getStack() {
075        return new LinkedList<Recipe>(stack);
076    }
077
078    public Repository getRepository() {
079        return repository;
080    }
081
082    public void setRepository(Repository repository) {
083        if (repository == null) throw new NullPointerException("repository is null");
084        this.repository = repository;
085    }
086
087    public boolean containsObject(String name) {
088        boolean contains = repository.contains(name);
089        return contains;
090    }
091
092    public Object getObject(String name) {
093        Object object = repository.get(name);
094        return object;
095    }
096
097    public void addObject(String name, Object object) {
098        repository.add(name, object);
099
100        // set any pending references
101        List<Reference> list = unresolvedRefs.remove(name);
102        if (list != null) {
103            for (Reference Reference : list) {
104                Reference.set(object);
105            }
106        }
107    }
108
109    public void addReference(Reference reference) {
110        Object value = repository.get(reference.getName());
111        if (value != null && !(value instanceof Recipe)) {
112            reference.set(value);
113        } else {
114            List<Reference> list = unresolvedRefs.get(reference.getName());
115            if (list == null) {
116                list = new ArrayList<Reference>();
117                unresolvedRefs.put(reference.getName(), list);
118            }
119            list.add(reference);
120        }
121    }
122
123    public SortedMap<String, List<Reference>> getUnresolvedRefs() {
124        return unresolvedRefs;
125    }
126
127    public ClassLoader getClassLoader() {
128        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
129        if (classLoader == null) classLoader = getClass().getClassLoader();
130        return classLoader;
131    }
132}