/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.util;
import java.util.List;
import java.util.LinkedList;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.*;
import com.sun.enterprise.InvocationManager;
import com.sun.enterprise.Switch;
import com.sun.enterprise.InjectionManager;
import com.sun.enterprise.InjectionException;
import com.sun.enterprise.ComponentInvocation;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.sun.enterprise.deployment.JndiNameEnvironment;
import com.sun.enterprise.deployment.InjectionCapable;
import com.sun.enterprise.deployment.InjectionInfo;
import com.sun.enterprise.deployment.InjectionTarget;
import com.sun.logging.*;
/**
* Implementation of InjectionManager.
*
* @author Kenneth Saks
*/
public class InjectionManagerImpl implements InjectionManager {
static Logger _logger=LogDomains.getLogger(LogDomains.UTIL_LOGGER);
static private LocalStringManagerImpl localStrings =
new LocalStringManagerImpl(InjectionManagerImpl.class);
private Switch theSwitch;
private InvocationManager invocationMgr;
private InitialContext namingCtx;
public InjectionManagerImpl() {
theSwitch = Switch.getSwitch();
invocationMgr = theSwitch.getInvocationManager();
try {
namingCtx = new InitialContext();
} catch(NamingException ne) {
throw new RuntimeException(ne);
}
}
public void injectInstance(Object instance)
throws InjectionException {
ComponentInvocation inv = invocationMgr.getCurrentInvocation();
if( inv != null ) {
JndiNameEnvironment componentEnv = (JndiNameEnvironment)
theSwitch.getDescriptorFor(inv.getContainerContext());
if( componentEnv != null ) {
inject(instance.getClass(), instance, componentEnv, true);
} else {
throw new InjectionException("No descriptor registered for " +
" current invocation : " + inv);
}
} else {
throw new InjectionException("null invocation context");
}
}
public void injectInstance(Object instance,
JndiNameEnvironment componentEnv)
throws InjectionException
{
inject(instance.getClass(), instance, componentEnv, true);
}
public void injectInstance(Object instance,
JndiNameEnvironment componentEnv,
boolean invokePostConstruct)
throws InjectionException
{
inject(instance.getClass(), instance, componentEnv,
invokePostConstruct);
}
public void injectClass(Class clazz,
JndiNameEnvironment componentEnv)
throws InjectionException
{
injectClass(clazz, componentEnv, true);
}
public void injectClass(Class clazz,
JndiNameEnvironment componentEnv,
boolean invokePostConstruct)
throws InjectionException
{
inject(clazz, null, componentEnv, invokePostConstruct);
}
public void invokeInstancePreDestroy(Object instance,
JndiNameEnvironment componentEnv)
throws InjectionException
{
invokePreDestroy(instance.getClass(), instance, componentEnv);
}
public void invokeInstancePreDestroy(Object instance)
throws InjectionException {
ComponentInvocation inv = invocationMgr.getCurrentInvocation();
if( inv != null ) {
JndiNameEnvironment componentEnv = (JndiNameEnvironment)
theSwitch.getDescriptorFor(inv.getContainerContext());
if( componentEnv != null ) {
invokePreDestroy(instance.getClass(), instance, componentEnv);
} else {
throw new InjectionException("No descriptor registered for " +
" current invocation : " + inv);
}
} else {
throw new InjectionException("null invocation context");
}
}
public void invokeClassPreDestroy(Class clazz,
JndiNameEnvironment componentEnv)
throws InjectionException
{
invokePreDestroy(clazz, null, componentEnv);
}
/**
* @param instance Target instance for injection, or null if injection
* is class-based. Any error encountered during any
* portion of injection is propagated immediately.
*/
private void inject(final Class clazz, final Object instance,
JndiNameEnvironment envDescriptor,
boolean invokePostConstruct)
throws InjectionException
{
LinkedList<Method> postConstructMethods = new LinkedList<Method>();
Class nextClass = clazz;
// Process each class in the inheritance hierarchy, starting with
// the most derived class and ignoring java.lang.Object.
while((nextClass != Object.class) && (nextClass != null)) {
InjectionInfo injInfo =
envDescriptor.getInjectionInfoByClass(nextClass.getName());
if( injInfo.getInjectionResources().size() > 0 ) {
_inject(nextClass, instance, injInfo.getInjectionResources());
}
if( invokePostConstruct ) {
if( injInfo.getPostConstructMethodName() != null ) {
Method postConstructMethod = getPostConstructMethod
(injInfo, nextClass);
// Delay calling post construct methods until all
// dependency injection within the hierarchy has been
// completed. Then, invoke the methods starting from
// the least-derived class downward.
postConstructMethods.addFirst(postConstructMethod);
}
}
nextClass = nextClass.getSuperclass();
}
for(Method postConstructMethod : postConstructMethods) {
invokeLifecycleMethod(postConstructMethod, instance);
}
}
/**
* @param instance Target instance for preDestroy, or null if
* class-based.
*/
private void invokePreDestroy(final Class clazz, final Object instance,
JndiNameEnvironment envDescriptor)
throws InjectionException
{
LinkedList<Method> preDestroyMethods = new LinkedList<Method>();
Class nextClass = clazz;
// Process each class in the inheritance hierarchy, starting with
// the most derived class and ignoring java.lang.Object.
while((nextClass != Object.class) && (nextClass != null)) {
InjectionInfo injInfo =
envDescriptor.getInjectionInfoByClass(nextClass.getName());
if( injInfo.getPreDestroyMethodName() != null ) {
Method preDestroyMethod = getPreDestroyMethod
(injInfo, nextClass);
// Invoke the preDestroy methods starting from
// the least-derived class downward.
preDestroyMethods.addFirst(preDestroyMethod);
}
nextClass = nextClass.getSuperclass();
}
for(Method preDestroyMethod : preDestroyMethods) {
invokeLifecycleMethod(preDestroyMethod, instance);
}
}
private void _inject(final Class clazz, final Object instance,
List<InjectionCapable> injectableResources)
throws InjectionException
{
for (InjectionCapable next : injectableResources ) {
try {
final Object value = namingCtx.lookup("java:comp/env/" +
next.getComponentEnvName());
// there still could be 2 injection on the same class, better
// do a loop here
for (InjectionTarget target : next.getInjectionTargets()) {
// if target class is not the class we are injecting
// we can just jump to the next target
if (!clazz.getName().equals(target.getClassName()))
continue;
if( target.isFieldInjectable() ) {
final Field f = getField(target, clazz);
if( Modifier.isStatic(f.getModifiers()) &&
(instance != null) ) {
throw new InjectionException
("Illegal use of static field " + f +
" on class that only supports instance-based"
+ " injection");
}
if( (instance == null) &&
!Modifier.isStatic(f.getModifiers()) ) {
throw new InjectionException
("Injected field " + f +
" on Application Client class " + clazz +
" must be declared static");
}
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("Injecting dependency with logical name "
+ next.getComponentEnvName() +
" into field " + f + " on class " +
clazz);
}
// Wrap actual value insertion in doPrivileged to
// allow for private/protected field access.
if( System.getSecurityManager() != null ) {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction() {
public java.lang.Object run() throws Exception {
f.set(instance, value);
return null;
}
});
} else {
f.set(instance, value);
}
} else if( target.isMethodInjectable() ) {
final Method m = getMethod(next, target, clazz);
if( Modifier.isStatic(m.getModifiers()) &&
(instance != null) ) {
throw new InjectionException
("Illegal use of static method " + m +
" on class that only supports instance-based"
+ " injection");
}
if( (instance == null) &&
!Modifier.isStatic(m.getModifiers()) ) {
throw new InjectionException
("Injected method " + m +
" on Application Client class " + clazz +
" must be declared static");
}
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("Injecting dependency with logical name "
+ next.getComponentEnvName() +
" into method " + m + " on class " +
clazz);
}
if( System.getSecurityManager() != null ) {
// Wrap actual value insertion in doPrivileged to
// allow for private/protected field access.
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction() {
public java.lang.Object run() throws Exception {
m.invoke(instance, new Object[] { value });
return null;
}});
} else {
m.invoke(instance, new Object[] { value });
}
}
}
} catch(Throwable t) {
String msg = "Exception attempting to inject "
+ next + " into " + clazz;
_logger.log(Level.FINE, msg, t);
InjectionException ie = new InjectionException(msg);
Throwable cause = (t instanceof InvocationTargetException) ?
((InvocationTargetException)t).getCause() : t;
ie.initCause( cause );
throw ie;
}
}
}
private void invokeLifecycleMethod(final Method lifecycleMethod,
final Object instance)
throws InjectionException {
try {
if(_logger.isLoggable(Level.FINE)) {
_logger.fine("Calling lifeccle method " +
lifecycleMethod + " on class " +
lifecycleMethod.getDeclaringClass());
}
// Wrap actual value insertion in doPrivileged to
// allow for private/protected field access.
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction() {
public java.lang.Object run() throws Exception {
if( !lifecycleMethod.isAccessible() ) {
lifecycleMethod.setAccessible(true);
}
lifecycleMethod.invoke(instance);
return null;
}
});
} catch( Throwable t) {
String msg = "Exception attempting invoke lifecycle "
+ " method " + lifecycleMethod;
_logger.log(Level.FINE, msg, t);
InjectionException ie = new InjectionException(msg);
Throwable cause = (t instanceof InvocationTargetException) ?
((InvocationTargetException)t).getCause() : t;
ie.initCause( cause );
throw ie;
}
return;
}
private Field getField(InjectionTarget target,
Class resourceClass) throws Exception {
Field f = target.getField();
if( f == null ) {
try {
// Check for the given field within the resourceClass only.
// This does not include super-classes of this class.
f = resourceClass.getDeclaredField
(target.getFieldName());
final Field finalF = f;
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction() {
public java.lang.Object run() throws Exception {
if( !finalF.isAccessible() ) {
finalF.setAccessible(true);
}
return null;
}
});
} catch(java.lang.NoSuchFieldException nsfe) {}
if( f != null ) {
target.setField(f);
}
}
if( f == null ) {
throw new Exception("InjectionManager exception. Field " +
target.getFieldName() +
" not found in Class " + resourceClass);
}
return f;
}
private Method getMethod(InjectionCapable resource, InjectionTarget target,
Class resourceClass) throws Exception {
Method m = target.getMethod();
if( m == null ) {
// Check for the method within the resourceClass only.
// This does not include super-classses.
for(Method next : resourceClass.getDeclaredMethods()) {
// Overloading is not supported for setter injection
// methods, so matching on method-name is sufficient.
if(next.getName().equals(target.getMethodName())) {
m = next;
target.setMethod(m);
final Method finalM = m;
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction() {
public java.lang.Object run() throws Exception {
if( !finalM.isAccessible() ) {
finalM.setAccessible(true);
}
return null;
}});
break;
}
}
}
if( m == null ) {
throw new Exception("InjectionManager exception. Method " +
"void " + target.getMethodName() +
"(" + resource.getInjectResourceType() + ")" +
" not found in Class " + resourceClass);
}
return m;
}
private Method getPostConstructMethod(InjectionInfo injInfo,
Class resourceClass)
throws InjectionException {
Method m = injInfo.getPostConstructMethod();
if( m == null ) {
String postConstructMethodName =
injInfo.getPostConstructMethodName();
// Check for the method within the resourceClass only.
// This does not include super-classses.
for(Method next : resourceClass.getDeclaredMethods()) {
// InjectionManager only handles injection into PostConstruct
// methods with no arguments.
if( next.getName().equals(postConstructMethodName) &&
(next.getParameterTypes().length == 0) ) {
m = next;
injInfo.setPostConstructMethod(m);
break;
}
}
}
if( m == null ) {
throw new InjectionException
("InjectionManager exception. PostConstruct method " +
injInfo.getPostConstructMethodName() +
" could not be found in class " +
injInfo.getClassName());
}
return m;
}
private Method getPreDestroyMethod(InjectionInfo injInfo,
Class resourceClass)
throws InjectionException {
Method m = injInfo.getPreDestroyMethod();
if( m == null ) {
String preDestroyMethodName = injInfo.getPreDestroyMethodName();
// Check for the method within the resourceClass only.
// This does not include super-classses.
for(Method next : resourceClass.getDeclaredMethods()) {
// InjectionManager only handles injection into PreDestroy
// methods with no arguments.
if( next.getName().equals(preDestroyMethodName) &&
(next.getParameterTypes().length == 0) ) {
m = next;
injInfo.setPreDestroyMethod(m);
break;
}
}
}
if( m == null ) {
throw new InjectionException
("InjectionManager exception. PreDestroy method " +
injInfo.getPreDestroyMethodName() +
" could not be found in class " +
injInfo.getClassName());
}
return m;
}
}
|