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.Collections;
021 import java.util.List;
022 import java.lang.reflect.Type;
023
024 public class ReferenceRecipe extends AbstractRecipe {
025 private String referenceName;
026
027 public ReferenceRecipe() {
028 }
029
030 public ReferenceRecipe(String referenceName) {
031 this.referenceName = referenceName;
032 }
033
034 public String getReferenceName() {
035 return referenceName;
036 }
037
038 public void setReferenceName(String name) {
039 this.referenceName = name;
040 }
041
042 public List<Recipe> getNestedRecipes() {
043 ExecutionContext context = ExecutionContext.getContext();
044 if (!context.containsObject(referenceName)) {
045 throw new NoSuchObjectException(referenceName);
046 }
047
048 Object object = ExecutionContext.getContext().getObject(referenceName);
049 if (object instanceof Recipe) {
050 Recipe recipe = (Recipe) object;
051 return Collections.singletonList(recipe);
052 }
053 return Collections.emptyList();
054 }
055
056 public List<Recipe> getConstructorRecipes() {
057 return getNestedRecipes();
058 }
059
060 public boolean canCreate(Type type) {
061 if (referenceName == null) {
062 throw new ConstructionException("Reference name has not been set");
063 }
064
065 ExecutionContext context = ExecutionContext.getContext();
066
067 Object object = context.getObject(referenceName);
068 if (object instanceof Recipe) {
069 Recipe recipe = (Recipe) object;
070 return recipe.canCreate(type);
071 } else {
072 return RecipeHelper.isInstance(type, object);
073 }
074 }
075
076 protected Object internalCreate(Type expectedType, boolean lazyRefAllowed) throws ConstructionException {
077 if (referenceName == null) {
078 throw new ConstructionException("Reference name has not been set");
079 }
080
081 ExecutionContext context = ExecutionContext.getContext();
082
083 Object object;
084 if (!context.containsObject(referenceName)) {
085 if (!lazyRefAllowed) {
086 throw new ConstructionException("Currently no object registered with name " + referenceName +
087 " and a lazy reference not allowed");
088 }
089
090 Reference reference = new Reference(referenceName);
091 context.addReference(reference);
092 object = reference;
093 } else {
094 object = context.getObject(referenceName);
095 if (object instanceof Recipe) {
096 if (lazyRefAllowed) {
097 Reference reference = new Reference(referenceName);
098 context.addReference(reference);
099 object = reference;
100 } else {
101 Recipe recipe = (Recipe) object;
102 object = recipe.create(expectedType, false);
103 }
104
105 }
106 }
107
108 // add to execution context if name is specified
109 if (getName() != null) {
110 if (object instanceof Reference) {
111 object = new WrapperReference(getName(), (Reference) object);
112 } else {
113 ExecutionContext.getContext().addObject(getName(), object);
114 }
115 }
116
117 return object;
118 }
119
120 private static class WrapperReference extends Reference {
121 private final Reference delegate;
122
123 private WrapperReference(String name, Reference delegate) {
124 super(name);
125 this.delegate = delegate;
126 }
127
128 public boolean isResolved() {
129 return delegate.isResolved();
130 }
131
132 public Object get() {
133 return delegate.get();
134 }
135
136 public void set(Object object) {
137 if (isResolved()) {
138 throw new ConstructionException("Reference has already been resolved");
139 }
140
141 // add to execution context
142 ExecutionContext.getContext().addObject(getName(), object);
143
144 delegate.set(object);
145 }
146
147 public void setAction(Action action) {
148 delegate.setAction(action);
149 }
150 }
151 }