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.proxy.ejb;
023:
024: import java.security.Principal;
025: import java.util.Map;
026: import javax.management.MBeanException;
027: import javax.management.MBeanServer;
028: import javax.management.ObjectName;
029: import javax.transaction.Transaction;
030:
031: import org.omg.CORBA.BAD_OPERATION;
032: import org.omg.CORBA.InterfaceDef;
033: import org.omg.CORBA.ORBPackage.InvalidName;
034: import org.omg.CORBA.portable.InvokeHandler;
035: import org.omg.CORBA.portable.InputStream;
036: import org.omg.CORBA.portable.OutputStream;
037: import org.omg.CORBA.portable.ResponseHandler;
038: import org.omg.CORBA.portable.UnknownException;
039: import org.omg.PortableServer.Current;
040: import org.omg.PortableServer.POA;
041: import org.omg.CSI.IdentityToken;
042:
043: import org.jboss.iiop.CorbaORB;
044: import org.jboss.iiop.csiv2.SASCurrent;
045: import org.jboss.iiop.rmi.RmiIdlUtil;
046: import org.jboss.iiop.rmi.marshal.strategy.SkeletonStrategy;
047: import org.jboss.invocation.Invocation;
048: import org.jboss.invocation.InvocationKey;
049: import org.jboss.invocation.InvocationType;
050: import org.jboss.invocation.PayloadKey;
051: import org.jboss.invocation.iiop.ReferenceData;
052: import org.jboss.invocation.iiop.ServantWithMBeanServer;
053: import org.jboss.logging.Logger;
054: import org.jboss.tm.iiop.TxServerInterceptor;
055: import org.jboss.security.SimplePrincipal;
056:
057: /**
058: * CORBA servant class for the <code>EJBObject</code>s of a given bean. An
059: * instance of this class "implements" the bean's set of <code>EJBObject</code>
060: * instances by forwarding to the bean container all IIOP invocations on any
061: * of the bean's <code>EJBObject</code>s. Such invocations are routed through
062: * the JBoss <code>MBean</code> server, which delivers them to the target
063: * container.
064: *
065: * @author <a href="mailto:reverbel@ime.usp.br">Francisco Reverbel</a>
066: * @version $Revision: 57194 $
067: */
068: public class EjbObjectCorbaServant extends ServantWithMBeanServer
069: implements InvokeHandler, LocalIIOPInvoker {
070:
071: /**
072: * The <code>MBean</code> name of this servant's container.
073: */
074: private final ObjectName containerName;
075:
076: /**
077: * The classloader of this servant's container.
078: */
079: private final ClassLoader containerClassLoader;
080:
081: /**
082: * Thread-local <code>Current</code> object from which we get the target oid
083: * in an incoming IIOP request.
084: */
085: private final Current poaCurrent;
086:
087: /**
088: * Mapping from bean methods to <code>SkeletonStrategy</code> instances.
089: */
090: private final Map methodInvokerMap;
091:
092: /**
093: * CORBA repository ids of the RMI-IDL interfaces implemented by the bean
094: * (<code>EJBObject</code> instance).
095: */
096: private final String[] repositoryIds;
097:
098: /**
099: * CORBA reference to an IR object representing the bean's remote interface.
100: */
101: private final InterfaceDef interfaceDef;
102:
103: /**
104: * This servant's logger.
105: */
106: private final Logger logger;
107:
108: /**
109: * True is the trace logging level is enabled.
110: */
111: private final boolean traceEnabled;
112:
113: /**
114: * A reference to the JBoss <code>MBean</code> server.
115: */
116: private MBeanServer mbeanServer;
117:
118: /**
119: * A reference to the SASCurrent, or null if the SAS interceptors are not
120: * installed.
121: */
122: private SASCurrent sasCurrent;
123:
124: /**
125: * Constructs an <code>EjbObjectCorbaServant></code>.
126: */
127: public EjbObjectCorbaServant(ObjectName containerName,
128: ClassLoader containerClassLoader, Current poaCurrent,
129: Map methodInvokerMap, String[] repositoryIds,
130: InterfaceDef interfaceDef, Logger logger) {
131: this .containerName = containerName;
132: this .containerClassLoader = containerClassLoader;
133: this .poaCurrent = poaCurrent;
134: this .methodInvokerMap = methodInvokerMap;
135: this .repositoryIds = repositoryIds;
136: this .interfaceDef = interfaceDef;
137: this .logger = logger;
138: this .traceEnabled = logger.isTraceEnabled();
139: try {
140: this .sasCurrent = (SASCurrent) CorbaORB.getInstance()
141: .resolve_initial_references("SASCurrent");
142: } catch (InvalidName invalidName) {
143: this .sasCurrent = null;
144: }
145: }
146:
147: // Implementation of method declared as abstract in the superclass ------
148:
149: /**
150: * Sets this servant's <code>MBeanServer</code>.
151: */
152: public void setMBeanServer(MBeanServer mbeanServer) {
153: this .mbeanServer = mbeanServer;
154: }
155:
156: // This method overrides the one in org.omg.PortableServer.Servant ------
157:
158: /**
159: * Returns an IR object describing the bean's remote interface.
160: */
161: public org.omg.CORBA.Object _get_interface_def() {
162: if (interfaceDef != null)
163: return interfaceDef;
164: else
165: return super ._get_interface_def();
166: }
167:
168: // Implementation of org.omg.CORBA.portable.InvokeHandler ---------------
169:
170: /**
171: * Returns an array with the CORBA repository ids of the RMI-IDL interfaces
172: * implemented by this servant's <code>EJBObject</code>s.
173: */
174: public String[] _all_interfaces(POA poa, byte[] objectId) {
175: return (String[]) repositoryIds.clone();
176: }
177:
178: /**
179: * Receives IIOP requests to this servant's <code>EJBObject</code>s
180: * and forwards them to the bean container, through the JBoss
181: * <code>MBean</code> server.
182: */
183: public OutputStream _invoke(String opName, InputStream in,
184: ResponseHandler handler) {
185:
186: if (traceEnabled) {
187: logger.trace("EJBObject invocation: " + opName);
188: }
189:
190: ClassLoader oldCl = Thread.currentThread()
191: .getContextClassLoader();
192: Thread.currentThread().setContextClassLoader(
193: containerClassLoader);
194: try {
195: SkeletonStrategy op = (SkeletonStrategy) methodInvokerMap
196: .get(opName);
197: if (op == null) {
198: logger.debug("Unable to find opname '" + opName
199: + "' valid operations:"
200: + methodInvokerMap.keySet());
201: throw new BAD_OPERATION(opName);
202: }
203:
204: Object id;
205: try {
206: id = ReferenceData.extractObjectId(poaCurrent
207: .get_object_id());
208: if (traceEnabled && id != null)
209: logger.trace(" id class is "
210: + id.getClass().getName());
211: } catch (Exception e) {
212: logger.error("Error getting EJBObject id", e);
213: throw new UnknownException(e);
214: }
215:
216: org.omg.CORBA_2_3.portable.OutputStream out;
217: try {
218: Object retVal;
219:
220: if (opName.equals("_get_handle")) {
221: retVal = new HandleImplIIOP(_this _object());
222: } else {
223: Transaction tx = TxServerInterceptor
224: .getCurrentTransaction();
225: SimplePrincipal principal = null;
226: char[] password = null;
227: if (sasCurrent != null) {
228: byte[] username = sasCurrent
229: .get_incoming_username();
230: byte[] credential = sasCurrent
231: .get_incoming_password();
232: String name = new String(username, "UTF-8");
233: int domainIndex = name.indexOf('@');
234: if (domainIndex > 0)
235: name = name.substring(0, domainIndex);
236: if (name.length() == 0) {
237: byte[] incomingName = sasCurrent
238: .get_incoming_principal_name();
239: if (incomingName.length > 0) {
240: name = new String(incomingName, "UTF-8");
241: domainIndex = name.indexOf('@');
242: if (domainIndex > 0)
243: name = name.substring(0,
244: domainIndex);
245: principal = new SimplePrincipal(name);
246: // username==password is a hack until
247: // we have a real way to establish trust
248: password = name.toCharArray();
249: }
250: } else {
251: principal = new SimplePrincipal(name);
252: password = new String(credential, "UTF-8")
253: .toCharArray();
254: }
255:
256: }
257: Object[] params = op
258: .readParams((org.omg.CORBA_2_3.portable.InputStream) in);
259: Invocation inv = new Invocation(id, op.getMethod(),
260: params, tx, principal, /* identity */
261: password /* credential */);
262: inv.setValue(InvocationKey.INVOKER_PROXY_BINDING,
263: "iiop", PayloadKey.AS_IS);
264: inv.setType(InvocationType.REMOTE);
265: retVal = mbeanServer.invoke(containerName,
266: "invoke", new Object[] { inv },
267: Invocation.INVOKE_SIGNATURE);
268:
269: }
270: out = (org.omg.CORBA_2_3.portable.OutputStream) handler
271: .createReply();
272: if (op.isNonVoid()) {
273: op.writeRetval(out, retVal);
274: }
275: } catch (Exception e) {
276: if (traceEnabled) {
277: logger
278: .trace("Exception in EJBObject invocation",
279: e);
280: }
281: if (e instanceof MBeanException) {
282: e = ((MBeanException) e).getTargetException();
283: }
284: RmiIdlUtil.rethrowIfCorbaSystemException(e);
285: out = (org.omg.CORBA_2_3.portable.OutputStream) handler
286: .createExceptionReply();
287: op.writeException(out, e);
288: }
289: return out;
290: } finally {
291: Thread.currentThread().setContextClassLoader(oldCl);
292: }
293: }
294:
295: // Implementation of the interface LocalIIOPInvoker ------------------------
296:
297: /**
298: * Receives intra-VM invocations on this servant's <code>EJBObject</code>s
299: * and forwards them to the bean container, through the JBoss
300: * <code>MBean</code>
301: * server.
302: */
303: public Object invoke(String opName, Object[] arguments,
304: Transaction tx, Principal identity, Object credential)
305: throws Exception {
306: if (traceEnabled) {
307: logger.trace("EJBObject local invocation: " + opName);
308: }
309:
310: ClassLoader oldCl = Thread.currentThread()
311: .getContextClassLoader();
312: Thread.currentThread().setContextClassLoader(
313: containerClassLoader);
314:
315: try {
316: SkeletonStrategy op = (SkeletonStrategy) methodInvokerMap
317: .get(opName);
318: if (op == null) {
319: throw new BAD_OPERATION(opName);
320: }
321:
322: Object id;
323: try {
324: id = ReferenceData.extractObjectId(poaCurrent
325: .get_object_id());
326: if (traceEnabled && id != null) {
327: logger.trace(" id class is "
328: + id.getClass().getName());
329: }
330: } catch (Exception e) {
331: logger.error("Error getting EJBObject id", e);
332: throw new UnknownException(e);
333: }
334:
335: Invocation inv = new Invocation(id, op.getMethod(),
336: arguments, tx, null, /* identity */
337: null /* credential */);
338: inv.setValue(InvocationKey.INVOKER_PROXY_BINDING, "iiop",
339: PayloadKey.AS_IS);
340: inv.setType(InvocationType.REMOTE);
341: return mbeanServer.invoke(containerName, "invoke",
342: new Object[] { inv }, Invocation.INVOKE_SIGNATURE);
343: } catch (MBeanException e) {
344: throw e.getTargetException();
345: } finally {
346: Thread.currentThread().setContextClassLoader(oldCl);
347: }
348: }
349:
350: }
|