/****************************************************************************** | |
* 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.config.internal.adapter; | |
import org.apache.commons.logging.Log; | |
import org.apache.commons.logging.LogFactory; | |
import org.eclipse.gemini.blueprint.context.support.internal.security.SecurityUtils; | |
import org.eclipse.gemini.blueprint.service.exporter.OsgiServiceRegistrationListener; | |
import org.springframework.beans.factory.BeanFactory; | |
import org.springframework.beans.factory.BeanFactoryAware; | |
import org.springframework.beans.factory.InitializingBean; | |
import org.springframework.util.Assert; | |
import org.springframework.util.StringUtils; | |
import java.lang.reflect.Method; | |
import java.security.AccessControlContext; | |
import java.security.AccessController; | |
import java.security.PrivilegedAction; | |
import java.security.PrivilegedActionException; | |
import java.security.PrivilegedExceptionAction; | |
import java.util.List; | |
import java.util.Map; | |
/** | |
* Adapter/wrapper class that handles listener with custom method invocation. Similar in functionality to | |
* {@link org.eclipse.gemini.blueprint.config.internal.adapter.OsgiServiceLifecycleListenerAdapter}. | |
* | |
* @author Costin Leau | |
* | |
*/ | |
public class OsgiServiceRegistrationListenerAdapter implements OsgiServiceRegistrationListener, InitializingBean, | |
BeanFactoryAware { | |
private static final Log log = LogFactory.getLog(OsgiServiceRegistrationListenerAdapter.class); | |
/** does the target implement the listener interface */ | |
private boolean isListener; | |
private String registrationMethod, unregistrationMethod; | |
/** actual target */ | |
private Object target; | |
/** target bean name (when dealing with cycles) */ | |
private String targetBeanName; | |
/** bean factory used for retrieving the target when dealing with cycles */ | |
private BeanFactory beanFactory; | |
/** init flag */ | |
private boolean initialized; | |
/** | |
* Map of methods keyed by the first parameter which indicates the service type expected. | |
*/ | |
private Map<Class<?>, List<Method>> registrationMethods, unregistrationMethods; | |
private boolean isBlueprintCompliant = false; | |
public void afterPropertiesSet() { | |
Assert.notNull(beanFactory); | |
Assert.isTrue(target != null || StringUtils.hasText(targetBeanName), | |
"one of 'target' or 'targetBeanName' properties has to be set"); | |
if (target != null) | |
initialized = true; | |
// do validation (on the target type) | |
initialize(); | |
// postpone target initialization until one of bind/unbind method is called | |
} | |
private void retrieveTarget() { | |
target = beanFactory.getBean(targetBeanName); | |
initialized = true; | |
} | |
/** | |
* Initialise adapter. Determine custom methods and do validation. | |
*/ | |
private void initialize() { | |
Class<?> clazz = (target == null ? beanFactory.getType(targetBeanName) : target.getClass()); | |
isListener = OsgiServiceRegistrationListener.class.isAssignableFrom(clazz); | |
if (isListener) | |
if (log.isDebugEnabled()) | |
log.debug(clazz.getName() + " is a registration listener"); | |
registrationMethods = | |
CustomListenerAdapterUtils.determineCustomMethods(clazz, registrationMethod, isBlueprintCompliant); | |
unregistrationMethods = | |
CustomListenerAdapterUtils.determineCustomMethods(clazz, unregistrationMethod, isBlueprintCompliant); | |
if (!isListener && (registrationMethods.isEmpty() && unregistrationMethods.isEmpty())) | |
throw new IllegalArgumentException("Target object needs to implement " | |
+ OsgiServiceRegistrationListener.class.getName() | |
+ " or custom registered/unregistered methods have to be specified"); | |
if (log.isTraceEnabled()) { | |
StringBuilder builder = new StringBuilder(); | |
builder.append("Discovered bind methods="); | |
builder.append(registrationMethods.values()); | |
builder.append("\nunbind methods="); | |
builder.append(unregistrationMethods.values()); | |
log.trace(builder.toString()); | |
} | |
} | |
public void registered(final Object service, final Map serviceProperties) { | |
boolean trace = log.isTraceEnabled(); | |
if (trace) | |
log.trace("Invoking registered method with props=" + serviceProperties); | |
if (!initialized) | |
retrieveTarget(); | |
boolean isSecurityEnabled = System.getSecurityManager() != null; | |
AccessControlContext acc = null; | |
if (isSecurityEnabled) { | |
acc = SecurityUtils.getAccFrom(beanFactory); | |
} | |
// first call interface method (if it exists) | |
if (isListener) { | |
if (trace) | |
log.trace("Invoking listener interface methods"); | |
try { | |
if (isSecurityEnabled) { | |
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { | |
((OsgiServiceRegistrationListener) target).registered(service, serviceProperties); | |
return null; | |
}, acc); | |
} else { | |
((OsgiServiceRegistrationListener) target).registered(service, serviceProperties); | |
} | |
} catch (Exception ex) { | |
if (ex instanceof PrivilegedActionException) { | |
ex = ((PrivilegedActionException) ex).getException(); | |
} | |
log.warn("Standard registered method on [" + target.getClass().getName() + "] threw exception", ex); | |
} | |
} | |
if (isSecurityEnabled) { | |
AccessController.doPrivileged((PrivilegedAction<Object>) () -> { | |
CustomListenerAdapterUtils.invokeCustomMethods(target, registrationMethods, service, | |
serviceProperties); | |
return null; | |
}, acc); | |
} else { | |
CustomListenerAdapterUtils.invokeCustomMethods(target, registrationMethods, service, serviceProperties); | |
} | |
} | |
public void unregistered(final Object service, final Map serviceProperties) { | |
boolean trace = log.isTraceEnabled(); | |
if (trace) | |
log.trace("Invoking unregistered method with props=" + serviceProperties); | |
if (!initialized) | |
retrieveTarget(); | |
boolean isSecurityEnabled = System.getSecurityManager() != null; | |
AccessControlContext acc = null; | |
if (isSecurityEnabled) { | |
acc = SecurityUtils.getAccFrom(beanFactory); | |
} | |
// first call interface method (if it exists) | |
if (isListener) { | |
if (trace) | |
log.trace("Invoking listener interface methods"); | |
try { | |
if (isSecurityEnabled) { | |
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { | |
((OsgiServiceRegistrationListener) target).unregistered(service, serviceProperties); | |
return null; | |
}, acc); | |
} else { | |
((OsgiServiceRegistrationListener) target).unregistered(service, serviceProperties); | |
} | |
} catch (Exception ex) { | |
log.warn("Standard unregistered method on [" + target.getClass().getName() + "] threw exception", ex); | |
} | |
} | |
if (isSecurityEnabled) { | |
AccessController.doPrivileged((PrivilegedAction<Object>) () -> { | |
CustomListenerAdapterUtils.invokeCustomMethods(target, unregistrationMethods, service, | |
serviceProperties); | |
return null; | |
}, acc); | |
} else { | |
CustomListenerAdapterUtils.invokeCustomMethods(target, unregistrationMethods, service, serviceProperties); | |
} | |
} | |
/** | |
* @param registrationMethod The registrationMethod to set. | |
*/ | |
public void setRegistrationMethod(String registrationMethod) { | |
this.registrationMethod = registrationMethod; | |
} | |
/** | |
* @param unregistrationMethod The unregistrationMethod to set. | |
*/ | |
public void setUnregistrationMethod(String unregistrationMethod) { | |
this.unregistrationMethod = unregistrationMethod; | |
} | |
public void setBeanFactory(BeanFactory beanFactory) { | |
this.beanFactory = beanFactory; | |
} | |
/** | |
* @param target The target to set. | |
*/ | |
public void setTarget(Object target) { | |
this.target = target; | |
} | |
/** | |
* @param targetBeanName The targetBeanName to set. | |
*/ | |
public void setTargetBeanName(String targetBeanName) { | |
this.targetBeanName = targetBeanName; | |
} | |
public void setBlueprintCompliant(boolean compliant) { | |
this.isBlueprintCompliant = compliant; | |
} | |
} |