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 }