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.rmi.MarshalledObject;
025:
026: import javax.management.ObjectName;
027: import javax.management.InstanceNotFoundException;
028: import javax.management.ReflectionException;
029:
030: import org.jboss.invocation.jrmp.interfaces.JRMPInvokerProxyHA;
031: import org.jboss.invocation.Invocation;
032: import org.jboss.invocation.Invoker;
033: import org.jboss.invocation.InvokerHA;
034: import org.jboss.invocation.MarshalledInvocation;
035: import org.jboss.system.Registry;
036:
037: import org.jboss.ha.framework.interfaces.HARMIResponse;
038: import org.jboss.ha.framework.server.HATarget;
039: import org.jboss.ha.framework.interfaces.LoadBalancePolicy;
040: import org.jboss.ha.framework.interfaces.GenericClusteringException;
041:
042: import java.util.ArrayList;
043: import java.util.HashMap;
044:
045: /**
046: * The JRMPInvokerHA is an HA-RMI implementation that can generate Invocations from RMI/JRMP
047: * into the JMX base
048: *
049: * @author <a href="mailto:bill@burkecentral.com>Bill Burke</a>
050: * @author <a href="mailto:sacha.labourey@cogito-info.ch">Sacha Labourey</a>.
051: * @author Scott.Stark@jboss.org
052: * @version $Revision: 57188 $
053: */
054: public class JRMPInvokerHA extends JRMPInvoker implements InvokerHA {
055: protected HashMap beanMap = new HashMap();
056:
057: /**
058: * Explicit no-args constructor.
059: */
060: public JRMPInvokerHA() {
061: super ();
062: }
063:
064: // JRMPInvoker.createService() does the right thing
065:
066: protected void startService() throws Exception {
067: loadCustomSocketFactories();
068:
069: if (log.isDebugEnabled()) {
070: log.debug("RMI Port='"
071: + (rmiPort == ANONYMOUS_PORT ? "Anonymous"
072: : Integer.toString(rmiPort) + "'"));
073: log.debug("Client SocketFactory='"
074: + (clientSocketFactory == null ? "Default"
075: : clientSocketFactory.toString() + "'"));
076: log.debug("Server SocketFactory='"
077: + (serverSocketFactory == null ? "Default"
078: : serverSocketFactory.toString() + "'"));
079: log.debug("Server SocketAddr='"
080: + (serverAddress == null ? "Default"
081: : serverAddress + "'"));
082: log.debug("SecurityDomain='"
083: + (sslDomain == null ? "None" : sslDomain + "'"));
084: }
085:
086: exportCI();
087: Registry.bind(support.getServiceName(), this );
088: }
089:
090: protected void stopService() throws Exception {
091: unexportCI();
092: }
093:
094: // JRMPInvoker.destroyService() does the right thing
095:
096: public void registerBean(ObjectName beanName, HATarget target)
097: throws Exception {
098: Integer hash = new Integer(beanName.hashCode());
099: log.debug("registerBean: " + beanName);
100:
101: if (beanMap.containsKey(hash)) {
102: // FIXME [oleg] In theory this is possible!
103: throw new IllegalStateException(
104: "Trying to register bean with the existing hashCode");
105: }
106: beanMap.put(hash, target);
107: }
108:
109: public Invoker createProxy(ObjectName beanName,
110: LoadBalancePolicy policy, String proxyFamilyName)
111: throws Exception {
112: Integer hash = new Integer(beanName.hashCode());
113: HATarget target = (HATarget) beanMap.get(hash);
114: if (target == null) {
115: throw new IllegalStateException(
116: "The bean hashCode not found");
117: }
118:
119: String familyName = proxyFamilyName;
120: if (familyName == null)
121: familyName = target.getAssociatedPartition()
122: .getPartitionName()
123: + "/" + beanName;
124:
125: JRMPInvokerProxyHA proxy = new JRMPInvokerProxyHA(target
126: .getReplicants(), policy, familyName, target
127: .getCurrentViewId());
128: return proxy;
129: }
130:
131: public void unregisterBean(ObjectName beanName) throws Exception {
132: Integer hash = new Integer(beanName.hashCode());
133: beanMap.remove(hash);
134: }
135:
136: /**
137: * Invoke a Remote interface method.
138: */
139: public Object invoke(Invocation invocation) throws Exception {
140: ClassLoader oldCl = Thread.currentThread()
141: .getContextClassLoader();
142:
143: try {
144: // Deserialize the transaction if it is there
145: invocation
146: .setTransaction(importTPC(((MarshalledInvocation) invocation)
147: .getTransactionPropagationContext()));
148:
149: // Extract the ObjectName, the rest is still marshalled
150: ObjectName mbean = (ObjectName) Registry.lookup(invocation
151: .getObjectName());
152: long clientViewId = ((Long) invocation
153: .getValue("CLUSTER_VIEW_ID")).longValue();
154:
155: HATarget target = (HATarget) beanMap.get(invocation
156: .getObjectName());
157: if (target == null) {
158: // We could throw IllegalStateException but we have a race condition that could occur:
159: // when we undeploy a bean, the cluster takes some time to converge
160: // and to recalculate a new viewId and list of replicant for each HATarget.
161: // Consequently, a client could own an up-to-date list of the replicants
162: // (before the cluster has converged) and try to perform an invocation
163: // on this node where the HATarget no more exist, thus receiving a
164: // wrong exception and no failover is performed with an IllegalStateException
165: //
166: throw new GenericClusteringException(
167: GenericClusteringException.COMPLETED_NO,
168: "target is not/no more registered on this node");
169: }
170:
171: if (!target.invocationsAllowed())
172: throw new GenericClusteringException(
173: GenericClusteringException.COMPLETED_NO,
174: "invocations are currently not allowed on this target");
175:
176: // The cl on the thread should be set in another interceptor
177: Object rtn = support.getServer().invoke(mbean, "invoke",
178: new Object[] { invocation },
179: Invocation.INVOKE_SIGNATURE);
180:
181: HARMIResponse rsp = new HARMIResponse();
182:
183: if (clientViewId != target.getCurrentViewId()) {
184: rsp.newReplicants = new ArrayList(target
185: .getReplicants());
186: rsp.currentViewId = target.getCurrentViewId();
187: }
188: rsp.response = rtn;
189:
190: return new MarshalledObject(rsp);
191: } catch (InstanceNotFoundException e) {
192: throw new GenericClusteringException(
193: GenericClusteringException.COMPLETED_NO, e);
194: } catch (ReflectionException e) {
195: throw new GenericClusteringException(
196: GenericClusteringException.COMPLETED_NO, e);
197: } catch (Exception e) {
198: org.jboss.mx.util.JMXExceptionDecoder.rethrow(e);
199:
200: // the compiler does not know an exception is thrown by the above
201: throw new org.jboss.util.UnreachableStatementException();
202: } finally {
203: Thread.currentThread().setContextClassLoader(oldCl);
204: }
205: }
206: }
|