KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > invocation > http > interfaces > HttpInvokerProxyHA


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.invocation.http.interfaces;
23
24 import java.io.Externalizable JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.ObjectInput JavaDoc;
27 import java.io.ObjectOutput JavaDoc;
28 import java.lang.reflect.InvocationTargetException JavaDoc;
29 import java.net.URL JavaDoc;
30 import java.rmi.ServerException JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.List JavaDoc;
33
34 import org.jboss.ha.framework.interfaces.ClusteringTargetsRepository;
35 import org.jboss.ha.framework.interfaces.GenericClusteringException;
36 import org.jboss.ha.framework.interfaces.HARMIResponse;
37 import org.jboss.ha.framework.interfaces.LoadBalancePolicy;
38 import org.jboss.ha.framework.interfaces.FamilyClusterInfo;
39 import org.jboss.invocation.Invocation;
40 import org.jboss.invocation.InvocationException;
41 import org.jboss.invocation.Invoker;
42 import org.jboss.invocation.InvokerProxyHA;
43 import org.jboss.invocation.MarshalledInvocation;
44 import org.jboss.invocation.PayloadKey;
45 import org.jboss.logging.Logger;
46
47 /** The client side Http invoker proxy that posts an invocation to the
48  InvokerServlet using the HttpURLConnection created from a target url.
49  This proxy handles failover using its associated LoadBalancePolicy and
50  current list of URL strings. The candidate URLs are updated dynamically
51  after an invocation if the cluster partitation view has changed.
52
53 * @author Scott.Stark@jboss.org
54 * @version $Revision: 56228 $
55 */

56 public class HttpInvokerProxyHA
57    implements InvokerProxyHA, Invoker, Externalizable JavaDoc
58 {
59    // Constants -----------------------------------------------------
60
private static Logger log = Logger.getLogger(HttpInvokerProxyHA.class);
61
62    /** Serial Version Identifier.
63     * @since 1.1.4.5
64     */

65    private static final long serialVersionUID = -7081220026780794383L;
66
67    // Attributes ----------------------------------------------------
68

69    // URL to the remote JMX node invoker
70
protected LoadBalancePolicy loadBalancePolicy;
71    protected String JavaDoc proxyFamilyName = null;
72    protected FamilyClusterInfo familyClusterInfo = null;
73    /** Trace level logging flag only set when the proxy is created or read from JNDI */
74    protected transient boolean trace = false;
75
76    // Constructors --------------------------------------------------
77
public HttpInvokerProxyHA()
78    {
79       // For externalization to work
80
}
81
82    /**
83     * @param targets the list of URLs through which clients should contact the
84     * InvokerServlet.
85     * @param policy the policy for choosing among targets ClusteringTargetsRepository under
86     * which this proxy is to be stored
87     * @param proxyFamilyName the name into the
88    */

89    public HttpInvokerProxyHA(List JavaDoc targets, long viewId, LoadBalancePolicy policy,
90       String JavaDoc proxyFamilyName)
91    {
92       this.familyClusterInfo = ClusteringTargetsRepository.initTarget (proxyFamilyName, targets, viewId);
93       this.loadBalancePolicy = policy;
94       this.proxyFamilyName = proxyFamilyName;
95       this.trace = log.isTraceEnabled();
96       if( trace )
97          log.trace("Init, cluterInfo: "+familyClusterInfo+", policy="+loadBalancePolicy);
98    }
99
100    // Public --------------------------------------------------------
101

102    public void updateClusterInfo (ArrayList JavaDoc targets, long viewId)
103    {
104       if (familyClusterInfo != null)
105          this.familyClusterInfo.updateClusterInfo (targets, viewId);
106    }
107
108    public String JavaDoc getServerHostName() throws Exception JavaDoc
109    {
110       return null;
111    }
112
113    public FamilyClusterInfo getClusterInfo()
114    {
115       return familyClusterInfo;
116    }
117
118    public Object JavaDoc getRemoteTarget()
119    {
120       return getRemoteTarget(null);
121    }
122    public Object JavaDoc getRemoteTarget(Invocation invocationBasedRouting)
123    {
124       Object JavaDoc target = loadBalancePolicy.chooseTarget(this.familyClusterInfo, invocationBasedRouting);
125       if( trace )
126          log.trace("Choose remoteTarget: "+target);
127       return target;
128    }
129
130    public void remoteTargetHasFailed(Object JavaDoc target)
131    {
132       removeDeadTarget(target);
133    }
134
135    protected int totalNumberOfTargets ()
136    {
137       int size = 0;
138       if( familyClusterInfo != null )
139          size = familyClusterInfo.getTargets().size();
140       return size;
141    }
142
143    protected void removeDeadTarget(Object JavaDoc target)
144    {
145       if( familyClusterInfo != null )
146       {
147          List JavaDoc targets = familyClusterInfo.removeDeadTarget(target);
148          if( trace )
149          {
150             log.trace("removeDeadTarget("+target+"), targets.size="+targets.size());
151          }
152       }
153    }
154    protected void resetView ()
155    {
156       familyClusterInfo.resetView();
157    }
158
159    /** This method builds a MarshalledInvocation from the invocation passed
160     in and then does a post to the target URL.
161    */

162    public Object JavaDoc invoke(Invocation invocation)
163       throws Exception JavaDoc
164    {
165       // we give the opportunity, to any server interceptor, to know if this a
166
// first invocation to a node or if it is a failovered call
167
//
168
int failoverCounter = 0;
169
170       // We are going to go through a Remote invocation, switch to a Marshalled Invocation
171
MarshalledInvocation mi = new MarshalledInvocation(invocation);
172       mi.setValue("CLUSTER_VIEW_ID", new Long JavaDoc(familyClusterInfo.getCurrentViewId()));
173       String JavaDoc target = (String JavaDoc) getRemoteTarget(invocation);
174       URL JavaDoc externalURL = Util.resolveURL(target);
175       Exception JavaDoc lastException = null;
176       while( externalURL != null )
177       {
178          boolean definitivlyRemoveNodeOnFailure = true;
179          invocation.setValue("FAILOVER_COUNTER", new Integer JavaDoc(failoverCounter), PayloadKey.AS_IS);
180          try
181          {
182             if( trace )
183                log.trace("Invoking on target="+externalURL);
184             Object JavaDoc rtn = Util.invoke(externalURL, mi);
185             HARMIResponse rsp = (HARMIResponse) rtn;
186
187             if (rsp.newReplicants != null)
188                updateClusterInfo(rsp.newReplicants, rsp.currentViewId);
189             return rsp.response;
190          }
191          catch(GenericClusteringException e)
192          {
193             // this is a generic clustering exception that contain the
194
// completion status: usefull to determine if we are authorized
195
// to re-issue a query to another node
196
//
197
if( e.getCompletionStatus() != e.COMPLETED_NO )
198             {
199                   // we don't want to remove the node from the list of targets
200
// UNLESS there is a risk to loop
201
if (totalNumberOfTargets() >= failoverCounter)
202                   {
203                      if( e.isDefinitive() == false )
204                         definitivlyRemoveNodeOnFailure = false;
205                   }
206             }
207             else
208             {
209                throw new ServerException JavaDoc("Cannot proceed beyond target="+externalURL, e);
210             }
211          }
212          catch(InvocationException e)
213          {
214             // Handle application declared exceptions
215
Throwable JavaDoc cause = e.getTargetException();
216             if( cause instanceof Exception JavaDoc )
217                throw (Exception JavaDoc) cause;
218             else if (cause instanceof Error JavaDoc)
219                throw (Error JavaDoc) cause;
220             throw new InvocationTargetException JavaDoc(cause);
221          }
222          catch(IOException JavaDoc e)
223          {
224             if( trace )
225                log.trace("Invoke failed, target="+externalURL, e);
226             lastException = e;
227          }
228          catch(Exception JavaDoc e)
229          {
230             // Rethrow for the application to handle
231
throw e;
232          }
233
234          // If we reach here, this means that we must fail-over
235
remoteTargetHasFailed(target);
236          if( definitivlyRemoveNodeOnFailure )
237             resetView();
238          target = (String JavaDoc) getRemoteTarget(invocation);
239          externalURL = Util.resolveURL(target);
240          failoverCounter ++;
241       }
242       // if we get here this means list was exhausted
243
throw new ServerException JavaDoc("Service unavailable last exception:", lastException);
244    }
245
246    /** Externalize this instance.
247    */

248    public void writeExternal(final ObjectOutput JavaDoc out)
249       throws IOException JavaDoc
250    {
251       // JBAS-2071 - sync on FCI to ensure targets and vid are consistent
252
List JavaDoc currentTargets = null;
253       long vid = 0;
254       synchronized (this.familyClusterInfo)
255       {
256          currentTargets = this.familyClusterInfo.getTargets ();
257          vid = this.familyClusterInfo.getCurrentViewId ();
258       }
259       out.writeObject(currentTargets);
260       out.writeLong(vid);
261       out.writeObject(this.loadBalancePolicy);
262       out.writeObject(this.proxyFamilyName);
263    }
264
265    /** Un-externalize this instance.
266    */

267    public void readExternal(final ObjectInput JavaDoc in)
268       throws IOException JavaDoc, ClassNotFoundException JavaDoc
269    {
270       List JavaDoc targets = (List JavaDoc) in.readObject();
271       long vid = in.readLong ();
272       this.loadBalancePolicy = (LoadBalancePolicy) in.readObject();
273       this.proxyFamilyName = (String JavaDoc)in.readObject();
274       this.trace = log.isTraceEnabled();
275
276       // keep a reference on our family object
277
this.familyClusterInfo = ClusteringTargetsRepository.initTarget(this.proxyFamilyName, targets, vid);
278       if( trace )
279          log.trace("Init, clusterInfo: "+familyClusterInfo+", policy="+loadBalancePolicy);
280    }
281 }
282
283
Popular Tags