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