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.HashMap;
027 import java.util.List;
028 import java.util.Map;
029
030 import javax.naming.Context;
031 import javax.naming.NamingException;
032
033 import org.apache.xbean.recipe.ObjectRecipe;
034 import org.apache.xbean.recipe.Option;
035 import org.apache.xbean.recipe.StaticRecipe;
036
037 /**
038 * @version $Rev: 549455 $ $Date: 2007-06-21 08:12:27 -0400 (Thu, 21 Jun 2007) $
039 */
040 public class Holder implements Serializable {
041
042 public static final Holder EMPTY = new Holder() {
043 };
044
045 private Map<String, List<Injection>> injectionMap;
046 private Map<String, LifecycleMethod> postConstruct;
047 private Map<String, LifecycleMethod> preDestroy;
048
049
050 public Holder() {
051 }
052
053
054 public void addInjection(String className, Injection injection) {
055 if (injectionMap == null) {
056 injectionMap = new HashMap<String, List<Injection>>();
057 }
058 List<Injection> injections = injectionMap.get(className);
059 if (injections == null) {
060 injections = new ArrayList<Injection>();
061 injectionMap.put(className, injections);
062 }
063 injections.add(injection);
064 }
065
066 public void addPostConstructs(Map<String, LifecycleMethod> newPostConstructs) {
067 this.postConstruct = merge(postConstruct, newPostConstructs);
068 }
069
070 public void addPreDestroys(Map<String, LifecycleMethod> newPreDestroys) {
071 this.preDestroy = merge(preDestroy, newPreDestroys);
072 }
073
074 private Map<String, LifecycleMethod> merge(Map<String, LifecycleMethod> old, Map<String, LifecycleMethod> additional) {
075 if (old == null) {
076 return additional;
077 }
078 if (additional == null) {
079 return old;
080 }
081 old.putAll(additional);
082 return old;
083 }
084
085 public List<Injection> getInjections(String className) {
086 if (injectionMap == null) {
087 return null;
088 }
089 return injectionMap.get(className);
090 }
091
092 public Map<String, LifecycleMethod> getPostConstruct() {
093 return postConstruct;
094 }
095
096 public Map<String, LifecycleMethod> getPreDestroy() {
097 return preDestroy;
098 }
099
100 public boolean isEmpty() {
101 return (injectionMap == null || injectionMap.isEmpty())
102 && (postConstruct == null || postConstruct.isEmpty())
103 && (preDestroy == null || preDestroy.isEmpty());
104 }
105
106 public Object newInstance(String className, ClassLoader classLoader, Context context) throws IllegalAccessException, InstantiationException {
107 ObjectRecipe objectRecipe = new ObjectRecipe(className);
108 objectRecipe.allow(Option.FIELD_INJECTION);
109 objectRecipe.allow(Option.PRIVATE_PROPERTIES);
110 Class clazz;
111 try {
112 clazz = classLoader.loadClass(className);
113 } catch (ClassNotFoundException e) {
114 throw (InstantiationException)new InstantiationException("Can't load class " + className + " in classloader: " + classLoader).initCause(e);
115 }
116 List<NamingException> problems = new ArrayList<NamingException>();
117 while (clazz != Object.class) {
118 addInjections(clazz.getName(), context, objectRecipe, problems);
119 clazz = clazz.getSuperclass();
120 }
121 if (!problems.isEmpty()) {
122 throw new InstantiationException("Some objects to be injected were not found in jndi: " + problems);
123 }
124 Object result = objectRecipe.create(classLoader);
125 if (getPostConstruct() != null) {
126 try {
127 apply(result, null, postConstruct);
128 } catch (InvocationTargetException e) {
129 Throwable cause = e.getCause();
130 throw (InstantiationException) new InstantiationException("Could not call postConstruct method").initCause(cause);
131 }
132 }
133 return result;
134 }
135
136 private void addInjections(String className, Context context, ObjectRecipe objectRecipe, List<NamingException> problems) {
137 List<Injection> callbackHandlerinjections = getInjections(className);
138 if (callbackHandlerinjections != null) {
139 for (Injection injection : callbackHandlerinjections) {
140 try {
141 String jndiName = injection.getJndiName();
142 //our componentContext is attached to jndi at "java:comp" so we remove that when looking stuff up in it
143 Object object = context.lookup("env/" + jndiName);
144 if (object instanceof String) {
145 String string = (String) object;
146 // Pass it in raw so it could be potentially converted to
147 // another data type by an xbean-reflect property editor
148 objectRecipe.setProperty(injection.getTargetName(), string);
149 } else {
150 objectRecipe.setProperty(injection.getTargetName(), new StaticRecipe(object));
151 }
152 } catch (NamingException e) {
153 problems.add(e);
154 }
155 }
156 }
157 }
158
159 public void destroyInstance(Object o) throws Exception {
160 Class clazz = o.getClass();
161 Map<String, LifecycleMethod> preDestroy = getPreDestroy();
162 if (preDestroy != null) {
163 apply(o, clazz, preDestroy);
164 }
165 }
166
167 public static void apply(Object o, Class clazz, Map<String, LifecycleMethod> map) throws IllegalAccessException, InvocationTargetException {
168 if (clazz == null) {
169 clazz = o.getClass();
170 }
171 ArrayList<Class> classes = new ArrayList<Class>();
172 while (clazz != null && clazz != Object.class) {
173 classes.add(clazz);
174 clazz = clazz.getSuperclass();
175 }
176 for (int i = classes.size() - 1; i > -1; i--) {
177 Class clazz1 = classes.get(i);
178 LifecycleMethod m = map.get(clazz1.getName());
179 if (m != null) {
180 m.call(o, clazz1);
181 }
182 }
183 }
184
185 }