/****************************************************************************** * Copyright (c) 2006, 2010 VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0 * is available at http://www.opensource.org/licenses/apache2.0.php. * You may elect to redistribute this code under either of these licenses. * * Contributors: * VMware Inc. *****************************************************************************/ package org.eclipse.gemini.blueprint.compendium.internal.cm; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Dictionary; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.gemini.blueprint.util.internal.ReflectionUtils; import org.springframework.util.Assert; /** * Adapter class that takes care of detecting and invoking a custom method for managed-service beans. * * The supported method formats are: * * <pre> public void anyMethodName(Map properties) public void anyMethodName(Map<String,?> properties); // for * Java 5 public void anyMethodName(Dictionary properties); </pre> * * @author Costin Leau * */ class UpdateMethodAdapter { private static final Log log = LogFactory.getLog(UpdateMethodAdapter.class); /** * Determines the update method. * * @param target * @param methodName * @return */ static Map determineUpdateMethod(final Class<?> target, final String methodName) { Assert.notNull(target); Assert.notNull(methodName); final Map methods = new LinkedHashMap(2); final boolean trace = log.isTraceEnabled(); org.springframework.util.ReflectionUtils.doWithMethods(target, new org.springframework.util.ReflectionUtils.MethodCallback() { public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { // consider filtering bridge non-void and non-public methods as well if (!method.isBridge() && Modifier.isPublic(method.getModifiers()) && (void.class.equals(method.getReturnType())) && methodName.equals(method.getName())) { // check the argument types Class<?>[] args = method.getParameterTypes(); // Properties can be passed as Map or Dictionary if (args != null && args.length == 1) { Class<?> propertiesType = args[0]; if (propertiesType.isAssignableFrom(Map.class) || propertiesType.isAssignableFrom(Dictionary.class)) { if (trace) log.trace("Discovered custom method [" + method.toString() + "] on " + target); // see if there was a method already found Method m = (Method) methods.get(propertiesType); if (m != null) { if (trace) log.trace("Type " + propertiesType + " already has an associated method [" + m.toString() + "];ignoring " + method); } else methods.put(propertiesType, method); } } } } }); return methods; } static void invokeCustomMethods(Object target, Map methods, Map properties) { if (methods != null && !methods.isEmpty()) { boolean trace = log.isTraceEnabled(); Object[] args = new Object[] { properties }; for (Iterator iterator = methods.values().iterator(); iterator.hasNext();) { Method method = (Method) iterator.next(); if (trace) log.trace("Invoking listener custom method " + method); try { ReflectionUtils.invokeMethod(method, target, args); } // make sure to log exceptions and continue with the // rest of the methods catch (Exception ex) { Exception cause = ReflectionUtils.getInvocationException(ex); log.warn("Custom method [" + method + "] threw exception when passing properties [" + properties + "]", cause); } } } } private final Map methods; /** * Constructs a new <code>UpdateMethodAdapter</code> instance. * * @param methodName * @param type */ UpdateMethodAdapter(String methodName, Class<?> type) { this.methods = determineUpdateMethod(type, methodName); } void invoke(Object instance, Map properties) { invokeCustomMethods(instance, methods, properties); } }