001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with 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,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020
021 package org.apache.geronimo.j2ee.annotation;
022
023 import java.io.Serializable;
024 import java.lang.reflect.InvocationTargetException;
025 import java.util.ArrayList;
026 import java.util.Collection;
027 import java.util.HashMap;
028 import java.util.HashSet;
029 import java.util.List;
030 import java.util.Map;
031 import java.util.Set;
032
033 import javax.naming.Context;
034 import javax.naming.NamingException;
035
036 import org.apache.xbean.recipe.ObjectRecipe;
037 import org.apache.xbean.recipe.Option;
038 import org.apache.xbean.recipe.StaticRecipe;
039
040 /**
041 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
042 */
043 public class Holder implements Serializable {
044
045 public static final Holder EMPTY = new Holder() {
046 };
047
048 private Map<String, Set<Injection>> injectionMap;
049 private Map<String, LifecycleMethod> postConstruct;
050 private Map<String, LifecycleMethod> preDestroy;
051
052
053 public Holder() {
054 }
055
056 public Holder(Holder source) {
057 if (source.getInjectionMap() != null) {
058 this.injectionMap = new HashMap<String, Set<Injection>>();
059 addInjectionMap(source.getInjectionMap());
060 }
061
062 if (source.getPostConstruct() != null) {
063 this.postConstruct = new HashMap<String, LifecycleMethod>();
064 addPostConstructs(source.getPostConstruct());
065 }
066
067 if (source.getPreDestroy() != null) {
068 this.preDestroy = new HashMap<String, LifecycleMethod>();
069 addPreDestroys(source.getPreDestroy());
070 }
071 }
072
073 private Set<Injection> getInjectionList(String className) {
074 if (injectionMap == null) {
075 injectionMap = new HashMap<String, Set<Injection>>();
076 }
077 Set<Injection> injections = injectionMap.get(className);
078 if (injections == null) {
079 injections = new HashSet<Injection>();
080 injectionMap.put(className, injections);
081 }
082 return injections;
083 }
084
085 public void addInjection(String className, Injection newInjection) {
086 Set<Injection> injections = getInjectionList(className);
087 injections.add(newInjection);
088 }
089
090 public void addInjections(String className, Collection<Injection> newInjections) {
091 Set<Injection> injections = getInjectionList(className);
092 for (Injection injection : newInjections) {
093 injections.add(injection);
094 }
095 }
096
097 public void addPostConstructs(Map<String, LifecycleMethod> newPostConstructs) {
098 this.postConstruct = merge(postConstruct, newPostConstructs);
099 }
100
101 public void addPreDestroys(Map<String, LifecycleMethod> newPreDestroys) {
102 this.preDestroy = merge(preDestroy, newPreDestroys);
103 }
104
105 private Map<String, LifecycleMethod> merge(Map<String, LifecycleMethod> old, Map<String, LifecycleMethod> additional) {
106 if (old == null) {
107 return additional;
108 }
109 if (additional == null) {
110 return old;
111 }
112 old.putAll(additional);
113 return old;
114 }
115
116 public void addInjectionMap(Map<String, Set<Injection>> injectionMap) {
117 if (injectionMap == null) {
118 return;
119 }
120 for (Map.Entry<String, Set<Injection>> entry : injectionMap.entrySet()) {
121 String className = entry.getKey();
122 Set<Injection> injections = entry.getValue();
123 addInjections(className, injections);
124 }
125 }
126
127 public List<Injection> getInjections(String className) {
128 if (injectionMap != null) {
129 Set<Injection> injections = injectionMap.get(className);
130 if (injections != null) {
131 return new ArrayList<Injection>(injections);
132 }
133 }
134 return null;
135 }
136
137 public Map<String, Set<Injection>> getInjectionMap() {
138 return injectionMap;
139 }
140
141 public Map<String, LifecycleMethod> getPostConstruct() {
142 return postConstruct;
143 }
144
145 public Map<String, LifecycleMethod> getPreDestroy() {
146 return preDestroy;
147 }
148
149 public boolean isEmpty() {
150 return (injectionMap == null || injectionMap.isEmpty())
151 && (postConstruct == null || postConstruct.isEmpty())
152 && (preDestroy == null || preDestroy.isEmpty());
153 }
154
155 public Object newInstance(String className, ClassLoader classLoader, Context context) throws IllegalAccessException, InstantiationException {
156 ObjectRecipe objectRecipe = new ObjectRecipe(className);
157 objectRecipe.allow(Option.FIELD_INJECTION);
158 objectRecipe.allow(Option.PRIVATE_PROPERTIES);
159 Class clazz;
160 try {
161 clazz = classLoader.loadClass(className);
162 } catch (ClassNotFoundException e) {
163 throw (InstantiationException)new InstantiationException("Can't load class " + className + " in classloader: " + classLoader).initCause(e);
164 }
165 List<NamingException> problems = new ArrayList<NamingException>();
166 while (clazz != Object.class) {
167 addInjections(clazz.getName(), context, objectRecipe, problems);
168 clazz = clazz.getSuperclass();
169 }
170 if (!problems.isEmpty()) {
171 throw new InstantiationException("Some objects to be injected were not found in jndi: " + problems);
172 }
173 Object result = objectRecipe.create(classLoader);
174 if (getPostConstruct() != null) {
175 try {
176 apply(result, null, postConstruct);
177 } catch (InvocationTargetException e) {
178 Throwable cause = e.getCause();
179 throw (InstantiationException) new InstantiationException("Could not call postConstruct method").initCause(cause);
180 }
181 }
182 return result;
183 }
184
185 private void addInjections(String className, Context context, ObjectRecipe objectRecipe, List<NamingException> problems) {
186 List<Injection> callbackHandlerinjections = getInjections(className);
187 if (callbackHandlerinjections != null) {
188 for (Injection injection : callbackHandlerinjections) {
189 try {
190 String jndiName = injection.getJndiName();
191 //our componentContext is attached to jndi at "java:comp" so we remove that when looking stuff up in it
192 Object object = context.lookup("env/" + jndiName);
193 if (object instanceof String) {
194 String string = (String) object;
195 // Pass it in raw so it could be potentially converted to
196 // another data type by an xbean-reflect property editor
197 objectRecipe.setProperty(injection.getTargetName(), string);
198 } else {
199 objectRecipe.setProperty(injection.getTargetName(), new StaticRecipe(object));
200 }
201 } catch (NamingException e) {
202 problems.add(e);
203 }
204 }
205 }
206 }
207
208 public void destroyInstance(Object o) throws Exception {
209 Class clazz = o.getClass();
210 Map<String, LifecycleMethod> preDestroy = getPreDestroy();
211 if (preDestroy != null) {
212 apply(o, clazz, preDestroy);
213 }
214 }
215
216 public static void apply(Object o, Class clazz, Map<String, LifecycleMethod> map) throws IllegalAccessException, InvocationTargetException {
217 if (clazz == null) {
218 clazz = o.getClass();
219 }
220 ArrayList<Class> classes = new ArrayList<Class>();
221 while (clazz != null && clazz != Object.class) {
222 classes.add(clazz);
223 clazz = clazz.getSuperclass();
224 }
225 for (int i = classes.size() - 1; i > -1; i--) {
226 Class clazz1 = classes.get(i);
227 LifecycleMethod m = map.get(clazz1.getName());
228 if (m != null) {
229 m.call(o, clazz1);
230 }
231 }
232 }
233
234 }