geronimo-xbean-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d...@apache.org
Subject svn commit: r617547 [1/3] - in /geronimo/xbean/trunk/xbean-reflect/src: main/java/org/apache/xbean/recipe/ test/java/org/apache/xbean/recipe/
Date Fri, 01 Feb 2008 16:23:29 GMT
Author: dain
Date: Fri Feb  1 08:23:21 2008
New Revision: 617547

URL: http://svn.apache.org/viewvc?rev=617547&view=rev
Log:
Work in progress on graph building

Added:
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AllPropertiesRecipe.java
      - copied, changed from r614104, geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/UnsetPropertiesRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CircularDependencyException.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/Construction.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ConstructionStrategy.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/DefaultExecutionContext.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/DefaultRepository.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExecutionContext.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExplicitConstruction.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExplicitConstructionStrategy.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/NoSuchObjectException.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectGraph.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeVisitor.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/Reference.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReferenceRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/Repository.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/UnresolvedReferencesException.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/AllPropertiesTest.java
      - copied, changed from r614104, geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/UnsetPropertiesTest.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/CollectionTest.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/ObjectGraphTest.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/ReferenceTest.java
Removed:
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AbstractSecretRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/SecretRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/StaticRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ValueRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/StaticRecipeTest.java
Modified:
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AbstractRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/MapRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/Option.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/Recipe.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeHelper.java
    geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/UnsetPropertiesRecipe.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/Car.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/CaseInsensitivePropertiesTest.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/ObjectRecipeTest.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/Person.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/PersonFactory.java
    geronimo/xbean/trunk/xbean-reflect/src/test/java/org/apache/xbean/recipe/UnsetPropertiesTest.java

Modified: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AbstractRecipe.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AbstractRecipe.java?rev=617547&r1=617546&r2=617547&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AbstractRecipe.java (original)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AbstractRecipe.java Fri Feb  1 08:23:21 2008
@@ -17,14 +17,128 @@
  */
 package org.apache.xbean.recipe;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
 public abstract class AbstractRecipe implements Recipe {
+    private static final AtomicLong ID = new AtomicLong(1);
+    private long id;
+    private String name;
+
+    protected AbstractRecipe() {
+        id = ID.getAndIncrement();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        if (name == null) throw new NullPointerException("name is null");
+        this.name = name;
+    }
+
     public float getPriority() {
         return 0;
     }
 
     public Object create() throws ConstructionException {
-        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
-        if (classLoader == null) classLoader = getClass().getClassLoader();
-        return create(classLoader);
+        return create(null);
+    }
+
+    public final Object create(ClassLoader classLoader) throws ConstructionException {
+        // if classloader was passed in, set it on the thread
+        ClassLoader oldClassLoader = null;
+        if (classLoader != null) {
+            oldClassLoader = Thread.currentThread().getContextClassLoader();
+            Thread.currentThread().setContextClassLoader(classLoader);
+        }
+
+        try {
+            return create(Object.class, false);
+        } finally {
+            // if we set a thread context class loader, reset it
+            if (classLoader != null) {
+                Thread.currentThread().setContextClassLoader(oldClassLoader);
+            }
+        }
+    }
+
+    public final Object create(Class expectedType, boolean lazyRefAllowed) throws ConstructionException {
+        if (expectedType == null) throw new NullPointerException("expectedType is null");
+
+        // assure there is a valid thread context class loader
+        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+        if (oldClassLoader == null) {
+            Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+        }
+
+        // if there is no execution context, create one
+        boolean createNewContext = !ExecutionContext.isContextSet();
+        if (createNewContext) {
+            ExecutionContext.setContext(new DefaultExecutionContext());
+        }
+
+        try {
+            ExecutionContext context = ExecutionContext.getContext();
+
+            // if this recipe has already been executed in this context, return the currently registered value
+            if (getName() != null && context.containsObject(getName()) && !(context.getObject(getName()) instanceof Recipe)) {
+                return context.getObject(getName());
+            }
+
+            // execute the recipe
+            context.push(this);
+            try {
+                return internalCreate(expectedType, lazyRefAllowed);
+            } finally {
+                Recipe popped = context.pop();
+                if (popped != this) {
+                    //noinspection ThrowFromFinallyBlock
+                    throw new IllegalStateException("Internal Error: recipe stack is corrupt:" +
+                            " Expected " + this + " to be popped of the stack but " + popped + " was");
+                }
+            }
+        } finally {
+            // if we set a new execution context, remove it from the thread
+            if (createNewContext) {
+                ExecutionContext context = ExecutionContext.getContext();
+                ExecutionContext.setContext(null);
+
+                Map<String,List<Reference>> unresolvedRefs = context.getUnresolvedRefs();
+                if (!unresolvedRefs.isEmpty()) {
+                    throw new UnresolvedReferencesException(unresolvedRefs);
+                }
+            }
+
+            // if we set a thread context class loader, clear it
+            if (oldClassLoader == null) {
+                Thread.currentThread().setContextClassLoader(null);
+            }
+        }
+    }
+
+    protected abstract Object internalCreate(Class expectedType, boolean lazyRefAllowed) throws ConstructionException;
+
+    public List<Recipe> getNestedRecipes() {
+        return Collections.emptyList();
+    }
+
+    public List<Recipe> getConstructorRecipes() {
+        return Collections.emptyList();
+    }
+
+    public String toString() {
+        if (name != null) {
+            return name;
+        }
+
+        String string = getClass().getSimpleName();
+        if (string.endsWith("Recipe")) {
+            string = string.substring(0, string.length() - "Recipe".length());
+        }
+        return string + "@" + id;
     }
 }

Copied: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AllPropertiesRecipe.java (from r614104, geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/UnsetPropertiesRecipe.java)
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AllPropertiesRecipe.java?p2=geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AllPropertiesRecipe.java&p1=geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/UnsetPropertiesRecipe.java&r1=614104&r2=617547&rev=617547&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/UnsetPropertiesRecipe.java (original)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/AllPropertiesRecipe.java Fri Feb  1 08:23:21 2008
@@ -20,27 +20,30 @@
 import java.util.Map;
 import java.util.Properties;
 
-public class UnsetPropertiesRecipe extends AbstractSecretRecipe {
-    public float getPriority() {
-        return 100;
-    }
-
-    public boolean canCreate(Class type, ClassLoader classLoader) {
+public class AllPropertiesRecipe extends AbstractRecipe {
+    public boolean canCreate(Class type) {
         return type.isAssignableFrom(Properties.class);
     }
 
-    public Object create(Recipe outerRecipe, ClassLoader classLoader) throws ConstructionException {
+    protected Object internalCreate(Class expectedType, boolean lazyRefAllowed) throws ConstructionException {
+        Recipe outerRecipe = RecipeHelper.getCaller();
         if (!(outerRecipe instanceof ObjectRecipe)) {
             throw new ConstructionException("UnsetPropertiesRecipe can only be nested in an ObjectRecipe: outerRecipe=" + outerRecipe);
         }
         ObjectRecipe objectRecipe = (ObjectRecipe) outerRecipe;
-        Map<String,Object> unsetProperties = objectRecipe.getUnsetProperties();
+        Map<String,Object> allProperties = objectRecipe.getProperties();
 
         // copy to a properties object
         Properties properties = new Properties();
-        for (Map.Entry<String, Object> entry : unsetProperties.entrySet()) {
+        for (Map.Entry<String, Object> entry : allProperties.entrySet()) {
             properties.put(entry.getKey(), entry.getValue());
         }
+
+        // add to execution context if name is specified
+        if (getName() != null) {
+            ExecutionContext.getContext().addObject(getName(), properties);
+        }
+        
         return properties;
     }
-}
+}
\ No newline at end of file

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CircularDependencyException.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CircularDependencyException.java?rev=617547&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CircularDependencyException.java (added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CircularDependencyException.java Fri Feb  1 08:23:21 2008
@@ -0,0 +1,48 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xbean.recipe;
+
+import java.util.List;
+
+public class CircularDependencyException extends ConstructionException {
+    private final List<Recipe> circularDependency;
+
+    public CircularDependencyException(List<Recipe> circularDependency) {
+        super(circularDependency.toString());
+        this.circularDependency = circularDependency;
+    }
+
+    public CircularDependencyException(String message, List<Recipe> circularDependency) {
+        super(message + ": " + circularDependency);
+        this.circularDependency = circularDependency;
+    }
+
+    public CircularDependencyException(String message, Throwable cause, List<Recipe> circularDependency) {
+        super(message + ": " + circularDependency, cause);
+        this.circularDependency = circularDependency;
+    }
+
+    public CircularDependencyException(Throwable cause, List<Recipe> circularDependency) {
+        super(circularDependency.toString(), cause);
+        this.circularDependency = circularDependency;
+    }
+
+    public List<Recipe> getCircularDependency() {
+        return circularDependency;
+    }
+}

Modified: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java?rev=617547&r1=617546&r2=617547&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java (original)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java Fri Feb  1 08:23:21 2008
@@ -16,9 +16,11 @@
  */
 package org.apache.xbean.recipe;
 
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Iterator;
+import java.util.Collections;
+import java.util.EnumSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -30,197 +32,218 @@
  */
 public class CollectionRecipe extends AbstractRecipe {
     private final List<Object> list;
-    private final String type;
+    private String typeName;
+    private Class typeClass;
+    private final EnumSet<Option> options = EnumSet.noneOf(Option.class);
 
     public CollectionRecipe() {
         list = new ArrayList<Object>();
-        type = ArrayList.class.getName();
     }
 
     public CollectionRecipe(String type) {
         list = new ArrayList<Object>();
-        this.type = type;
+        this.typeName = type;
     }
 
     public CollectionRecipe(Class type) {
         if (type == null) throw new NullPointerException("type is null");
-        if (!RecipeHelper.hasDefaultConstructor(type)) throw new IllegalArgumentException("Type does not have a default constructor " + type);
+        if (!RecipeHelper.hasDefaultConstructor(type)) throw new IllegalArgumentException("Collection type does not have a default constructor " + type);
+
         this.list = new ArrayList<Object>();
-        this.type = type.getName();
+        this.typeClass = type;
     }
 
-    public CollectionRecipe(Collection collection) {
+    public CollectionRecipe(Collection<?> collection) {
         if (collection == null) throw new NullPointerException("collection is null");
 
-        this.list = new ArrayList<Object>(collection.size());
+        this.list = new ArrayList<Object>(collection);
 
-        // If the specified set has a default constructor we will recreate the set, otherwise we use a the default
+        // If the specified collection has a default constructor we will recreate the collection, otherwise we use a the default
         if (RecipeHelper.hasDefaultConstructor(collection.getClass())) {
-            this.type = collection.getClass().getName();
+            this.typeClass = collection.getClass();
         } else if (collection instanceof SortedSet) {
-            this.type = TreeSet.class.getName();
+            this.typeClass = SortedSet.class;
         } else if (collection instanceof Set) {
-            this.type = LinkedHashSet.class.getName();
+            this.typeClass = Set.class;
+        } else if (collection instanceof List) {
+            this.typeClass = List.class;
         } else {
-            this.type = ArrayList.class.getName();
+            this.typeClass = Collection.class;
         }
-        addAll(collection);
     }
 
-    public CollectionRecipe(String type, Collection collection) {
-        if (type == null) throw new NullPointerException("type is null");
-        if (collection == null) throw new NullPointerException("collection is null");
-        this.list = new ArrayList<Object>(collection.size());
-        this.type = type;
-        addAll(collection);
+    public CollectionRecipe(CollectionRecipe collectionRecipe) {
+        if (collectionRecipe == null) throw new NullPointerException("setRecipe is null");
+        this.typeName = collectionRecipe.typeName;
+        this.typeClass = collectionRecipe.typeClass;
+        list = new ArrayList<Object>(collectionRecipe.list);
     }
 
-    public CollectionRecipe(Class type, Collection collection) {
-        if (type == null) throw new NullPointerException("type is null");
-        if (!RecipeHelper.hasDefaultConstructor(type)) throw new IllegalArgumentException("Type does not have a default constructor " + type);
-        if (collection == null) throw new NullPointerException("collection is null");
-        this.list = new ArrayList<Object>(collection.size());
-        this.type = type.getName();
-        addAll(collection);
+    public void allow(Option option) {
+        options.add(option);
     }
 
-    public CollectionRecipe(CollectionRecipe collectionRecipe) {
-        if (collectionRecipe == null) throw new NullPointerException("setRecipe is null");
-        this.type = collectionRecipe.type;
-        list = new ArrayList<Object>(collectionRecipe.list);
+    public void disallow(Option option) {
+        options.remove(option);
+    }
+
+    public List<Recipe> getNestedRecipes() {
+        List<Recipe> nestedRecipes = new ArrayList<Recipe>(list.size());
+        for (Object o : list) {
+            if (o instanceof Recipe) {
+                Recipe recipe = (Recipe) o;
+                nestedRecipes.add(recipe);
+            }
+        }
+        return nestedRecipes;
     }
 
-    public boolean canCreate(Class type, ClassLoader classLoader) {
-        Class myType = getType(classLoader);
-        return type.isAssignableFrom(myType);
+    public List<Recipe> getConstructorRecipes() {
+        if (!options.contains(Option.LAZY_ASSIGNMENT)) {
+            return getNestedRecipes();
+        }
+        return Collections.emptyList();
     }
 
-    public Collection create(ClassLoader classLoader) {
-        Class setType = getType(classLoader);
+    public boolean canCreate(Class expectedType) {
+        Class myType = getType(expectedType);
+        return expectedType.isAssignableFrom(myType);
+    }
 
-        if (!RecipeHelper.hasDefaultConstructor(setType)) {
-            throw new ConstructionException("Type does not have a default constructor " + type);
+    protected Object internalCreate(Class expectedType, boolean lazyRefAllowed) throws ConstructionException {
+        Class type = getType(expectedType);
+
+        if (!RecipeHelper.hasDefaultConstructor(type)) {
+            throw new ConstructionException("Type does not have a default constructor " + type.getName());
         }
 
+        // create collection instance
         Object o;
         try {
-            o = setType.newInstance();
+            o = type.newInstance();
         } catch (Exception e) {
-            throw new ConstructionException("Error while creating set instance: " + type);
+            throw new ConstructionException("Error while creating collection instance: " + type.getName());
         }
-
-        if(!(o instanceof Collection)) {
-            throw new ConstructionException("Specified set type does not implement the Collection interface: " + type);
+        if (!(o instanceof Collection)) {
+            throw new ConstructionException("Specified collection type does not implement the Collection interface: " + type.getName());
         }
-
         Collection instance = (Collection) o;
-        int i =0;
-        for (Iterator iterator = list.iterator(); iterator.hasNext();) {
-            Object value = iterator.next();
-            if (value instanceof Recipe) {
-                Recipe recipe = (Recipe) value;
-                try {
-                    value = recipe.create(classLoader);
-                } catch (ConstructionException e) {
-                    e.setPrependAttributeName("[" + type + " item " + i + "]");
-                    throw e;
+
+        // add to execution context if name is specified
+        if (getName() != null) {
+            ExecutionContext.getContext().addObject(getName(), instance);
+        }
+
+        // get component type
+        Class<?> componentType = Object.class;
+        Type[] typeParameters = RecipeHelper.getTypeParameters(Collection.class, expectedType);
+        if (typeParameters != null && typeParameters.length == 1 && typeParameters[0] instanceof Class) {
+            componentType = (Class<?>) typeParameters[0];
+        }
+
+        boolean refAllowed = options.contains(Option.LAZY_ASSIGNMENT);
+
+        int index = 0;
+        for (Object value : list) {
+            value = RecipeHelper.convert(componentType, value, refAllowed);
+
+            if (value instanceof Reference) {
+                Reference reference = (Reference) value;
+                if (instance instanceof List) {
+                    // add a null place holder in the list that will be updated later
+                    //noinspection unchecked
+                    instance.add(null);
+                    reference.setAction(new UpdateList((List) instance, index));
+                } else {
+                    reference.setAction(new UpdateCollection(instance));
                 }
+            } else {
+                //noinspection unchecked
+                instance.add(value);
             }
-            //noinspection unchecked
-            instance.add(value);
-            i++;
+            index++;
         }
         return instance;
     }
 
-    private Class getType(ClassLoader classLoader) {
-        Class setType = null;
-        try {
-            setType = Class.forName(type, true, classLoader);
-        } catch (ClassNotFoundException e) {
-            throw new ConstructionException("Type class could not be found: " + type);
+    private Class getType(Class expectedType) {
+        Class type = expectedType;
+        if (typeClass != null || typeName != null) {
+            type = typeClass;
+            if (type == null) {
+                try {
+                    type = RecipeHelper.loadClass(typeName);
+                } catch (ClassNotFoundException e) {
+                    throw new ConstructionException("Type class could not be found: " + typeName);
+                }
+            }
+
+            // if expectedType is a subclass of the assigned type,
+            // we use it assuming it has a default constructor
+            if (type.isAssignableFrom(expectedType) && RecipeHelper.hasDefaultConstructor(expectedType)) {
+                type = expectedType;
+            }
         }
-        return setType;
-    }
 
-    public void add(Boolean value) {
-        if (value == null) throw new NullPointerException("value is null");
-        list.add(value);
+        // no type explicitly set
+        if (RecipeHelper.hasDefaultConstructor(type)) {
+            return expectedType;
+        } else if (expectedType.isAssignableFrom(SortedSet.class)) {
+            return TreeSet.class;
+        } else if (expectedType.isAssignableFrom(Set.class)) {
+            return LinkedHashSet.class;
+        } else if (expectedType.isAssignableFrom(List.class)) {
+            return ArrayList.class;
+        } else {
+            return ArrayList.class;
+        }
     }
 
-    public void add(Character value) {
-        if (value == null) throw new NullPointerException("value is null");
+    public void add(Object value) {
         list.add(value);
     }
 
-    public void add(Byte value) {
-        if (value == null) throw new NullPointerException("value is null");
-        list.add(value);
+    public void addAll(Collection<?> value) {
+        list.addAll(value);
     }
 
-    public void add(Short value) {
-        if (value == null) throw new NullPointerException("value is null");
-        list.add(value);
+    public void remove(Object value) {
+        list.remove(value);
     }
 
-    public void add(Integer value) {
-        if (value == null) throw new NullPointerException("value is null");
-        list.add(value);
+    public void removeAll(Object value) {
+        list.remove(value);
     }
 
-    public void add(Long value) {
-        if (value == null) throw new NullPointerException("value is null");
-        list.add(value);
+    public List<Object> getAll() {
+        return Collections.unmodifiableList(list);
     }
 
-    public void add(Float value) {
-        if (value == null) throw new NullPointerException("value is null");
-        list.add(value);
-    }
+    private static class UpdateCollection implements Reference.Action {
+        private final Collection collection;
 
-    public void add(Double value) {
-        if (value == null) throw new NullPointerException("value is null");
-        list.add(value);
-    }
+        public UpdateCollection(Collection collection) {
+            this.collection = collection;
+        }
 
-    public void add(String value) {
-        if (value == null) throw new NullPointerException("value is null");
-        list.add(value);
+        @SuppressWarnings({"unchecked"})
+        public void onSet(Reference ref) {
+            collection.add(ref.get());
+        }
     }
 
-    public void add(Recipe value) {
-        if (value == null) throw new NullPointerException("value is null");
-        list.add(value);
-    }
+    private static class UpdateList implements Reference.Action {
+        private final List list;
+        private final int index;
 
-    public void addAll(Collection value) {
-        if (value == null) throw new NullPointerException("value is null");
-        for (Iterator iterator = value.iterator(); iterator.hasNext();) {
-            Object o = iterator.next();
-            if (o instanceof Boolean) {
-                add((Boolean)o);
-            } else if (o instanceof Character) {
-                add((Character)o);
-            } else if (o instanceof Byte) {
-                add((Byte)o);
-            } else if (o instanceof Short) {
-                add((Short)o);
-            } else if (o instanceof Integer) {
-                add((Integer)o);
-            } else if (o instanceof Long) {
-                add((Long)o);
-            } else if (o instanceof Float) {
-                add((Float)o);
-            } else if (o instanceof Double) {
-                add((Double)o);
-            } else if (o instanceof String) {
-                add((String)o);
-            } else if (o instanceof Recipe) {
-                add((Recipe)o);
-            } else {
-                add(new ValueRecipe(o));
-            }
+        public UpdateList(List list, int index) {
+            this.list = list;
+            this.index = index;
         }
-    }
 
+        @SuppressWarnings({"unchecked"})
+        public void onSet(Reference ref) {
+            list.set(index, ref.get());
+        }
+    }
 }

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/Construction.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/Construction.java?rev=617547&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/Construction.java (added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/Construction.java Fri Feb  1 08:23:21 2008
@@ -0,0 +1,32 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xbean.recipe;
+
+import java.util.List;
+
+public interface Construction {
+    List<String> getParameterNames();
+
+    List<Class> getParameterTypes();
+
+    Object create(Object... parameters) throws ConstructionException;
+
+    Object callInstanceFactory(Object instance) throws ConstructionException;
+
+    boolean hasInstanceFactory();
+}

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ConstructionStrategy.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ConstructionStrategy.java?rev=617547&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ConstructionStrategy.java (added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ConstructionStrategy.java Fri Feb  1 08:23:21 2008
@@ -0,0 +1,22 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xbean.recipe;
+
+public interface ConstructionStrategy {
+    Construction getConstruction(ObjectRecipe recipe, Class expectedType) throws ConstructionException;
+}

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/DefaultExecutionContext.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/DefaultExecutionContext.java?rev=617547&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/DefaultExecutionContext.java (added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/DefaultExecutionContext.java Fri Feb  1 08:23:21 2008
@@ -0,0 +1,132 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xbean.recipe;
+
+import java.util.*;
+
+public class DefaultExecutionContext extends ExecutionContext {
+    /**
+     * The source of recipes and existing objects.
+     */
+    private Repository repository;
+
+    /**
+     * Before each recipe is executed it is pushed on the stack.  The
+     * stack is used to detect circular dependencies and so a recipe can
+     * access the caller recipe (e.g. UnsetPropertiesRecipe returns a
+     * map of the caller's unset properties)
+     */
+    private final LinkedList<Recipe> stack = new LinkedList<Recipe>();
+
+    /**
+     * The unresolved references by name.
+     */
+    private final SortedMap<String, List<Reference>> unresolvedRefs = new TreeMap<String, List<Reference>>();
+
+    public DefaultExecutionContext() {
+        this(new DefaultRepository());
+    }
+
+    public DefaultExecutionContext(Repository repository) {
+        if (repository == null) throw new NullPointerException("repository is null");
+        this.repository = repository;
+    }
+
+    public void push(Recipe recipe) {
+        if (stack.contains(recipe)) {
+            ArrayList<Recipe> circularity = new ArrayList<Recipe>(stack.subList(stack.indexOf(recipe), stack.size()));
+
+            // remove anonymous nodes from circularity list
+            for (Iterator<Recipe> iterator = circularity.iterator(); iterator.hasNext();) {
+                Recipe item = iterator.next();
+                if (item != recipe && item.getName() == null) {
+                    iterator.remove();
+                }
+            }
+
+            // add ending node to list so a full circuit is shown
+            circularity.add(recipe);
+
+            throw new CircularDependencyException(circularity);
+        }
+        stack.add(recipe);
+    }
+
+    public Recipe pop() {
+        return stack.removeLast();
+    }
+
+    public LinkedList<Recipe> getStack() {
+        return new LinkedList<Recipe>(stack);
+    }
+
+    public Repository getRepository() {
+        return repository;
+    }
+
+    public void setRepository(Repository repository) {
+        if (repository == null) throw new NullPointerException("repository is null");
+        this.repository = repository;
+    }
+
+    public boolean containsObject(String name) {
+        boolean contains = repository.contains(name);
+        return contains;
+    }
+
+    public Object getObject(String name) {
+        Object object = repository.get(name);
+        return object;
+    }
+
+    public void addObject(String name, Object object) {
+        repository.add(name, object);
+
+        // set any pending references
+        List<Reference> list = unresolvedRefs.remove(name);
+        if (list != null) {
+            for (Reference Reference : list) {
+                Reference.set(object);
+            }
+        }
+    }
+
+    public void addReference(String name, Reference reference) {
+        Object value = repository.get(name);
+        if (value != null && !(value instanceof Recipe)) {
+            reference.set(value);
+        } else {
+            List<Reference> list = unresolvedRefs.get(name);
+            if (list == null) {
+                list = new ArrayList<Reference>();
+                unresolvedRefs.put(name, list);
+            }
+            list.add(reference);
+        }
+    }
+
+    public SortedMap<String, List<Reference>> getUnresolvedRefs() {
+        return unresolvedRefs;
+    }
+
+    public ClassLoader getClassLoader() {
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+        if (classLoader == null) classLoader = getClass().getClassLoader();
+        return classLoader;
+    }
+}

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/DefaultRepository.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/DefaultRepository.java?rev=617547&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/DefaultRepository.java (added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/DefaultRepository.java Fri Feb  1 08:23:21 2008
@@ -0,0 +1,62 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xbean.recipe;
+
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+public class DefaultRepository implements Repository {
+    /**
+     * The unmarshaled object instances by name.
+     */
+    private final SortedMap<String, Object> instances = new TreeMap<String, Object>();
+
+    /**
+     * Does this repository contain a object with the specified name.
+     *
+     * @param name the unique name of the object instance
+     * @return true if this repository contain a object with the specified name
+     */
+    public boolean contains(String name) {
+        return instances.containsKey(name);
+    }
+
+    /**
+     * Gets the object or recipe with the specified name from this repository.
+     *
+     * @param name the unique name of the object instance
+     * @return the object instance, a recipe to build the object or null
+     */
+    public Object get(String name) {
+        return instances.get(name);
+    }
+
+    /**
+     * Add an object instance to this repository.
+     *
+     * @param name the unique name of the instance
+     * @param instance the instance
+     * @throws ConstructionException if another object instance is already registered with the name
+     */
+    public void add(String name, Object instance) {
+        if (instances.containsKey(name) && !(instances.get(name) instanceof Recipe)) {
+            throw new ConstructionException("Name " + name + " is already registered to instance " + instance);
+        }
+        instances.put(name, instance);
+    }
+}

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExecutionContext.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExecutionContext.java?rev=617547&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExecutionContext.java (added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExecutionContext.java Fri Feb  1 08:23:21 2008
@@ -0,0 +1,115 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xbean.recipe;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public abstract class ExecutionContext {
+    private static final ThreadLocal<ExecutionContext> context = new ThreadLocal<ExecutionContext>();
+
+    public static boolean isContextSet() {
+        return context.get() != null;
+    }
+
+    public static ExecutionContext getContext() {
+        ExecutionContext executionContext = context.get();
+        if (executionContext == null) {
+            throw new IllegalStateException("Execution context has not been set");
+        }
+        return executionContext;
+    }
+
+    public static ExecutionContext setContext(ExecutionContext newContext) {
+        ExecutionContext oldContext = context.get();
+        context.set(newContext);
+        return oldContext;
+    }
+
+    /**
+     * Adds a recipe to the top of the execution stack.  If the recipe is already on
+     * the stack, a CircularDependencyException is thrown.
+     * @param recipe the recipe to add to the stack
+     * @throws CircularDependencyException if the recipe is already on the stack
+     */
+    public abstract void push(Recipe recipe) throws CircularDependencyException;
+
+    /**
+     * Removes the top recipe from the execution stack.
+     * @return the top recipe on the stack
+     */
+    public abstract Recipe pop();
+
+    /**
+     * Gets a snapshot of the current execution stack.  The returned list is
+     * a snapshot so any modification of the returned list does not modify
+     * the stack contained in this object.
+     * @return a snapshot of the current execution stack
+     */
+    public abstract LinkedList<Recipe> getStack();
+
+    /**
+     * Does this context contain a object with the specified name.
+     *
+     * @param name the unique name of the object instance
+     * @return true if this context contain a object with the specified name
+     */
+    public abstract boolean containsObject(String name);
+
+    /**
+     * Gets the object or recipe with the specified name from the repository.
+     *
+     * @param name the unique name of the object instance
+     * @return the object instance, a recipe to build the object or null
+     */
+    public abstract Object getObject(String name);
+
+    /**
+     * Add an object to the repository.
+     *
+     * @param name the unique name of the object instance
+     * @param object the object instance
+     * @throws ConstructionException if another object instance is already registered with the name
+     */
+    public abstract void addObject(String name, Object object);
+
+    /**
+     * Adds a reference to an object with the specified name.  If an object is already registered under
+     * the specified name, the reference will immedately be set.  Otherwise, the reference will be set
+     * when an object is added with the specified name.
+     *
+     * @param name the name of the referenced object instance
+     * @param reference the reference to set
+     */
+    public abstract void addReference(String name, Reference reference);
+
+    /**
+     * Gets the unresolved references by name.
+     *
+     * @return the unresolved references by name
+     */
+    public abstract Map<String, List<Reference>> getUnresolvedRefs();
+
+    /**
+     * Gets the class loader used for loading of all classes during the
+     * life of this execution context
+     * @return the class loader for loading classes in this context
+     */
+    public abstract ClassLoader getClassLoader();
+}

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExplicitConstruction.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExplicitConstruction.java?rev=617547&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExplicitConstruction.java (added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExplicitConstruction.java Fri Feb  1 08:23:21 2008
@@ -0,0 +1,115 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xbean.recipe;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ExplicitConstruction implements Construction {
+    private Constructor constructor;
+    private Method staticFactory;
+    private String[] parameterNames;
+    protected String factoryMethod;
+
+    public ExplicitConstruction(Constructor constructor, Method staticFactory, String[] parameterNames, String factoryMethod) {
+        this.constructor = constructor;
+        this.factoryMethod = factoryMethod;
+        this.parameterNames = parameterNames;
+        this.staticFactory = staticFactory;
+    }
+
+    public boolean hasInstanceFactory() {
+        return factoryMethod != null;
+    }
+
+    public List<String> getParameterNames() {
+        if (parameterNames == null) {
+            throw new ConstructionException("InstanceFactory has not been initialized");
+        }
+
+        return new ArrayList<String>(Arrays.asList(parameterNames));
+    }
+
+    public List<Class> getParameterTypes() {
+        if (constructor == null && staticFactory == null) {
+            throw new ConstructionException("InstanceFactory has not been initialized");
+        }
+
+        if (staticFactory != null) {
+            return new ArrayList<Class>(Arrays.asList(staticFactory.getParameterTypes()));
+        }
+        return new ArrayList<Class>(Arrays.asList(constructor.getParameterTypes()));
+    }
+
+    public Object create(Object... parameters) throws ConstructionException {
+        if (constructor == null && staticFactory == null) {
+            throw new ConstructionException("InstanceFactory has not been initialized");
+        }
+
+        // create the instance
+        Object instance;
+        try {
+            if (staticFactory != null) {
+                instance = staticFactory.invoke(null, parameters);
+            } else {
+                instance = constructor.newInstance(parameters);
+            }
+        } catch (Exception e) {
+            Throwable t = e;
+            if (e instanceof InvocationTargetException) {
+                InvocationTargetException invocationTargetException = (InvocationTargetException) e;
+                if (invocationTargetException.getCause() != null) {
+                    t = invocationTargetException.getCause();
+                }
+            }
+            if (staticFactory != null) {
+                throw new ConstructionException("Error invoking factory method: " + staticFactory, t);
+            } else {
+                throw new ConstructionException("Error invoking constructor: " + constructor, t);
+            }
+        }
+        return instance;
+    }
+
+    public Object callInstanceFactory(Object instance) throws ConstructionException {
+        // if we have a factory method name and did not find a static factory,
+        // look for a instance factory method
+        if (factoryMethod != null && staticFactory == null) {
+            // find the instance factory method
+            Method instanceFactory = ReflectionUtil.findInstanceFactory(instance.getClass(), factoryMethod, null);
+
+            try {
+                instance = instanceFactory.invoke(instance);
+            } catch (Exception e) {
+                Throwable t = e;
+                if (e instanceof InvocationTargetException) {
+                    InvocationTargetException invocationTargetException = (InvocationTargetException) e;
+                    if (invocationTargetException.getCause() != null) {
+                        t = invocationTargetException.getCause();
+                    }
+                }
+                throw new ConstructionException("Error calling instance factory method: " + instanceFactory, t);
+            }
+        }
+        return instance;
+    }
+}
\ No newline at end of file

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExplicitConstructionStrategy.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExplicitConstructionStrategy.java?rev=617547&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExplicitConstructionStrategy.java (added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ExplicitConstructionStrategy.java Fri Feb  1 08:23:21 2008
@@ -0,0 +1,75 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xbean.recipe;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+public class ExplicitConstructionStrategy implements ConstructionStrategy {
+    public Construction getConstruction(ObjectRecipe recipe, Class expectedType) throws ConstructionException {
+        Class type = recipe.getType();
+
+        //
+        // verify that it is a class we can construct
+        if (!Modifier.isPublic(type.getModifiers())) {
+            throw new ConstructionException("Class is not public: " + type.getName());
+        }
+        if (Modifier.isInterface(type.getModifiers())) {
+            throw new ConstructionException("Class is an interface: " + type.getName());
+        }
+
+        //
+        // attempt to find a static factory
+        String[] parameterNames = recipe.getConstructorArgNames();
+        if (parameterNames == null) parameterNames = new String[0];
+        Class[] parameterTypes = recipe.getConstructorArgTypes();
+        if (parameterTypes == null) parameterTypes = new Class[parameterNames.length];
+        if (parameterNames.length != parameterTypes.length) {
+            throw new ConstructionException("Invalid ObjectRecipe: recipe has " + parameterNames.length +
+                    " parameter names and " + parameterTypes.length + " parameter types");
+        }
+        if (recipe.getFactoryMethod() != null) {
+            try {
+                Method staticFactory = ReflectionUtil.findStaticFactory(type, recipe.getFactoryMethod(), parameterTypes, null);
+                return new ExplicitConstruction(null, staticFactory, parameterNames, null);
+            } catch (MissingFactoryMethodException ignored) {
+            }
+
+        }
+
+        //
+        // factory was not found, look for a constuctor
+
+        // if expectedType is a subclass of the assigned type, we create
+        // the sub class instead
+        Class consturctorClass;
+        if (type.isAssignableFrom(expectedType)) {
+            consturctorClass = expectedType;
+        } else {
+            consturctorClass = type;
+        }
+
+        if (Modifier.isAbstract(consturctorClass.getModifiers())) {
+            throw new ConstructionException("Class is abstract: " + consturctorClass.getName());
+        }
+
+        Constructor constructor = ReflectionUtil.findConstructor(consturctorClass, parameterTypes, null);
+        return new ExplicitConstruction(constructor, null, parameterNames, recipe.getFactoryMethod());
+    }
+}

Modified: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/MapRecipe.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/MapRecipe.java?rev=617547&r1=617546&r2=617547&view=diff
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/MapRecipe.java (original)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/MapRecipe.java Fri Feb  1 08:23:21 2008
@@ -16,155 +16,265 @@
  */
 package org.apache.xbean.recipe;
 
+import java.lang.reflect.Type;
 import java.util.ArrayList;
-import java.util.Iterator;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 /**
  * @version $Rev: 6687 $ $Date: 2005-12-28T21:08:56.733437Z $
  */
 public class MapRecipe extends AbstractRecipe {
     private final List<Object[]> entries;
-    private final String type;
+    private String typeName;
+    private Class typeClass;
+    private final EnumSet<Option> options = EnumSet.noneOf(Option.class);
 
     public MapRecipe() {
-        type = LinkedHashMap.class.getName();
         entries = new ArrayList<Object[]>();
     }
 
     public MapRecipe(String type) {
-        this.type = type;
+        this.typeName = type;
         entries = new ArrayList<Object[]>();
     }
 
     public MapRecipe(Class type) {
-        this.type = type.getName();
+        this.typeClass = type;
         if (!RecipeHelper.hasDefaultConstructor(type)) throw new IllegalArgumentException("Type does not have a default constructor " + type);
         entries = new ArrayList<Object[]>();
     }
 
-    public MapRecipe(Map map) {
+    public MapRecipe(Map<?,?> map) {
         if (map == null) throw new NullPointerException("map is null");
 
         entries = new ArrayList<Object[]>(map.size());
 
         // If the specified set has a default constructor we will recreate the set, otherwise we use a LinkedHashMap or TreeMap
         if (RecipeHelper.hasDefaultConstructor(map.getClass())) {
-            this.type = map.getClass().getName();
+            this.typeClass = map.getClass();
         } else if (map instanceof SortedMap) {
-            this.type = TreeMap.class.getName();
+            this.typeClass = TreeMap.class;
+        } else if (map instanceof ConcurrentMap) {
+            this.typeClass = ConcurrentHashMap.class;
         } else {
-            this.type = LinkedHashMap.class.getName();
+            this.typeClass = LinkedHashMap.class;
         }
         putAll(map);
     }
 
-    public MapRecipe(String type, Map map) {
-        if (map == null) throw new NullPointerException("map is null");
-        this.type = type;
-        entries = new ArrayList<Object[]>(map.size());
-        putAll(map);
+    public MapRecipe(MapRecipe mapRecipe) {
+        if (mapRecipe == null) throw new NullPointerException("mapRecipe is null");
+        this.typeName = mapRecipe.typeName;
+        this.typeClass = mapRecipe.typeClass;
+        entries = new ArrayList<Object[]>(mapRecipe.entries);
     }
 
-    public MapRecipe(Class type, Map map) {
-        if (map == null) throw new NullPointerException("map is null");
-        if (!RecipeHelper.hasDefaultConstructor(type)) throw new IllegalArgumentException("Type does not have a default constructor " + type);
-        this.type = type.getName();
-        entries = new ArrayList<Object[]>(map.size());
-        putAll(map);
+    public void allow(Option option){
+        options.add(option);
     }
 
-    public MapRecipe(MapRecipe mapRecipe) {
-        if (mapRecipe == null) throw new NullPointerException("mapRecipe is null");
-        this.type = mapRecipe.type;
-        entries = new ArrayList<Object[]>(mapRecipe.entries);
+    public void disallow(Option option){
+        options.remove(option);
+    }
+
+    public List<Recipe> getNestedRecipes() {
+        List<Recipe> nestedRecipes = new ArrayList<Recipe>(entries.size() * 2);
+        for (Object[] entry : entries) {
+            Object key = entry[0];
+            if (key instanceof Recipe) {
+                Recipe recipe = (Recipe) key;
+                nestedRecipes.add(recipe);
+            }
+
+            Object value = entry[1];
+            if (value instanceof Recipe) {
+                Recipe recipe = (Recipe) value;
+                nestedRecipes.add(recipe);
+            }
+        }
+        return nestedRecipes;
+    }
+
+    public List<Recipe> getConstructorRecipes() {
+        if (!options.contains(Option.LAZY_ASSIGNMENT)) {
+            return getNestedRecipes();
+        }
+        return Collections.emptyList();
     }
 
-    public boolean canCreate(Class type, ClassLoader classLoader) {
-        Class myType = getType(classLoader);
+    public boolean canCreate(Class type) {
+        Class myType = getType(type);
         return type.isAssignableFrom(myType);
     }
 
-    public Map create(ClassLoader classLoader) {
-        Class mapType = getType(classLoader);
+    protected Object internalCreate(Class expectedType, boolean lazyRefAllowed) throws ConstructionException {
+        Class mapType = getType(expectedType);
 
         if (!RecipeHelper.hasDefaultConstructor(mapType)) {
-            throw new ConstructionException("Type does not have a default constructor " + type);
+            throw new ConstructionException("Type does not have a default constructor " + mapType.getName());
         }
 
         Object o;
         try {
             o = mapType.newInstance();
         } catch (Exception e) {
-            throw new ConstructionException("Error while creating set instance: " + type);
+            throw new ConstructionException("Error while creating set instance: " + mapType.getName());
         }
 
         if(!(o instanceof Map)) {
-            throw new ConstructionException("Specified map type does not implement the Map interface: " + type);
+            throw new ConstructionException("Specified map type does not implement the Map interface: " + mapType.getName());
         }
-
         Map instance = (Map) o;
+
+        // get component type
+        Class<?> keyType = Object.class;
+        Class<?> valueType = Object.class;
+        Type[] typeParameters = RecipeHelper.getTypeParameters(Collection.class, expectedType);
+        if (typeParameters != null && typeParameters.length == 2) {
+            if (typeParameters[0] instanceof Class) {
+                keyType = (Class<?>) typeParameters[0];
+            }
+            if (typeParameters[1] instanceof Class) {
+                valueType = (Class<?>) typeParameters[1];
+            }
+        }
+
+        // add to execution context if name is specified
+        if (getName() != null) {
+            ExecutionContext.getContext().addObject(getName(), instance);
+        }
+
+        // add map entries
+        boolean refAllowed = options.contains(Option.LAZY_ASSIGNMENT);
         for (Object[] entry : entries) {
-            Object key = entry[0];
-            if (key instanceof Recipe) {
-                Recipe recipe = (Recipe) key;
-                try {
-                    key = recipe.create(classLoader);
-                } catch (ConstructionException e) {
-                    e.setPrependAttributeName("[" + type + " " + key + "]");
-                    throw e;
+            Object key = RecipeHelper.convert(keyType, entry[0], refAllowed);
+            Object value = RecipeHelper.convert(valueType, entry[1], refAllowed);
+
+            if (key instanceof Reference) {
+                // when the key reference and optional value reference are both resolved
+                // the key/value pair will be added to the map
+                Reference.Action action = new UpdateMap(instance, key, value);
+                ((Reference) key).setAction(action);
+                if (value instanceof Reference) {
+                    ((Reference) value).setAction(action);
                 }
+            } else if (value instanceof Reference) {
+                // add a null place holder assigned to the key
+                //noinspection unchecked
+                instance.put(key, null);
+                // when value is resolved we will replace the null value with they real value
+                Reference.Action action = new UpdateValue(instance, key);
+                ((Reference) value).setAction(action);
+            } else {
+                //noinspection unchecked
+                instance.put(key, value);
             }
+        }
+        return instance;
+    }
 
-            Object value = entry[1];
-            if (value instanceof Recipe) {
-                Recipe recipe = (Recipe) value;
+    private Class getType(Class expectedType) {
+        if (typeClass != null || typeName != null) {
+            Class type = typeClass;
+            if (type == null) {
                 try {
-                    value = recipe.create(classLoader);
-                } catch (ConstructionException e) {
-                    e.setPrependAttributeName("[" + type + " " + key + "]");
-                    throw e;
+                    type = RecipeHelper.loadClass(typeName);
+                } catch (ClassNotFoundException e) {
+                    throw new ConstructionException("Type class could not be found: " + typeName);
                 }
             }
 
-            //noinspection unchecked
-            instance.put(key, value);
+            // if expectedType is a subclass of the assigned type,
+            // we use it assuming it has a default constructor
+            if (type.isAssignableFrom(expectedType) && RecipeHelper.hasDefaultConstructor(expectedType)) {
+                return expectedType;
+            }
+            return type;
         }
-        return instance;
-    }
 
-    private Class getType(ClassLoader classLoader) {
-        Class mapType = null;
-        try {
-            mapType = Class.forName(type, true, classLoader);
-        } catch (ClassNotFoundException e) {
-            throw new ConstructionException("Type class could not be found: " + type);
+        // no type explicitly set
+        if (RecipeHelper.hasDefaultConstructor(expectedType)) {
+            return expectedType;
+        } else if (expectedType.isAssignableFrom(SortedMap.class)) {
+            return TreeMap.class;
+        } else if (expectedType.isAssignableFrom(ConcurrentMap.class)) {
+            return ConcurrentHashMap.class;
+        } else {
+            return LinkedHashMap.class;
         }
-        return mapType;
     }
 
+
     public void put(Object key, Object value) {
         if (key == null) throw new NullPointerException("key is null");
-        if (!RecipeHelper.isSimpleType(key)) {
-            key = new ValueRecipe(key);
-        }
-        if (!RecipeHelper.isSimpleType(value)) {
-            value = new ValueRecipe(value);
-        }
         entries.add(new Object[] { key, value});
     }
 
-    public void putAll(Map map) {
+    public void putAll(Map<?,?> map) {
         if (map == null) throw new NullPointerException("map is null");
-        for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
-            Map.Entry entry = (Map.Entry) iterator.next();
+        for (Map.Entry<?,?> entry : map.entrySet()) {
             Object key = entry.getKey();
             Object value = entry.getValue();
             put(key, value);
         }
     }
+
+    private static class UpdateValue implements Reference.Action {
+        private final Map map;
+        private final Object key;
+
+        public UpdateValue(Map map, Object key) {
+            this.map = map;
+            this.key = key;
+        }
+
+        @SuppressWarnings({"unchecked"})
+        public void onSet(Reference ref) {
+            map.put(key, ref.get());
+        }
+    }
+
+
+    private static class UpdateMap implements Reference.Action {
+        private final Map map;
+        private final Object key;
+        private final Object value;
+
+        public UpdateMap(Map map, Object key, Object value) {
+            this.map = map;
+            this.key = key;
+            this.value = value;
+        }
+
+        @SuppressWarnings({"unchecked"})
+        public void onSet(Reference ignored) {
+            Object key = this.key;
+            if (key instanceof Reference) {
+                Reference reference = (Reference) key;
+                if (!reference.isResolved()) {
+                    return;
+                }
+                key = reference.get();
+            }
+            Object value = this.value;
+            if (value instanceof Reference) {
+                Reference reference = (Reference) value;
+                if (!reference.isResolved()) {
+                    return;
+                }
+                value = reference.get();
+            }
+            map.put(key, value);
+        }
+    }
+
 }

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/NoSuchObjectException.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/NoSuchObjectException.java?rev=617547&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/NoSuchObjectException.java (added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/NoSuchObjectException.java Fri Feb  1 08:23:21 2008
@@ -0,0 +1,36 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xbean.recipe;
+
+public class NoSuchObjectException extends ConstructionException {
+    private String name;
+
+    public NoSuchObjectException(String name) {
+        super("No object named " + name + " exists");
+        this.name = name;
+    }
+
+    public NoSuchObjectException(Throwable cause, String name) {
+        super("No object named " + name + " exists", cause);
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

Added: geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectGraph.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectGraph.java?rev=617547&view=auto
==============================================================================
--- geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectGraph.java (added)
+++ geronimo/xbean/trunk/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectGraph.java Fri Feb  1 08:23:21 2008
@@ -0,0 +1,277 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xbean.recipe;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Iterator;
+
+public class ObjectGraph {
+    private Repository repository;
+
+    public ObjectGraph() {
+        this(new DefaultRepository());
+    }
+
+    public ObjectGraph(Repository repository) {
+        if (repository == null) throw new NullPointerException("repository is null");
+        this.repository = repository;
+    }
+
+    public Repository getRepository() {
+        return repository;
+    }
+
+    public void setRepository(Repository repository) {
+        if (repository == null) throw new NullPointerException("repository is null");
+        this.repository = repository;
+    }
+
+    public Object create(String name) throws ConstructionException {
+        Map<String, Object> objects = createAll(Collections.singletonList(name));
+        Object instance = objects.get(name);
+        if (instance == null) {
+            instance = repository.get(name);
+        }
+        return instance;
+    }
+
+    public Map<String,Object> createAll(String... names) throws ConstructionException {
+        return createAll(Arrays.asList(names));
+    }
+
+    public Map<String,Object> createAll(List<String> names) throws ConstructionException {
+        // setup execution context
+        boolean createNewContext = !ExecutionContext.isContextSet();
+        if (createNewContext) {
+            ExecutionContext.setContext(new DefaultExecutionContext(repository));
+        }
+        WrapperExecutionContext wrapperContext = new WrapperExecutionContext(ExecutionContext.getContext());
+        ExecutionContext.setContext(wrapperContext);
+
+        try {
+            // find recipes to create
+            LinkedHashMap<String, Recipe> recipes = getSortedRecipes(names);
+
+            // Seed the objects linked hash map with the existing objects
+            LinkedHashMap<String, Object> objects = new LinkedHashMap<String, Object>();
+            List<String> existingObjectNames = new ArrayList<String>(names);
+            existingObjectNames.removeAll(recipes.keySet());
+            for (String name : existingObjectNames) {
+                Object object = repository.get(name);
+                if (object == null) {
+                    throw new NoSuchObjectException(name);
+                }
+                objects.put(name, object);
+            }
+
+            // build each object from the recipe
+            for (Map.Entry<String, Recipe> entry : recipes.entrySet()) {
+                String name = entry.getKey();
+                Recipe recipe = entry.getValue();
+                if (!wrapperContext.containsObject(name) || wrapperContext.getObject(name) instanceof Recipe) {
+                    recipe.create(Object.class, false);
+                }
+            }
+
+            // add the constructed objects to the objects linked hash map
+            // The result map will be in construction order, with existing
+            // objects at the front
+            objects.putAll(wrapperContext.getConstructedObject());
+            return objects;
+        } finally {
+            // if we set a new execution context, remove it from the thread
+            if (createNewContext) {
+                ExecutionContext.setContext(null);
+            }
+        }
+    }
+
+    private LinkedHashMap<String, Recipe> getSortedRecipes(List<String> names) {
+        // construct the graph
+        Map<String, Node> nodes = new LinkedHashMap<String, Node>();
+        for (String name : names) {
+            if (!nodes.containsKey(name)) {
+                Object object = repository.get(name);
+                if (object instanceof Recipe) {
+                    Recipe recipe = (Recipe) object;
+                    createNode(name, recipe,  nodes);
+                }
+            }
+        }
+
+        // find all initial leaf nodes (and islands)
+        List<Node> sortedNodes = new ArrayList<Node>(nodes.size());
+        LinkedList<Node> leafNodes = new LinkedList<Node>();
+        for (Node n : nodes.values()) {
+            if (n.refernceCount == 0) {
+                // if the node is totally isolated (no in or out refs),
+                // move it directly to the finished list, so they are first
+                if (n.references.size() == 0) {
+                    sortedNodes.add(n);
+                } else {
+                    leafNodes.add(n);
+                }
+            }
+        }
+
+        // pluck the leaves until there are no leaves remaining
+        while (!leafNodes.isEmpty()) {
+            Node node = leafNodes.removeFirst();
+            sortedNodes.add(node);
+            for (Node ref : node.references) {
+                ref.refernceCount--;
+                if (ref.refernceCount == 0) {
+                    leafNodes.add(ref);
+                }
+            }
+        }
+
+        // There are no more leaves so if there are there still
+        // unprocessed nodes in the graph, we have one or more curcuits
+        if (sortedNodes.size() != nodes.size()) {
+            findCircuit(nodes.values().iterator().next(), new ArrayList<Recipe>(nodes.size()));
+            // find circuit should never fail, if it does there is a programming error
+            throw new ConstructionException("Internal Error: expected a CircularDependencyException");
+        }
+
+        // return the recipes
+        LinkedHashMap<String, Recipe> sortedRecipes = new LinkedHashMap<String, Recipe>();
+        for (Node node : sortedNodes) {
+            sortedRecipes.put(node.name, node.recipe);
+        }
+        return sortedRecipes;
+    }
+
+    private void findCircuit(Node node, ArrayList<Recipe> stack) {
+        if (stack.contains(node.recipe)) {
+            ArrayList<Recipe> circularity = new ArrayList<Recipe>(stack.subList(stack.indexOf(node.recipe), stack.size()));
+
+            // remove anonymous nodes from circularity list
+            for (Iterator<Recipe> iterator = circularity.iterator(); iterator.hasNext();) {
+                Recipe recipe = iterator.next();
+                if (recipe != node.recipe && recipe.getName() == null) {
+                    iterator.remove();
+                }
+            }
+
+            // add ending node to list so a full circuit is shown
+            circularity.add(node.recipe);
+            
+            throw new CircularDependencyException(circularity);
+        }
+
+        stack.add(node.recipe);
+        for (Node reference : node.references) {
+            findCircuit(reference, stack);
+        }
+    }
+
+    private Node createNode(String name, Recipe recipe, Map<String, Node> nodes) {
+        Node node = new Node();
+        node.name = name;
+        node.recipe = recipe;
+        nodes.put(name, node);
+
+        LinkedList<Recipe> nestedRecipes = new LinkedList<Recipe>(recipe.getNestedRecipes());
+        LinkedList<Recipe> constructorRecipes = new LinkedList<Recipe>(recipe.getConstructorRecipes());
+        while (!nestedRecipes.isEmpty()) {
+            Recipe nestedRecipe = nestedRecipes.removeFirst();
+            String nestedName = nestedRecipe.getName();
+            if (nestedName != null) {
+                Node nestedNode = nodes.get(nestedName);
+                if (nestedNode == null) {
+                    nestedNode = createNode(nestedName, nestedRecipe, nodes);
+                }
+
+                // if this is a constructor recipe, we need to add a reference link
+                if (constructorRecipes.contains(nestedRecipe)) {
+                    node.refernceCount++;
+                    nestedNode.references.add(node);
+                }
+            } else {
+                nestedRecipes.addAll(nestedRecipe.getNestedRecipes());
+            }
+        }
+
+        return node;
+    }
+
+    private class Node {
+        String name;
+        Recipe recipe;
+        final List<Node> references = new ArrayList<Node>();
+        int refernceCount;
+    }
+
+    private static class WrapperExecutionContext extends ExecutionContext {
+        private final ExecutionContext executionContext;
+        private final Map<String, Object> constructedObject = new LinkedHashMap<String, Object>();
+
+        private WrapperExecutionContext(ExecutionContext executionContext) {
+            if (executionContext == null) throw new NullPointerException("executionContext is null");
+            this.executionContext = executionContext;
+        }
+
+        public Map<String, Object> getConstructedObject() {
+            return constructedObject;
+        }
+
+        public void push(Recipe recipe) throws CircularDependencyException {
+            executionContext.push(recipe);
+        }
+
+        public Recipe pop() {
+            return executionContext.pop();
+        }
+
+        public LinkedList<Recipe> getStack() {
+            return executionContext.getStack();
+        }
+
+        public Object getObject(String name) {
+            return executionContext.getObject(name);
+        }
+
+        public boolean containsObject(String name) {
+            return executionContext.containsObject(name);
+        }
+
+        public void addObject(String name, Object object) {
+            executionContext.addObject(name, object);
+            constructedObject.put(name, object);
+        }
+
+        public void addReference(String name, Reference reference) {
+            executionContext.addReference(name, reference);
+        }
+
+        public Map<String, List<Reference>> getUnresolvedRefs() {
+            return executionContext.getUnresolvedRefs();
+        }
+
+        public ClassLoader getClassLoader() {
+            return executionContext.getClassLoader();
+        }
+    }
+}



Mime
View raw message