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     */
018    package org.apache.xbean.recipe;
019    
020    import java.util.*;
021    
022    public 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    }