From f759f897b063757bcc7a50229715035159d79dd5 Mon Sep 17 00:00:00 2001 From: Niels Meijer Date: Mon, 17 Jul 2017 16:32:38 +0200 Subject: [PATCH] Add DllDispatcherManager to interface with DLL's on the classpath The DLL must have two main functions: getServices(): to retreive a list of possible services that can be registered in the DllDispatchermanager. processMessage(serviceName, correlationId, requestMessage): to call a service in the DLL. --- .../src/main/java/DllDispatcherManager.java | 14 + .../dispatcher/DispatcherManagerFactory.java | 16 +- .../dispatcher/DispatcherManagerImpl.java | 244 +++++++++--------- .../dispatcher/DllDispatcherManagerImpl.java | 152 +++++++++++ .../DllDispatcherManagerInterface.java | 21 ++ 5 files changed, 321 insertions(+), 126 deletions(-) create mode 100644 servicedispatcher/src/main/java/DllDispatcherManager.java create mode 100644 servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DllDispatcherManagerImpl.java create mode 100644 servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DllDispatcherManagerInterface.java diff --git a/servicedispatcher/src/main/java/DllDispatcherManager.java b/servicedispatcher/src/main/java/DllDispatcherManager.java new file mode 100644 index 0000000..588cfa4 --- /dev/null +++ b/servicedispatcher/src/main/java/DllDispatcherManager.java @@ -0,0 +1,14 @@ +import nl.nn.adapterframework.dispatcher.DllDispatcherManagerInterface; + +public class DllDispatcherManager implements DllDispatcherManagerInterface { + + @Override + native public String processRequest(String functionName, String correlationId, String requestMessage); + + @Override + native public String getServices(); + + static { + System.loadLibrary("Wrapper"); + } +} \ No newline at end of file diff --git a/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DispatcherManagerFactory.java b/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DispatcherManagerFactory.java index 5d598a3..1130f87 100644 --- a/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DispatcherManagerFactory.java +++ b/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DispatcherManagerFactory.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package nl.nn.adapterframework.dispatcher; +package nl.nn.adapterframework.dispatcher; /** * Factory to obtain an instance of the {@link DispatcherManager}. @@ -26,8 +26,16 @@ public class DispatcherManagerFactory { /** * Obtain an instance of the {@link DispatcherManager}. - */ - public static DispatcherManager getDispatcherManager() throws DispatcherException { - return DispatcherManagerImpl.getInstance(); + */ + public static DispatcherManager getDispatcherManager() throws DispatcherException { + return DispatcherManagerImpl.getInstance(); + } + + public static DispatcherManager getDispatcherManager(String dispatcherType) throws DispatcherException { + if(dispatcherType.equalsIgnoreCase("dll")) { + return DllDispatcherManagerImpl.getInstance(); + } + else + return getDispatcherManager(); } } diff --git a/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DispatcherManagerImpl.java b/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DispatcherManagerImpl.java index 9cf070a..5e13883 100644 --- a/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DispatcherManagerImpl.java +++ b/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DispatcherManagerImpl.java @@ -12,127 +12,127 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -*/ -package nl.nn.adapterframework.dispatcher; - -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.HashMap; - -/** - * Actual implementation of {@link DispatcherManager}. - * - * @author Gerrit van Brakel - * @version $Id: DispatcherManagerImpl.java,v 1.3 2011/07/18 08:33:01 L190409 Exp $ - */ -class DispatcherManagerImpl implements DispatcherManager { - - private static final boolean DEBUG=true; - - /** - * This is effectively an instance of this class (although actually it may be instead a - * java.lang.reflect.Proxy wrapping an instance from the original classloader). - */ - private static DispatcherManager instance = null; - - /* - * There can be only one - ie. even if the class is loaded in several different classloaders, - * there will be only one instance of the object. - */ - static DispatcherManager getInstance(ClassLoader classLoader) throws DispatcherException { - DispatcherManager result = null; - ClassLoader parentclassLoader = classLoader.getParent(); - // search for an instance as high in the classloader hierarchy as possible - if (parentclassLoader != null) { - result = getInstance(parentclassLoader); - if (result == null) { - ClassLoader myClassLoader = DispatcherManagerImpl.class.getClassLoader(); - Class classInstance; - try { - classInstance = parentclassLoader.loadClass(DispatcherManagerImpl.class.getName()); - // And call its getInstance method - this gives the correct - // instance of ourself - Method getInstanceMethod = classInstance.getDeclaredMethod("getInstance", new Class[] {}); - Object otherDispatcherManager = getInstanceMethod.invoke(null,new Object[] {}); - // But, we can't cast it to our own interface directly because classes loaded from - // different classloaders implement different versions of an interface. - // So instead, we use java.lang.reflect.Proxy to wrap it in an object that *does* - // support our interface, and the proxy will use reflection to pass through all calls - // to the object. - result = (DispatcherManager) Proxy.newProxyInstance(myClassLoader, new Class[] { DispatcherManager.class }, - new PassThroughProxyHandler(otherDispatcherManager)); - if (DEBUG) System.out.println("DispatcherManagerImpl INFO created DispatcherManager using ClassLoader ["+ parentclassLoader.getClass().getName() + "] that is parent of ["+ classLoader.getClass().getName() + "]"); - } catch (Exception e) { - if (DEBUG) System.out.println("DispatcherManagerImpl DEBUG "+ e.getClass().getName()+ " when trying to load DispatcherManager using ClassLoader ["+ parentclassLoader.getClass().getName() + "] that is parent of ["+ classLoader.getClass().getName() + "]: "+ e.getMessage()); - return null; - } - } - } - return result; - } - - /** - * Retrieve an instance of DispatcherManager from the original classloader. This is a true - * Singleton, in that there will only be one instance of this object in the virtual machine, - * even though there may be several copies of its class file loaded in different classloaders. - */ - synchronized static DispatcherManager getInstance() throws DispatcherException { - if (instance==null) { - ClassLoader myClassLoader = DispatcherManagerImpl.class.getClassLoader(); - if (myClassLoader!=null) { - instance = getInstance(myClassLoader); - } else { - System.out.println("DispatcherManagerImpl WARN could not obtain ClassLoader for ["+ DispatcherManagerImpl.class.getName() + "], instantiated DispatcherManager might be too low in class path tree (not on a common branch)"); - } - if (instance==null) { - instance = new DispatcherManagerImpl(); - } - } - return instance; - } - +*/ +package nl.nn.adapterframework.dispatcher; + +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; + +/** + * Actual implementation of {@link DispatcherManager}. + * + * @author Gerrit van Brakel + * @version $Id: DispatcherManagerImpl.java,v 1.3 2011/07/18 08:33:01 L190409 Exp $ + */ +class DispatcherManagerImpl implements DispatcherManager { + + private static final boolean DEBUG=true; + + /** + * This is effectively an instance of this class (although actually it may be instead a + * java.lang.reflect.Proxy wrapping an instance from the original classloader). + */ + private static DispatcherManager instance = null; + + /* + * There can be only one - ie. even if the class is loaded in several different classloaders, + * there will be only one instance of the object. + */ + static DispatcherManager getInstance(ClassLoader classLoader) throws DispatcherException { + DispatcherManager result = null; + ClassLoader parentclassLoader = classLoader.getParent(); + // search for an instance as high in the classloader hierarchy as possible + if (parentclassLoader != null) { + result = getInstance(parentclassLoader); + if (result == null) { + ClassLoader myClassLoader = DispatcherManagerImpl.class.getClassLoader(); + Class classInstance; + try { + classInstance = parentclassLoader.loadClass(DispatcherManagerImpl.class.getName()); + // And call its getInstance method - this gives the correct + // instance of ourself + Method getInstanceMethod = classInstance.getDeclaredMethod("getInstance", new Class[] {}); + Object otherDispatcherManager = getInstanceMethod.invoke(null,new Object[] {}); + // But, we can't cast it to our own interface directly because classes loaded from + // different classloaders implement different versions of an interface. + // So instead, we use java.lang.reflect.Proxy to wrap it in an object that *does* + // support our interface, and the proxy will use reflection to pass through all calls + // to the object. + result = (DispatcherManager) Proxy.newProxyInstance(myClassLoader, new Class[] { DispatcherManager.class }, + new PassThroughProxyHandler(otherDispatcherManager)); + if (DEBUG) System.out.println("DispatcherManagerImpl INFO created DispatcherManager using ClassLoader ["+ parentclassLoader.getClass().getName() + "] that is parent of ["+ classLoader.getClass().getName() + "]"); + } catch (Exception e) { + if (DEBUG) System.out.println("DispatcherManagerImpl DEBUG "+ e.getClass().getName()+ " when trying to load DispatcherManager using ClassLoader ["+ parentclassLoader.getClass().getName() + "] that is parent of ["+ classLoader.getClass().getName() + "]: "+ e.getMessage()); + return null; + } + } + } + return result; + } + + /** + * Retrieve an instance of DispatcherManager from the original classloader. This is a true + * Singleton, in that there will only be one instance of this object in the virtual machine, + * even though there may be several copies of its class file loaded in different classloaders. + */ + synchronized static DispatcherManager getInstance() throws DispatcherException { + if (instance==null) { + ClassLoader myClassLoader = DispatcherManagerImpl.class.getClassLoader(); + if (myClassLoader!=null) { + instance = getInstance(myClassLoader); + } else { + System.out.println("DispatcherManagerImpl WARN could not obtain ClassLoader for ["+ DispatcherManagerImpl.class.getName() + "], instantiated DispatcherManager might be too low in class path tree (not on a common branch)"); + } + if (instance==null) { + instance = new DispatcherManagerImpl(); + } + } + return instance; + } + private DispatcherManagerImpl() { - } - - private HashMap requestProcessorMap = new HashMap(); - - public String processRequest(String clientName, String message) throws DispatcherException, RequestProcessorException{ - return processRequest(clientName, null, message, null); - } - - public String processRequest(String clientName, String message, HashMap requestContext) throws DispatcherException, RequestProcessorException{ - return processRequest(clientName, null, message, requestContext); - } - - public String processRequest(String clientName, String correlationId, String message, HashMap requestContext) throws DispatcherException, RequestProcessorException { + } + + private HashMap requestProcessorMap = new HashMap(); + + public String processRequest(String serviceName, String message) throws DispatcherException, RequestProcessorException{ + return processRequest(serviceName, null, message, null); + } + + public String processRequest(String serviceName, String message, HashMap requestContext) throws DispatcherException, RequestProcessorException{ + return processRequest(serviceName, null, message, requestContext); + } + + public String processRequest(String serviceName, String correlationId, String message, HashMap requestContext) throws DispatcherException, RequestProcessorException { RequestProcessor listener=null; - - synchronized (requestProcessorMap) { - listener = (RequestProcessor)requestProcessorMap.get(clientName); - } - if (listener==null) { - throw new DispatcherException("no RequestProcessor registered for ["+clientName+"]"); - } - try { - ClassLoader callersClassLoader = Thread.currentThread().getContextClassLoader(); - try { - // set contextClassLoader, in order to really switch to the application called. - // This enables new classes to be loaded from proxy's own classpath, enabling - // Xalan extension functions, like 'build-node()' - Thread.currentThread().setContextClassLoader(listener.getClass().getClassLoader()); - return listener.processRequest(correlationId,message,requestContext); - } finally { - Thread.currentThread().setContextClassLoader(callersClassLoader); - } - } catch (Throwable t) { - throw new RequestProcessorException("RequestProcessor ["+clientName+"] caught exception",t); - } - } - - public void register(String name, RequestProcessor listener) throws DispatcherException { - synchronized (requestProcessorMap) { - requestProcessorMap.put(name, listener); - } - } -} - + + synchronized (requestProcessorMap) { + listener = (RequestProcessor)requestProcessorMap.get(serviceName); + } + if (listener==null) { + throw new DispatcherException("no RequestProcessor registered for ["+serviceName+"]"); + } + try { + ClassLoader callersClassLoader = Thread.currentThread().getContextClassLoader(); + try { + // set contextClassLoader, in order to really switch to the application called. + // This enables new classes to be loaded from proxy's own classpath, enabling + // Xalan extension functions, like 'build-node()' + Thread.currentThread().setContextClassLoader(listener.getClass().getClassLoader()); + return listener.processRequest(correlationId,message,requestContext); + } finally { + Thread.currentThread().setContextClassLoader(callersClassLoader); + } + } catch (Throwable t) { + throw new RequestProcessorException("RequestProcessor ["+serviceName+"] caught exception",t); + } + } + + public void register(String name, RequestProcessor listener) throws DispatcherException { + synchronized (requestProcessorMap) { + requestProcessorMap.put(name, listener); + } + } +} + diff --git a/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DllDispatcherManagerImpl.java b/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DllDispatcherManagerImpl.java new file mode 100644 index 0000000..0723282 --- /dev/null +++ b/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DllDispatcherManagerImpl.java @@ -0,0 +1,152 @@ +/* + Copyright 2013, 2017 Nationale-Nederlanden + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package nl.nn.adapterframework.dispatcher; + +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.StringTokenizer; + +import nl.nn.adapterframework.dispatcher.DispatcherException; + +public class DllDispatcherManagerImpl implements DispatcherManager { + + private DllDispatcherManagerInterface DllInstance; + private static final boolean DEBUG=true; + private List availableServices = new ArrayList(); + + /** + * This is effectively an instance of this class (although actually it may be instead a + * java.lang.reflect.Proxy wrapping an instance from the original classloader). + */ + private static DispatcherManager instance = null; + + /* + * There can be only one - ie. even if the class is loaded in several different classloaders, + * there will be only one instance of the object. + */ + static DispatcherManager getInstance(ClassLoader classLoader) throws DispatcherException { + DispatcherManager result = null; + ClassLoader parentclassLoader = classLoader.getParent(); + // search for an instance as high in the classloader hierarchy as possible + if (parentclassLoader != null) { + result = getInstance(parentclassLoader); + if (result == null) { + ClassLoader myClassLoader = DllDispatcherManagerImpl.class.getClassLoader(); + Class classInstance; + try { + classInstance = parentclassLoader.loadClass(DllDispatcherManagerImpl.class.getName()); + // And call its getInstance method - this gives the correct + // instance of ourself + Method getInstanceMethod = classInstance.getDeclaredMethod("getInstance", new Class[] {}); + Object otherDispatcherManager = getInstanceMethod.invoke(null,new Object[] {}); + // But, we can't cast it to our own interface directly because classes loaded from + // different classloaders implement different versions of an interface. + // So instead, we use java.lang.reflect.Proxy to wrap it in an object that *does* + // support our interface, and the proxy will use reflection to pass through all calls + // to the object. + result = (DispatcherManager) Proxy.newProxyInstance(myClassLoader, new Class[] { DispatcherManager.class }, + new PassThroughProxyHandler(otherDispatcherManager)); + if (DEBUG) System.out.println("DispatcherManagerImpl INFO created DispatcherManager using ClassLoader ["+ parentclassLoader.getClass().getName() + "] that is parent of ["+ classLoader.getClass().getName() + "]"); + } catch (Exception e) { + if (DEBUG) System.out.println("DispatcherManagerImpl DEBUG "+ e.getClass().getName()+ " when trying to load DispatcherManager using ClassLoader ["+ parentclassLoader.getClass().getName() + "] that is parent of ["+ classLoader.getClass().getName() + "]: "+ e.getMessage()); + return null; + } + } + } + return result; + } + + /** + * Retrieve an instance of DispatcherManager from the original classloader. This is a true + * Singleton, in that there will only be one instance of this object in the virtual machine, + * even though there may be several copies of its class file loaded in different classloaders. + */ + synchronized static DispatcherManager getInstance() throws DispatcherException { + if (instance==null) { + ClassLoader myClassLoader = DllDispatcherManagerImpl.class.getClassLoader(); + if (myClassLoader!=null) { + instance = getInstance(myClassLoader); + } else { + System.out.println("DllDispatcherManagerImpl WARN could not obtain ClassLoader for ["+ DllDispatcherManagerImpl.class.getName() + "], instantiated DispatcherManager might be too low in class path tree (not on a common branch)"); + } + if (instance==null) { + instance = new DllDispatcherManagerImpl(); + } + } + return instance; + } + + private DllDispatcherManagerImpl() throws DispatcherException { + try { + Class dll = Class.forName("DllDispatcherManager"); + DllInstance = (DllDispatcherManagerInterface) dll.newInstance(); + } + catch (Exception e) { + throw new DispatcherException("Failed to initialize DllDispatcherManager!", e); + } + String services = DllInstance.getServices(); + if(!services.isEmpty()) { + StringTokenizer st = new StringTokenizer(services, ","); + while (st.hasMoreTokens()) { + register(st.nextToken()); + } + } + else { + throw new DispatcherException("Successfully loaded DllDispatcherManager, but no services were found!"); + } + } + + @Override + public String processRequest(String serviceName, String message) throws DispatcherException, RequestProcessorException { + return processRequest(serviceName, null, message, null); + } + + @Override + public String processRequest(String serviceName, String message, HashMap requestContext) throws DispatcherException, RequestProcessorException{ + return processRequest(serviceName, null, message, requestContext); + } + + @Override + public String processRequest(String serviceName, String correlationId, String message, HashMap requestContext) throws DispatcherException, RequestProcessorException { + try { + boolean registeredService = false; + synchronized (availableServices) { + registeredService = availableServices.contains(serviceName); + } + if (registeredService==false) { + throw new DispatcherException("no service registered for ["+serviceName+"]"); + } + return DllInstance.processRequest(serviceName, correlationId, message); + } + catch (Exception e) { + throw new DispatcherException("Error while processing service ["+serviceName+"]", e); + } + } + + @Override + public void register(String serviceName, RequestProcessor listener) throws DispatcherException { + register(serviceName); + } + + public void register(String serviceName) { + synchronized (availableServices) { + availableServices.add(serviceName); + } + } +} \ No newline at end of file diff --git a/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DllDispatcherManagerInterface.java b/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DllDispatcherManagerInterface.java new file mode 100644 index 0000000..81473e9 --- /dev/null +++ b/servicedispatcher/src/main/java/nl/nn/adapterframework/dispatcher/DllDispatcherManagerInterface.java @@ -0,0 +1,21 @@ +package nl.nn.adapterframework.dispatcher; + +public interface DllDispatcherManagerInterface { + + /** + * Execute a request on a registered service. + * + * @param serviceName name of the RequestProcessor to process the request on. Must match a name of a RequestProcessor {@link #register(String name, RequestProcessor listener) registered} with the DispatcherManager. + * @param correlationId correlationId passed on to RequestProcessor. May be used to track processing of the message throug the business chain. + * @param message main message passed on to RequestProcessor. + * @return result of RequestProcessor + */ + public String processRequest(String serviceName, String correlationId, String requestMessage); + + /** + * Returns a comma separated list of all available services. + * + * @return available services + */ + public String getServices(); +}