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 }