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.unified.server;
023:
024: import javax.management.MBeanServer;
025: import javax.management.ObjectName;
026: import org.jboss.invocation.Invocation;
027: import org.jboss.invocation.unified.interfaces.UnifiedInvokerProxy;
028: import org.jboss.mx.util.JMXExceptionDecoder;
029: import org.jboss.remoting.InvocationRequest;
030: import org.jboss.remoting.InvokerLocator;
031: import org.jboss.remoting.ServerInvocationHandler;
032: import org.jboss.remoting.ServerInvoker;
033: import org.jboss.remoting.serialization.SerializationStreamFactory;
034: import org.jboss.remoting.callback.InvokerCallbackHandler;
035: import org.jboss.remoting.transport.ConnectorMBean;
036: import org.jboss.system.Registry;
037: import org.jboss.system.ServiceMBeanSupport;
038:
039: /**
040: * This is a detached invoker which sits on top of jboss remoting.
041: * Since this uses remoting, the transport protocol used is defined within
042: * the remoting service and this, the UnifiedInvoker, is declared as the handler.
043: *
044: * @author <a href="mailto:tom.elrod@jboss.com">Tom Elrod</a>
045: */
046: public class UnifiedInvoker extends ServiceMBeanSupport implements
047: ServerInvocationHandler, UnifiedInvokerMBean {
048:
049: private ConnectorMBean connector;
050: private ServerInvoker serverInvoker;
051:
052: private MBeanServer mbServer;
053:
054: private boolean strictRMIException = false;
055:
056: private UnifiedInvokerProxy proxy;
057:
058: private String subsystem = "invoker";
059:
060: /**
061: * If set to true, this will cause the UnifiedInvokerProxy (on the client side) to
062: * wrap all RemoteExceptions thrown from the server in a new ServerException. If false,
063: * will unwrap the original exception thrown from withint the RemoteException and throw that.
064: * The default is false.
065: *
066: * @param isStrict
067: */
068: public void setStrictRMIException(boolean isStrict) {
069: this .strictRMIException = isStrict;
070: }
071:
072: /**
073: * A return of true means that the UnifiedInvokerProxy (on the client side) will wrap all
074: * RemoteExceptions within a new ServerException. A return of false, will unwrap the original
075: * exception thrown from within the RemoteException and throw that. The default, if not explicitly set,
076: * is false.
077: *
078: * @return
079: */
080: public boolean getStrictRMIException() {
081: return strictRMIException;
082: }
083:
084: public String getSubSystem() {
085: return subsystem;
086: }
087:
088: /**
089: * Sets the remoting subsystem
090: * @param subsystem
091: */
092: public void setSubSystem(String subsystem) {
093: this .subsystem = subsystem;
094: }
095:
096: /**
097: * This may be called if set depends in config with optional-attribute-name.
098: *
099: * @param connector
100: */
101: public void setConnector(ConnectorMBean connector) {
102: this .connector = connector;
103: }
104:
105: protected void createService() throws Exception {
106: if (connector != null) {
107: try {
108: connector.addInvocationHandler(getSubSystem(), this );
109: } catch (Exception e) {
110: log
111: .error(
112: "Error adding unified invoker as handler upon connector being set.",
113: e);
114: }
115: }
116: }
117:
118: /**
119: * Will get the invoker locator from the server invoker, start the server invoker, create the proxy,
120: * and bind the proxy.
121: *
122: * @throws Exception
123: */
124: protected void startService() throws Exception {
125: log.debug("Starting unified invoker service.");
126:
127: InvokerLocator locator = null;
128: if (serverInvoker != null) {
129: locator = serverInvoker.getLocator();
130: if (!serverInvoker.isStarted()) {
131: serverInvoker.start();
132: }
133: } else if (connector != null) {
134: locator = connector.getLocator();
135: } else {
136: /**
137: * This will happen in one of two scenarios. One, the unified invoker was not declared in as
138: * service before the connector AND was not specified as the handler within the connector config.
139: * Two, the unified invoker service config did not use the proxy-type attribute within the depends
140: * tag to have the container set the connector upon creating the unified invoker.
141: */
142: log
143: .error("Error referencing either remoting connector or server invoker to be used. "
144: + "Please check configuration to make sure proper dependancies are set.");
145: throw new RuntimeException(
146: "Error getting locator because server invoker is null.");
147: }
148:
149: proxy = new UnifiedInvokerProxy(locator, strictRMIException);
150:
151: jmxBind();
152:
153: }
154:
155: protected void jmxBind() {
156: Registry.bind(getServiceName(), proxy);
157: }
158:
159: /**
160: * Stops the server invoker.
161: *
162: * @throws Exception
163: */
164: public void stopService() throws Exception {
165: if (serverInvoker != null) {
166: serverInvoker.stop();
167: }
168: }
169:
170: /**
171: * Gives this JMX service a name.
172: *
173: * @return The Name value
174: */
175: public String getName() {
176: return "Unified-Invoker";
177: }
178:
179: /**
180: * Gets the invoker locator string for this server
181: *
182: * @return
183: */
184: public String getInvokerLocator() {
185: if (serverInvoker != null) {
186: return serverInvoker.getLocator().getLocatorURI();
187: } else {
188: return null;
189: }
190: }
191:
192: /**
193: * Implementation of the server invoker handler interface. Will take the invocation request
194: * and invoke down the interceptor chain.
195: *
196: * @param invocationReq
197: * @return
198: * @throws Throwable
199: */
200: public Object invoke(InvocationRequest invocationReq)
201: throws Throwable {
202: Invocation invocation = (Invocation) invocationReq
203: .getParameter();
204: Thread currentThread = Thread.currentThread();
205: ClassLoader oldCl = currentThread.getContextClassLoader();
206: ObjectName mbean = null;
207: try {
208: mbean = (ObjectName) Registry.lookup(invocation
209: .getObjectName());
210:
211: // The cl on the thread should be set in another interceptor
212: Object obj = getServer().invoke(mbean, "invoke",
213: new Object[] { invocation },
214: Invocation.INVOKE_SIGNATURE);
215: return SerializationStreamFactory.getManagerInstance(
216: serverInvoker.getLocator().findSerializationType())
217: .createdMarshalledValue(obj);
218: } catch (Exception e) {
219: Throwable th = JMXExceptionDecoder.decode(e);
220: if (log.isTraceEnabled()) {
221: log.trace("Failed to invoke on mbean: " + mbean, th);
222: }
223:
224: if (th instanceof Exception) {
225: e = (Exception) th;
226: }
227:
228: throw e;
229: } finally {
230: currentThread.setContextClassLoader(oldCl);
231: Thread.interrupted(); // clear interruption because this thread may be pooled.
232: }
233:
234: }
235:
236: /**
237: * set the mbean server that the handler can reference
238: *
239: * @param server
240: */
241: public void setMBeanServer(MBeanServer server) {
242: mbServer = server;
243: }
244:
245: public MBeanServer getServer() {
246: return mbServer;
247: }
248:
249: /**
250: * set the invoker that owns this handler
251: *
252: * @param invoker
253: */
254: public void setInvoker(ServerInvoker invoker) {
255: /**
256: * This is needed in case we need to make calls on the server invoker (for classloading
257: * in particular). Will just leave alone for now and come back to this when have
258: * a use to call on it.
259: */
260: serverInvoker = invoker;
261: }
262:
263: protected ServerInvoker getInvoker() {
264: return serverInvoker;
265: }
266:
267: /**
268: * Adds a callback handler that will listen for callbacks from
269: * the server invoker handler.
270: * This is a no op as don't expect the detached invokers to have callbacks
271: *
272: * @param callbackHandler
273: */
274: public void addListener(InvokerCallbackHandler callbackHandler) {
275: //NO OP - do not expect the detached invoker to have callbacks
276: }
277:
278: /**
279: * Removes the callback handler that was listening for callbacks
280: * from the server invoker handler.
281: * This is a no op as don't expect the detached invokers to have callbacks
282: *
283: * @param callbackHandler
284: */
285: public void removeListener(InvokerCallbackHandler callbackHandler) {
286: //NO OP - do not expect the detached invoker to have callbacks
287: }
288:
289: }
|