001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.invocation.jrmp.server;
023:
024: import java.util.ArrayList;
025: import java.util.Iterator;
026: import java.util.Map;
027: import java.util.HashMap;
028: import java.lang.reflect.Method;
029: import javax.management.ObjectName;
030: import javax.naming.InitialContext;
031:
032: import org.jboss.invocation.InvokerInterceptor;
033: import org.jboss.invocation.Invocation;
034: import org.jboss.invocation.MarshalledInvocation;
035: import org.jboss.util.naming.Util;
036: import org.jboss.proxy.ClientMethodInterceptor;
037: import org.jboss.proxy.GenericProxyFactory;
038: import org.jboss.system.Registry;
039: import org.jboss.system.ServiceMBeanSupport;
040: import org.jboss.metadata.MetaData;
041: import org.w3c.dom.Element;
042:
043: /** Create an interface proxy that uses RMI/JRMP to communicate with the server
044: * side object that exposes the corresponding JMX invoke operation. Requests
045: * make through the proxy are sent to the JRMPInvoker instance the proxy
046: * is bound to.
047: *
048: * @author Scott.Stark@jboss.org
049: * @version $Revision: 57209 $
050: */
051: public class JRMPProxyFactory extends ServiceMBeanSupport implements
052: JRMPProxyFactoryMBean {
053: /** The server side JRMPInvoker mbean that will handle RMI/JRMP transport */
054: private ObjectName invokerName;
055: /** The server side mbean that exposes the invoke operation for the
056: exported interface */
057: private ObjectName targetName;
058: /** The Proxy object which uses the proxy as its handler */
059: protected Object theProxy;
060: /** The JNDI name under which the proxy will be bound */
061: private String jndiName;
062: /** The interface that the proxy implements */
063: private Class[] exportedInterfaces;
064: /** The optional definition */
065: private Element interceptorConfig;
066: /** The interceptor Classes defined in the interceptorConfig */
067: private ArrayList interceptorClasses = new ArrayList();
068: /** invoke target method */
069: private boolean invokeTargetMethod;
070: /** methods by their hash code */
071: private final Map methodMap = new HashMap();
072: /** signatures by method */
073: private final Map signatureMap = new HashMap();
074:
075: public JRMPProxyFactory() {
076: interceptorClasses.add(ClientMethodInterceptor.class);
077: interceptorClasses.add(InvokerInterceptor.class);
078: }
079:
080: public ObjectName getInvokerName() {
081: return invokerName;
082: }
083:
084: public void setInvokerName(ObjectName invokerName) {
085: this .invokerName = invokerName;
086: }
087:
088: public ObjectName getTargetName() {
089: return targetName;
090: }
091:
092: public void setTargetName(ObjectName targetName) {
093: this .targetName = targetName;
094: }
095:
096: public String getJndiName() {
097: return jndiName;
098: }
099:
100: public void setJndiName(String jndiName) {
101: this .jndiName = jndiName;
102: }
103:
104: public Class getExportedInterface() {
105: return exportedInterfaces[0];
106: }
107:
108: public void setExportedInterface(Class exportedInterface) {
109: this .exportedInterfaces = new Class[] { exportedInterface };
110: }
111:
112: public Class[] getExportedInterfaces() {
113: return exportedInterfaces;
114: }
115:
116: public void setExportedInterfaces(Class[] exportedInterfaces) {
117: this .exportedInterfaces = exportedInterfaces;
118: }
119:
120: public boolean getInvokeTargetMethod() {
121: return invokeTargetMethod;
122: }
123:
124: public void setInvokeTargetMethod(boolean invokeTargetMethod) {
125: this .invokeTargetMethod = invokeTargetMethod;
126: }
127:
128: public Element getClientInterceptors() {
129: return interceptorConfig;
130: }
131:
132: public void setClientInterceptors(Element config) throws Exception {
133: this .interceptorConfig = config;
134: Iterator interceptorElements = MetaData.getChildrenByTagName(
135: interceptorConfig, "interceptor");
136: ClassLoader loader = Thread.currentThread()
137: .getContextClassLoader();
138: interceptorClasses.clear();
139: while (interceptorElements != null
140: && interceptorElements.hasNext()) {
141: Element ielement = (Element) interceptorElements.next();
142: String className = null;
143: className = MetaData.getElementContent(ielement);
144: Class clazz = loader.loadClass(className);
145: interceptorClasses.add(clazz);
146: log.debug("added interceptor type: " + clazz);
147: }
148: }
149:
150: public Object getProxy() {
151: return theProxy;
152: }
153:
154: public Object invoke(Invocation mi) throws Exception {
155: final boolean remoteInvocation = mi instanceof MarshalledInvocation;
156: if (remoteInvocation) {
157: ((MarshalledInvocation) mi).setMethodMap(methodMap);
158: }
159:
160: final Object result;
161: if (invokeTargetMethod) {
162: String signature[] = (String[]) signatureMap.get(mi
163: .getMethod());
164: result = server.invoke(targetName,
165: mi.getMethod().getName(), mi.getArguments(),
166: signature);
167: } else {
168: result = server.invoke(targetName, "invoke",
169: new Object[] { mi }, Invocation.INVOKE_SIGNATURE);
170: }
171:
172: return result;
173: }
174:
175: /** Initializes the servlet.
176: */
177: protected void startService() throws Exception {
178: /* Create a binding between the invoker name hash and the jmx name
179: This is used by the JRMPInvoker to map from the Invocation ObjectName
180: hash value to the target JMX ObjectName.
181: */
182: Integer nameHash = new Integer(getServiceName().hashCode());
183: Registry.bind(nameHash, getServiceName());
184:
185: // Create the service proxy
186: Object cacheID = null;
187: String proxyBindingName = null;
188: Class[] ifaces = exportedInterfaces;
189: ClassLoader loader = Thread.currentThread()
190: .getContextClassLoader();
191: createProxy(cacheID, proxyBindingName, loader, ifaces);
192: log
193: .debug("Created JRMPPRoxy for service=" + targetName
194: + ", nameHash=" + nameHash + ", invoker="
195: + invokerName);
196:
197: if (jndiName != null) {
198: InitialContext iniCtx = new InitialContext();
199: Util.bind(iniCtx, jndiName, theProxy);
200: log.debug("Bound proxy under jndiName=" + jndiName);
201: }
202:
203: for (int i = 0; i < exportedInterfaces.length; ++i) {
204: final Method[] methods = exportedInterfaces[i].getMethods();
205: for (int j = 0; j < methods.length; ++j) {
206: methodMap.put(new Long(MarshalledInvocation
207: .calculateHash(methods[j])), methods[j]);
208:
209: String signature[];
210: final Class[] types = methods[j].getParameterTypes();
211: if (types == null || types.length == 0) {
212: signature = null;
213: } else {
214: signature = new String[types.length];
215: for (int typeInd = 0; typeInd < types.length; ++typeInd) {
216: signature[typeInd] = types[typeInd].getName();
217: }
218: }
219: signatureMap.put(methods[j], signature);
220: }
221: }
222: }
223:
224: protected void stopService() throws Exception {
225: Integer nameHash = new Integer(getServiceName().hashCode());
226: Registry.unbind(nameHash);
227: if (jndiName != null) {
228: InitialContext iniCtx = new InitialContext();
229: Util.unbind(iniCtx, jndiName);
230: }
231: this .theProxy = null;
232: }
233:
234: protected void destroyService() throws Exception {
235: interceptorClasses.clear();
236: }
237:
238: protected void createProxy(Object cacheID, String proxyBindingName,
239: ClassLoader loader, Class[] ifaces) {
240: GenericProxyFactory proxyFactory = new GenericProxyFactory();
241: theProxy = proxyFactory.createProxy(cacheID, getServiceName(),
242: invokerName, jndiName, proxyBindingName,
243: interceptorClasses, loader, ifaces);
244: }
245:
246: protected void rebind() throws Exception {
247: log.debug("(re-)Binding " + jndiName);
248: Util.rebind(new InitialContext(), jndiName, theProxy);
249: }
250:
251: protected ArrayList getInterceptorClasses() {
252: return interceptorClasses;
253: }
254: }
|