| /* |
| * 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.openejb; |
| |
| import org.apache.openejb.core.ivm.naming.JndiUrlReference; |
| import org.apache.openejb.injection.FallbackPropertyInjector; |
| import org.apache.openejb.loader.SystemInstance; |
| import org.apache.openejb.spi.ContainerSystem; |
| import org.apache.openejb.util.LogCategory; |
| import org.apache.openejb.util.Logger; |
| import org.apache.openejb.util.PassthroughFactory; |
| import org.apache.xbean.naming.reference.SimpleReference; |
| import org.apache.xbean.recipe.ObjectRecipe; |
| import org.apache.xbean.recipe.Option; |
| |
| import javax.naming.Context; |
| import javax.naming.NamingException; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| public class InjectionProcessor<T> { |
| private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, InjectionProcessor.class); |
| private final Class<? extends T> beanClass; |
| private final Collection<Injection> injections; |
| private final Map<String, Object> properties = new LinkedHashMap<String, Object>(); |
| private final List<Method> postConstructMethods; |
| private final List<Method> preDestroyMethods; |
| private final Context context; |
| private T instance; |
| private T suppliedInstance; |
| private final Map<String, Object> bindings = new HashMap<String, Object>(); |
| |
| |
| public InjectionProcessor(final T suppliedInstance, final Collection<Injection> injections, final Context context) { |
| this.beanClass = null; |
| this.suppliedInstance = suppliedInstance; |
| this.injections = injections; |
| this.context = context; |
| postConstructMethods = null; |
| preDestroyMethods = null; |
| } |
| |
| public InjectionProcessor(final Class<? extends T> beanClass, final Collection<Injection> injections, final Context context) { |
| this.beanClass = beanClass; |
| this.injections = injections; |
| this.context = context; |
| postConstructMethods = null; |
| preDestroyMethods = null; |
| } |
| |
| public InjectionProcessor(final Class<? extends T> beanClass, final Collection<Injection> injections, final List<Method> postConstructMethods, final List<Method> preDestroyMethods, final Context context) { |
| this.beanClass = beanClass; |
| this.injections = injections; |
| this.postConstructMethods = postConstructMethods; |
| this.preDestroyMethods = preDestroyMethods; |
| this.context = context; |
| } |
| |
| public InjectionProcessor(final Class<? extends T> beanClass, final Collection<Injection> injections, final List<Method> postConstructMethods, final List<Method> preDestroyMethods, final Context context, final Map<String, Object> bindings) { |
| this(beanClass, injections, postConstructMethods, preDestroyMethods, context); |
| this.bindings.putAll(bindings); |
| } |
| |
| public void setProperty(final String name, final Object value) { |
| properties.put(name, value); |
| } |
| |
| public T createInstance() throws OpenEJBException { |
| if (instance == null) { |
| construct(); |
| } |
| return instance; |
| } |
| |
| public T getInstance() { |
| return instance; |
| } |
| |
| private void construct() throws OpenEJBException { |
| if (instance != null) { |
| throw new IllegalStateException("Instance already constructed"); |
| } |
| |
| Class<? extends T> clazz = beanClass; |
| |
| final ObjectRecipe objectRecipe; |
| if (suppliedInstance != null) { |
| clazz = (Class<? extends T>) suppliedInstance.getClass(); |
| objectRecipe = PassthroughFactory.recipe(suppliedInstance); |
| } else { |
| objectRecipe = new ObjectRecipe(clazz); |
| } |
| |
| objectRecipe.allow(Option.FIELD_INJECTION); |
| objectRecipe.allow(Option.PRIVATE_PROPERTIES); |
| objectRecipe.allow(Option.IGNORE_MISSING_PROPERTIES); |
| objectRecipe.allow(Option.NAMED_PARAMETERS); |
| |
| fillInjectionProperties(objectRecipe); |
| |
| bindings.clear(); |
| |
| for (final Entry<String, Object> entry : properties.entrySet()) { |
| objectRecipe.setProperty(entry.getKey(), entry.getValue()); |
| } |
| |
| final Object object; |
| try { |
| object = objectRecipe.create(clazz.getClassLoader()); |
| } catch (final Exception e) { |
| throw new OpenEJBException("Error while creating bean " + clazz.getName(), e); |
| } |
| |
| final Map unsetProperties = objectRecipe.getUnsetProperties(); |
| if (unsetProperties.size() > 0) { |
| for (final Object property : unsetProperties.keySet()) { |
| logger.warning("Injection: No such property '" + property + "' in class " + clazz.getName()); |
| } |
| } |
| instance = clazz.cast(object); |
| } |
| |
| public void postConstruct() throws OpenEJBException { |
| if (instance == null) { |
| throw new IllegalStateException("Instance has not been constructed"); |
| } |
| if (postConstructMethods == null) { |
| return; |
| } |
| for (final Method postConstruct : postConstructMethods) { |
| try { |
| postConstruct.invoke(instance); |
| } catch (Exception e) { |
| if (e instanceof InvocationTargetException && e.getCause() instanceof Exception) { |
| e = (Exception) e.getCause(); |
| } |
| throw new OpenEJBException("Error while calling post construct method", e); |
| } |
| } |
| } |
| |
| public void preDestroy() { |
| if (instance == null) { |
| return; |
| } |
| if (preDestroyMethods == null) { |
| return; |
| } |
| for (final Method preDestroy : preDestroyMethods) { |
| try { |
| preDestroy.invoke(instance); |
| } catch (Exception e) { |
| if (e instanceof InvocationTargetException && e.getCause() instanceof Exception) { |
| e = (Exception) e.getCause(); |
| } |
| logger.error("Error while calling pre destroy method", e); |
| } |
| } |
| } |
| |
| private void fillInjectionProperties(final ObjectRecipe objectRecipe) { |
| if (injections == null) { |
| return; |
| } |
| |
| boolean usePrefix = true; |
| try { |
| if (beanClass != null) { |
| beanClass.getConstructor(); |
| } |
| } catch (final NoSuchMethodException e) { |
| // Using constructor injection |
| // xbean can't handle the prefix yet |
| usePrefix = false; |
| } |
| |
| Class clazz = beanClass; |
| |
| if (suppliedInstance != null) { |
| clazz = suppliedInstance.getClass(); |
| } |
| |
| if (context != null) { |
| for (final Injection injection : injections) { |
| if (injection.getTarget() == null) { |
| continue; |
| } |
| if (!injection.getTarget().isAssignableFrom(clazz)) { |
| continue; |
| } |
| |
| final String jndiName = injection.getJndiName(); |
| Object value; |
| try { |
| value = context.lookup(jndiName); |
| } catch (final NamingException ne) { // some fallback |
| value = bindings.get(jndiName); |
| if (value instanceof SimpleReference) { |
| try { |
| value = ((SimpleReference) value).getContent(); |
| } catch (final NamingException e) { |
| if (value instanceof JndiUrlReference) { |
| try { |
| value = SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext() |
| .lookup(((JndiUrlReference) value).getJndiName()); |
| } catch (final NamingException e1) { |
| value = null; |
| } |
| } |
| } |
| } |
| } |
| |
| if (value == null) { // used for testing/mocking |
| final FallbackPropertyInjector fallback = SystemInstance.get().getComponent(FallbackPropertyInjector.class); |
| if (fallback != null) { |
| value = fallback.getValue(injection); |
| } |
| } |
| |
| if (value != null) { |
| final String prefix; |
| if (usePrefix) { |
| prefix = injection.getTarget().getName() + "/"; |
| } else { |
| prefix = ""; |
| } |
| |
| objectRecipe.setProperty(prefix + injection.getName(), value); |
| } else { |
| logger.warning("Injection data not found in JNDI context: jndiName='" + injection.getJndiName() + "', target=" + injection.getTarget().getName() + "/" + injection.getName()); |
| } |
| } |
| } |
| } |
| |
| public static Context unwrap(final Context context) { |
| // if (context == null) return null; |
| // try { |
| // context = (Context) context.lookup("comp/env/"); |
| // } catch (NamingException notAnIssue) { |
| // //TODO figure out which clause should work and remove the other one. |
| // try { |
| // context = (Context) context.lookup("java:comp/env/"); |
| // } catch (NamingException notAnIssue2) { |
| // } |
| // } |
| // |
| return context; |
| } |
| |
| } |