blob: 41ba530f9e27aefe0e8cd44e94f6158519931160 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2015 Oracle.
* 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:
* Bob Nettleton (Oracle) - Initial Reference Implementation
******************************************************************************/
package org.eclipse.gemini.naming;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
class ServiceInvocationHandler implements InvocationHandler {
private static final Logger logger = Logger.getLogger(ServiceInvocationHandler.class.getName());
private final BundleContext m_callerBundleContext;
/* backing OSGi service */
private Object m_osgiService;
/* service tracker for the backing service */
protected ServiceTracker m_serviceTracker;
/* ServiceReference for the backing service */
private ServiceReference m_serviceReference;
/* the URL information used to rebind the backing service if necessary */
private final OSGiURLParser m_urlParser;
ServiceInvocationHandler(BundleContext callerBundleContext, ServiceReference serviceReference, OSGiURLParser urlParser, Object osgiService) {
m_callerBundleContext = callerBundleContext;
// initialize backing service
m_osgiService = osgiService;
m_serviceReference = serviceReference;
m_urlParser = urlParser;
// open a tracker for just this service
m_serviceTracker =
new ServiceTracker(m_callerBundleContext, m_serviceReference, null);
m_serviceTracker.open();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return SecurityUtils.invokePrivilegedAction(new ServiceInvokeAction(method, args));
}
private Object handleMethodInvocation(Method method, Object[] args) throws Throwable {
if (isServiceAvailable()) {
return invokeMethodOnService(method, args);
} else {
// attempt to obtain another service reference to match this interface
if(obtainService()) {
return invokeMethodOnService(method, args);
}
}
throw new ServiceException("Backing service is not available for invocation",
ServiceException.UNREGISTERED);
}
private Object invokeMethodOnService(Method method, Object[] args) throws Throwable {
try {
return ReflectionUtils.invokeMethodOnObject(method, m_osgiService, args);
}
catch (IllegalAccessException illegalAccessException) {
throw new ServiceException("An error occurred while trying to invoke on this service, please verify that this service's interface is public", illegalAccessException);
}
}
protected void close() {
try {
m_callerBundleContext.ungetService(m_serviceReference);
}
catch (Throwable throwable) {
logger.log(Level.FINER,
"An Exception occurred while trying to unget the backing OSGi service",
throwable);
}
m_serviceTracker.close();
}
@Override
protected void finalize() throws Throwable {
close();
}
private boolean isServiceAvailable() {
return m_serviceTracker.size() == 1;
}
protected boolean obtainService() {
m_serviceTracker.close();
try {
ServiceReference[] serviceReferences =
m_callerBundleContext.getServiceReferences(m_urlParser.getServiceInterface(),
m_urlParser.getFilter());
if (serviceReferences != null) {
final ServiceReference[] sortedServiceReferences =
ServiceUtils.sortServiceReferences(serviceReferences);
// reset the tracker
return resetBackingService(sortedServiceReferences[0]);
} else {
// attempt to locate service using service name property
ServiceReference[] serviceReferencesByName =
ServiceUtils.getServiceReferencesByServiceName(m_callerBundleContext, m_urlParser);
if (serviceReferencesByName != null) {
ServiceReference[] sortedServiceReferences =
ServiceUtils.sortServiceReferences(serviceReferencesByName);
// reset the tracker
return resetBackingService(sortedServiceReferences[0]);
}
}
}
catch (InvalidSyntaxException invalidSyntaxException) {
logger.log(Level.SEVERE,
"An error in the filter syntax for this OSGi lookup has occurred.",
invalidSyntaxException);
}
return false;
}
private boolean resetBackingService(ServiceReference serviceReference) {
m_serviceTracker =
new ServiceTracker(m_callerBundleContext, serviceReference, null);
m_serviceTracker.open();
// reset the service
m_osgiService = m_serviceTracker.getService();
if(m_osgiService!= null) {
return true;
}
return false;
}
private class ServiceInvokeAction extends ReflectiveInvokeAction {
ServiceInvokeAction(Method method, Object[] args) {
super(method, args);
}
@Override
public Object invokeMethod(Method method, Object[] args) throws Throwable {
return handleMethodInvocation(method, args);
}
}
}