blob: 49be3c21e53d0c1c0b8f9986206759fa96b8366a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.e4.core.services.internal.context;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.e4.core.services.context.ContextChangeEvent;
import org.eclipse.e4.core.services.context.IEclipseContext;
import org.eclipse.e4.core.services.context.IRunAndTrack;
import org.eclipse.e4.core.services.context.spi.ContextInjectionFactory;
import org.eclipse.e4.core.services.context.spi.IContextConstants;
/**
* Implements injection of context values into an object. Tracks context changes and makes the
* corresponding updates to injected objects. See class comment of {@link ContextInjectionFactory}
* for details on the injection algorithm.
*/
public class ContextToObjectLink implements IRunAndTrack, IContextConstants {
private static final Object[] EMPTY_ARR = new Object[0];
static class ProcessMethodsResult {
List postConstructMethods = new ArrayList();
Set seenMethods = new HashSet();
boolean seen(Method method) {
// uniquely identify methods by name+parameter types
StringBuffer sig = new StringBuffer();
sig.append(method.getName());
Class[] parms = method.getParameterTypes();
for (int i = 0; i < parms.length; i++) {
sig.append(parms[i]);
sig.append(',');
}
return !seenMethods.add(sig.toString());
}
}
abstract private class Processor {
protected boolean isSetter;
protected boolean shouldProcessPostConstruct = false;
protected Object userObject;
public Processor(boolean isSetter) {
this.isSetter = isSetter;
}
void processField(Field field, String injectName, boolean optional) {
// do nothing by default
}
void processMethod(Method method, boolean optional) {
// do nothing by default
}
void processPostConstructMethod(Method m) {
// do nothing by default
}
public void setObject(Object userObject) {
this.userObject = userObject;
}
}
private static final String IN = ".In";//$NON-NLS-1$
private static final String INJECT = ".Inject";//$NON-NLS-1$
final static private String JAVA_OBJECT = "java.lang.Object"; //$NON-NLS-1$
private static final String NAMED = ".Named";//$NON-NLS-1$
private static final String POST_CONSTRUCT = ".PostConstruct";//$NON-NLS-1$
private static final String PRE_DESTROY = ".PreDestroy";//$NON-NLS-1$
// annotation names
private static final String RESOURCE = ".Resource"; //$NON-NLS-1$
protected IEclipseContext context;
final protected String fieldPrefix;
final protected int fieldPrefixLength;
final protected String setMethodPrefix;
protected List userObjects = new ArrayList(3); // start small
public ContextToObjectLink(IEclipseContext context, String fieldPrefix, String setMethodPrefix) {
this.context = context;
this.fieldPrefix = (fieldPrefix != null) ? fieldPrefix : INJECTION_FIELD_PREFIX;
this.setMethodPrefix = (setMethodPrefix != null) ? setMethodPrefix
: INJECTION_SET_METHOD_PREFIX;
fieldPrefixLength = this.fieldPrefix.length();
}
/**
* Calculates alternative spelling of the key: "log" <-> "Log", if any. Returns null if there is
* no alternate.
*/
protected String altKey(String key) {
if (key.length() == 0)
return null;
char firstChar = key.charAt(0);
String candidate = null;
if (Character.isUpperCase(firstChar)) {
firstChar = Character.toLowerCase(firstChar);
if (key.length() == 1)
candidate = Character.toString(firstChar);
else
candidate = Character.toString(firstChar) + key.substring(1);
} else if (Character.isLowerCase(firstChar)) {
firstChar = Character.toUpperCase(firstChar);
if (key.length() == 1)
candidate = Character.toString(firstChar);
else
candidate = Character.toString(firstChar) + key.substring(1);
}
return candidate;
}
void callMethod(Object object, Method m, Object[] args) {
try {
if (!m.isAccessible()) {
m.setAccessible(true);
try {
m.invoke(object, args);
} finally {
m.setAccessible(false);
}
} else {
m.invoke(object, args);
}
} catch (Exception e) {
logWarning(object, e);
}
}
private void findAndCallDispose(Object object, Class objectsClass, ProcessMethodsResult result) {
// 1. Try a method with dispose annotation
Method[] methods = objectsClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (method.getParameterTypes().length > 0)
continue;
try {
Object[] annotations = (Object[]) method.getClass().getMethod("getAnnotations", //$NON-NLS-1$
new Class[0]).invoke(method, EMPTY_ARR);
for (int j = 0; j < annotations.length; j++) {
Object annotation = annotations[j];
try {
String annotationName = ((Class) annotation.getClass().getMethod(
"annotationType", new Class[0]).invoke(annotation, EMPTY_ARR)) //$NON-NLS-1$
.getName();
if (annotationName.endsWith(PRE_DESTROY)) {
if (!result.seen(method))
callMethod(object, method, null);
}
} catch (Exception ex) {
logWarning(method, ex);
}
}
} catch (Exception e) {
// ignore - no annotation support
}
}
// 2. Try IEclipseContextAware#contextDisposed(IEclipseContext)
try {
Method dispose = objectsClass.getDeclaredMethod(
IContextConstants.INJECTION_DISPOSE_CONTEXT_METHOD,
new Class[] { IEclipseContext.class });
// only call this method if we haven't found any other dispose methods yet
if (result.seenMethods.isEmpty() && !result.seen(dispose))
callMethod(object, dispose, new Object[] { context });
} catch (SecurityException e) {
// ignore
} catch (NoSuchMethodException e) {
// ignore
}
// 3. Try contextDisposed()
try {
Method dispose = objectsClass.getDeclaredMethod(
IContextConstants.INJECTION_DISPOSE_CONTEXT_METHOD, new Class[0]);
// only call this method if we haven't found any other dispose methods yet
if (result.seenMethods.isEmpty() && !result.seen(dispose))
callMethod(object, dispose, null);
return;
} catch (SecurityException e) {
// ignore
} catch (NoSuchMethodException e) {
// ignore
}
// 4. Try dispose()
try {
Method dispose = objectsClass.getDeclaredMethod("dispose", null); //$NON-NLS-1$
// only call this method if we haven't found any other dispose methods yet
if (result.seenMethods.isEmpty() && !result.seen(dispose))
callMethod(object, dispose, null);
return;
} catch (SecurityException e) {
// ignore
} catch (NoSuchMethodException e) {
// ignore
}
// 5. Recurse on superclass
Class superClass = objectsClass.getSuperclass();
if (!superClass.getName().equals(JAVA_OBJECT)) {
findAndCallDispose(object, superClass, result);
}
}
protected String findKey(String key, Class clazz) {
if (context.containsKey(key)) // priority goes to exact match
return key;
// alternate capitalization of the first char if possible
String candidate = altKey(key);
if (candidate != null) {
if (context.containsKey(candidate)) {
return candidate;
}
}
// try type name
if (context.containsKey(clazz.getName())) {
return clazz.getName();
}
return null;
}
private void handleAdd(final ContextChangeEvent event) {
final String name = event.getName();
if (IContextConstants.PARENT.equals(name)) {
handleParentChange(event);
return;
}
Processor processor = new Processor(true) {
void processField(final Field field, String injectName, boolean optional) {
String injectKey = findKey(name, field.getType());
if (injectKey != null
&& (keyMatches(name, injectName) || field.getType().getName().equals(name)))
setField(userObject, field, event.getContext().get(injectKey));
}
void processMethod(final Method method, boolean optional) {
String candidateName = method.getName();
if (candidateName.length() <= setMethodPrefix.length())
return;
candidateName = candidateName.substring(setMethodPrefix.length());
Class[] parameterTypes = method.getParameterTypes();
// only inject methods with a single parameter
if (parameterTypes.length != 1)
return;
// on add event, only inject the method corresponding to the added context key
if (keyMatches(name, candidateName)) {
String key = findKey(name, parameterTypes[0]);
setMethod(userObject, method, event.getContext().get(key, parameterTypes));
}
}
};
Object[] objectsCopy = safeObjectsCopy();
for (int i = 0; i < objectsCopy.length; i++) {
processClassHierarchy(objectsCopy[i], processor);
}
}
private void handleParentChange(final ContextChangeEvent event) {
final EclipseContext eventContext = (EclipseContext) event.getContext();
final EclipseContext oldParent = (EclipseContext) event.getOldValue();
final EclipseContext newParent = (EclipseContext) eventContext
.get(IContextConstants.PARENT);
if (oldParent == newParent)
return;
Processor processor = new Processor(true) {
/**
* Returns whether the value associated with the given key is affected by the parent
* change.
*/
private boolean hasChanged(String key) {
// if value is local then parent change has no effect
if (eventContext.getLocal(key) != null)
return false;
Object oldValue = oldParent == null ? null : oldParent.internalGet(eventContext,
key, null, false);
Object newValue = newParent == null ? null : newParent.internalGet(eventContext,
key, null, false);
return oldValue != newValue;
}
void processField(final Field field, String injectName, boolean optional) {
String key = findKey(injectName, field.getType());
if (key != null) {
if (hasChanged(key))
setField(event.getArguments()[0], field, event.getContext().get(key));
} else {
if (!optional) {
throw new IllegalStateException("Could not set " + field //$NON-NLS-1$
+ " because of missing: " + injectName); //$NON-NLS-1$
}
}
}
void processMethod(final Method method, boolean optional) {
String candidateName = method.getName();
if (candidateName.length() <= setMethodPrefix.length())
return;
candidateName = candidateName.substring(setMethodPrefix.length());
Class[] parameterTypes = method.getParameterTypes();
// only inject methods with a single parameter
if (parameterTypes.length != 1)
return;
// when initializing, inject every method that has a match in the context
String key = findKey(candidateName, parameterTypes[0]);
if (key != null) {
if (hasChanged(key))
setMethod(userObject, method, event.getContext().get(key, parameterTypes));
} else {
if (!optional) {
throw new IllegalStateException("Could not invoke " + method //$NON-NLS-1$
+ " because of missing: " + candidateName); //$NON-NLS-1$
}
}
}
};
Object[] objectsCopy = safeObjectsCopy();
for (int i = 0; i < objectsCopy.length; i++) {
processClassHierarchy(objectsCopy[i], processor);
}
}
private void handleRelease(ContextChangeEvent event) {
Object releasedObject = event.getArguments()[0];
synchronized (userObjects) {
boolean found = false;
for (Iterator i = userObjects.iterator(); i.hasNext();) {
WeakReference ref = (WeakReference) i.next();
Object userObject = ref.get();
if (userObject == null)
continue;
if (userObject.equals(releasedObject)) {
i.remove();
found = true;
break;
}
}
if (!found)
return;
}
processClassHierarchy(releasedObject, getRemovalProcessor());
}
private void handleDispose(ContextChangeEvent event) {
Processor processor = getRemovalProcessor();
Object[] objectsCopy = safeObjectsCopy();
for (int i = 0; i < objectsCopy.length; i++) {
processClassHierarchy(objectsCopy[i], processor);
findAndCallDispose(objectsCopy[i], objectsCopy[i].getClass(),
new ProcessMethodsResult());
}
}
private void handleInitial(final ContextChangeEvent event) {
if (event.getArguments() == null || event.getArguments().length == 0
|| event.getArguments()[0] == null)
throw new IllegalArgumentException();
Processor processor = new Processor(true) {
void processField(final Field field, String injectName, boolean optional) {
String key = findKey(injectName, field.getType());
if (key != null) {
setField(event.getArguments()[0], field, event.getContext().get(key));
} else {
if (!optional) {
throw new IllegalStateException("Could not set " + field //$NON-NLS-1$
+ " because of missing: " + injectName); //$NON-NLS-1$
}
}
}
void processMethod(final Method method, boolean optional) {
String candidateName = method.getName();
if (candidateName.length() <= setMethodPrefix.length())
return;
candidateName = candidateName.substring(setMethodPrefix.length());
Class[] parameterTypes = method.getParameterTypes();
// only inject methods with a single parameter
if (parameterTypes.length != 1)
return;
// when initializing, inject every method that has a match in the context
String key = findKey(candidateName, parameterTypes[0]);
if (key != null) {
setMethod(userObject, method, event.getContext().get(key, parameterTypes));
} else {
if (!optional) {
throw new IllegalStateException("Could not invoke " + method //$NON-NLS-1$
+ " because of missing: " + candidateName); //$NON-NLS-1$
}
}
}
void processPostConstructMethod(Method m) {
Object[] methodArgs = null;
if (m.getParameterTypes().length == 1)
methodArgs = new Object[] { context };
try {
if (!m.isAccessible()) {
m.setAccessible(true);
try {
m.invoke(userObject, methodArgs);
} finally {
m.setAccessible(false);
}
} else {
m.invoke(userObject, methodArgs);
}
} catch (Exception e) {
logWarning(userObject, e);
}
}
};
processor.shouldProcessPostConstruct = true;
processClassHierarchy(event.getArguments()[0], processor);
WeakReference ref = new WeakReference(event.getArguments()[0]);
synchronized (userObjects) {
userObjects.add(ref);
}
}
private void handleRemove(final ContextChangeEvent event) {
final String name = event.getName();
if (IContextConstants.PARENT.equals(name)) {
handleParentChange(event);
return;
}
Processor processor = new Processor(false) {
void processField(final Field field, String injectName, boolean optional) {
if (keyMatches(name, injectName) || field.getType().getName().equals(name))
setField(userObject, field, null);
}
void processMethod(final Method method, boolean optional) {
String candidateName = method.getName();
if (candidateName.length() <= setMethodPrefix.length())
return;
candidateName = candidateName.substring(setMethodPrefix.length());
Class[] parameterTypes = method.getParameterTypes();
// only inject methods with a single parameter
if (parameterTypes.length != 1)
return;
if (keyMatches(name, candidateName))
setMethod(userObject, method, null);
}
};
Object[] objectsCopy = safeObjectsCopy();
for (int i = 0; i < objectsCopy.length; i++) {
processClassHierarchy(objectsCopy[i], processor);
}
}
private Processor getRemovalProcessor() {
return new Processor(true) {
void processField(final Field field, String injectName, boolean optional) {
String key = findKey(injectName, field.getType());
if (key != null)
setField(userObject, field, null);
}
void processMethod(final Method method, boolean optional) {
String candidateName = method.getName();
if (!candidateName.startsWith(setMethodPrefix))
return;
candidateName = candidateName.substring(setMethodPrefix.length());
Class[] parameterTypes = method.getParameterTypes();
// only inject methods with a single parameter
if (parameterTypes.length != 1)
return;
// when initializing, inject every method that has a match in the context
String key = findKey(candidateName, parameterTypes[0]);
if (key != null)
setMethod(userObject, method, null);
}
};
}
/**
* Returns whether the given method is a post-construction process method, as defined by the
* class comment of {@link ContextInjectionFactory}.
*/
private boolean isPostConstruct(Method method) {
if (!method.getName().equals(IContextConstants.INJECTION_SET_CONTEXT_METHOD))
return false;
Class[] parms = method.getParameterTypes();
if (parms.length == 0)
return true;
if (parms.length == 1 && parms[0].equals(IEclipseContext.class))
return true;
return false;
}
protected boolean keyMatches(String key1, String key2) {
if (key1 == null && key2 == null)
return true;
if (key1 == null || key2 == null)
return false;
if (key1.equals(key2))
return true;
String candidate = altKey(key2);
if (candidate == null) // no alternative spellings
return false;
return key1.equals(candidate);
}
void logWarning(Object destination, Exception e) {
System.out.println("Injection failed " + destination.toString()); //$NON-NLS-1$
if (e != null)
e.printStackTrace();
// TBD convert this into real logging
// String msg = NLS.bind("Injection failed", destination.toString());
// RuntimeLog.log(new Status(IStatus.WARNING,
// IRuntimeConstants.PI_COMMON, 0, msg, e));
}
public boolean notify(final ContextChangeEvent event) {
switch (event.getEventType()) {
case ContextChangeEvent.INITIAL:
handleInitial(event);
break;
case ContextChangeEvent.ADDED:
handleAdd(event);
break;
case ContextChangeEvent.REMOVED:
handleRemove(event);
break;
case ContextChangeEvent.UNINJECTED:
handleRelease(event);
break;
case ContextChangeEvent.DISPOSE:
handleDispose(event);
break;
}
return (!userObjects.isEmpty());
}
/**
* Make the processor visit all declared members on the given class and all superclasses
*/
private void processClass(Class objectsClass, Processor processor, ProcessMethodsResult result) {
if (processor.isSetter) {
processFields(objectsClass, processor);
processMethods(objectsClass, processor, result);
} else {
processMethods(objectsClass, processor, result);
processFields(objectsClass, processor);
}
// recurse on superclass
Class superClass = objectsClass.getSuperclass();
if (!superClass.getName().equals(JAVA_OBJECT)) {
processClass(superClass, processor, result);
}
}
/**
* For setters: we set fields first, them methods. Otherwise, clear methods first, fields next
*/
private void processClassHierarchy(Object userObject, Processor processor) {
processor.setObject(userObject);
Class objectsClass = userObject.getClass();
ProcessMethodsResult processMethodsResult = new ProcessMethodsResult();
processClass(objectsClass, processor, processMethodsResult);
if (processor.shouldProcessPostConstruct) {
for (Iterator it = processMethodsResult.postConstructMethods.iterator(); it.hasNext();) {
Method m = (Method) it.next();
processor.processPostConstructMethod(m);
}
}
}
/**
* Make the processor visit all declared fields on the given class.
*/
private void processFields(Class objectsClass, Processor processor) {
Field[] fields = objectsClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
String injectName = field.getName();
boolean inject = false;
boolean optional = true;
try {
Object[] annotations = (Object[]) field.getClass().getMethod("getAnnotations", //$NON-NLS-1$
new Class[0]).invoke(field, EMPTY_ARR);
for (int j = 0; j < annotations.length; j++) {
Object annotation = annotations[j];
try {
String annotationName = ((Class) annotation.getClass().getMethod(
"annotationType", new Class[0]).invoke(annotation, EMPTY_ARR)) //$NON-NLS-1$
.getName();
if (annotationName.endsWith(INJECT) || annotationName.endsWith(IN)) {
inject = true;
try {
optional = ((Boolean) annotation.getClass().getMethod("optional",//$NON-NLS-1$
new Class[0]).invoke(annotation, EMPTY_ARR)).booleanValue();
} catch (Exception e) {
e.printStackTrace();
}
} else if (annotationName.endsWith(NAMED)) {
try {
injectName = (String) annotation.getClass().getMethod("value",//$NON-NLS-1$
new Class[0]).invoke(annotation, EMPTY_ARR);
} catch (Exception e) {
e.printStackTrace();
}
} else if (annotationName.endsWith(RESOURCE)) {
inject = true;
String resourceName = null;
try {
resourceName = (String) annotation.getClass().getMethod("name",//$NON-NLS-1$
new Class[0]).invoke(annotation, EMPTY_ARR);
} catch (Exception e) {
logWarning(field, e);
}
if (resourceName != null && !resourceName.equals("")) {//$NON-NLS-1$
injectName = resourceName;
}
}
} catch (Exception e1) {
logWarning(field, e1);
}
}
} catch (Exception e2) {
// ignore - no annotation support
}
if (!inject && injectName.startsWith(fieldPrefix)) {
inject = true;
injectName = injectName.substring(fieldPrefixLength);
}
if (inject) {
processor.processField(field, injectName, optional);
}
}
}
public static Object processInvoke(Object userObject, String methodName,
IEclipseContext localContext, Object defaultValue) {
boolean wasAccessible = true;
Method[] methods = userObject.getClass().getDeclaredMethods();
for (int j = 0; j < methods.length; j++) {
Method method = methods[j];
if (methodName.equals(method.getName())) {
try {
boolean satisfiable = true;
Class[] params = method.getParameterTypes();
Object[] contextParms = new Object[params.length];
Object[][] parameterAnnotations = (Object[][]) Method.class.getMethod(
"getParameterAnnotations", //$NON-NLS-1$
new Class[0]).invoke(method, EMPTY_ARR);
for (int i = 0; i < params.length && satisfiable; i++) {
Class clazz = params[i];
Object[] array = EMPTY_ARR;
if (parameterAnnotations.length > 0 && parameterAnnotations[i].length > 0) {
array = parameterAnnotations[i];
}
if (array != EMPTY_ARR) {
String injectName = clazz.getName();
for (int k = 0; k < array.length; k++) {
String annotationName = ((Class) array[k].getClass().getMethod(
"annotationType", new Class[0]).invoke(array[k], EMPTY_ARR)) //$NON-NLS-1$
.getName();
if (annotationName.endsWith(NAMED)) {
try {
injectName = (String) array[k].getClass().getMethod(
"value",//$NON-NLS-1$
new Class[0]).invoke(array[k], EMPTY_ARR);
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (IEclipseContext.class.equals(injectName)) {
contextParms[i] = localContext;
} else if (localContext.containsKey(injectName)) {
contextParms[i] = localContext.get(injectName);
} else {
satisfiable = false;
}
} else if (IEclipseContext.class.equals(clazz)) {
contextParms[i] = localContext;
} else if (localContext.containsKey(clazz.getName())) {
contextParms[i] = localContext.get(clazz.getName());
} else if (!localContext.containsKey(clazz.getName())
&& !IEclipseContext.class.equals(clazz)) {
satisfiable = false;
}
}
if (satisfiable) {
if (!method.isAccessible()) {
method.setAccessible(true);
wasAccessible = false;
}
return method.invoke(userObject, contextParms);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (!wasAccessible) {
method.setAccessible(false);
}
}
}
}
if (defaultValue == null) {
throw new RuntimeException(
"could not find satisfiable method " + methodName + " in class " + userObject.getClass()); //$NON-NLS-1$//$NON-NLS-2$
}
return defaultValue;
}
/**
* Make the processor visit all declared methods on the given class.
*/
private ProcessMethodsResult processMethods(Class objectsClass, Processor processor,
ProcessMethodsResult result) {
Method[] methods = objectsClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
// don't process methods already visited in subclasses
if (result.seen(method))
continue;
if (isPostConstruct(method)) {
result.postConstructMethods.add(method);
continue;
}
String candidateName = method.getName();
boolean inject = candidateName.startsWith(setMethodPrefix);
boolean optional = false;
try {
Object[] annotations = (Object[]) method.getClass().getMethod("getAnnotations", //$NON-NLS-1$
new Class[0]).invoke(method, EMPTY_ARR);
for (int j = 0; j < annotations.length; j++) {
Object annotation = annotations[j];
try {
String annotationName = ((Class) annotation.getClass().getMethod(
"annotationType", new Class[0]).invoke(annotation, EMPTY_ARR))//$NON-NLS-1$
.getName();
if (annotationName.endsWith(INJECT) || annotationName.endsWith(IN)) {
inject = true;
try {
optional = ((Boolean) annotation.getClass().getMethod("optional",//$NON-NLS-1$
new Class[0]).invoke(annotation, EMPTY_ARR)).booleanValue();
} catch (Exception e) {
e.printStackTrace();
}
} else if (processor.shouldProcessPostConstruct
&& annotationName.endsWith(POST_CONSTRUCT)) {
inject = false;
result.postConstructMethods.add(method);
}
} catch (Exception ex) {
logWarning(method, ex);
}
}
} catch (Exception e) {
// ignore - no annotation support
}
if (inject) {
processor.processMethod(method, optional);
}
}
return result;
}
private Object[] safeObjectsCopy() {
Object[] result;
int pos = 0;
synchronized (userObjects) {
result = new Object[userObjects.size()];
for (Iterator i = userObjects.iterator(); i.hasNext();) {
WeakReference ref = (WeakReference) i.next();
Object userObject = ref.get();
if (userObject == null) { // user object got GCed, clean up refs
// for future
i.remove();
continue;
}
result[pos] = userObject;
pos++;
}
}
if (pos == result.length)
return result;
// reallocate the array
Object[] tmp = new Object[pos];
System.arraycopy(result, 0, tmp, 0, pos);
return tmp;
}
protected boolean setField(Object userObject, Field field, Object value) {
if ((value != null) && !field.getType().isAssignableFrom(value.getClass())) {
// TBD add debug option
return false;
}
boolean wasAccessible = true;
if (!field.isAccessible()) {
field.setAccessible(true);
wasAccessible = false;
}
try {
field.set(userObject, value);
} catch (IllegalArgumentException e) {
logWarning(field, e);
return false;
} catch (IllegalAccessException e) {
logWarning(field, e);
return false;
} finally {
if (!wasAccessible)
field.setAccessible(false);
}
return true;
}
protected boolean setMethod(Object userObject, Method method, Object value) {
Class[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1)
return false;
if ((value != null) && !parameterTypes[0].isAssignableFrom(value.getClass()))
return false;
boolean wasAccessible = true;
if (!method.isAccessible()) {
method.setAccessible(true);
wasAccessible = false;
}
try {
method.invoke(userObject, new Object[] { value });
} catch (IllegalArgumentException e) {
logWarning(method, e);
return false;
} catch (IllegalAccessException e) {
logWarning(method, e);
return false;
} catch (InvocationTargetException e) {
logWarning(method, e);
return false;
} finally {
if (!wasAccessible)
method.setAccessible(false);
}
return true;
}
public String toString() {
return "InjectionTracker(" + context + ')'; //$NON-NLS-1$
}
}