KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > proxy > ejb > RetryInterceptor


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.proxy.ejb;
23
24 import java.io.ObjectOutput JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.ObjectInput JavaDoc;
27 import java.util.Hashtable JavaDoc;
28 import java.util.Properties JavaDoc;
29 import javax.naming.InitialContext JavaDoc;
30
31 import org.jboss.invocation.Invocation;
32 import org.jboss.invocation.InvocationContext;
33 import org.jboss.invocation.InvocationType;
34 import org.jboss.invocation.InvocationKey;
35 import org.jboss.invocation.Invoker;
36 import org.jboss.invocation.ServiceUnavailableException;
37 import org.jboss.logging.Logger;
38 import org.jboss.naming.NamingContextFactory;
39 import org.jboss.proxy.Interceptor;
40
41 /** An interceptor that will retry failed invocations by restoring the
42  * InvocationContext invoker. This is triggered by a ServiceUnavailableException
43  * which causes the interceptor to fall into a while loop that retries the
44  * lookup of the transport invoker using the jndi name obtained from the
45  * invocation context under the key InvocationKey.JNDI_NAME, with the additional
46  * extension of "-RemoteInvoker" if the invocation type is InvocationType.REMOTE
47  * and "-HomeInvoker" if the invocation type is InvocationType.HOME.
48  *
49  * The JNDI environment used for the lookup can be set via the setRetryEnv.
50  * Typically this is an HA-JNDI configuration with one or more bootstrap
51  * urls. If not set, an attempt will be made to use
52  * {@link NamingContextFactory#getInitialContext(Hashtable)} to find the
53  * JNDI environment. This will only be useful if java.naming.factory.initial
54  * was set to org.jboss.naming.NamingContextFactory. If neither of the above
55  * steps yield a set of naming environment properties, a default InitialContext
56  * will be used.
57  *
58  * @author Scott.Stark@jboss.org
59  * @author brian.stansberry@jboss.org
60  *
61  * @version $Revision: 40735 $
62  */

63 public class RetryInterceptor extends Interceptor
64 {
65    /** Serial Version Identifier. @since 1.0 */
66    private static final long serialVersionUID = 1;
67    /** The current externalized data version */
68    private static final int EXTERNAL_VERSION = 1;
69    private static Logger log = Logger.getLogger(RetryInterceptor.class);
70    /** The HA-JNDI environment used to restore the invoker proxy */
71    private static Properties JavaDoc retryEnv;
72
73    /** A flag that can be set to abort the retry loop */
74    private transient boolean retry;
75    /** The logging trace flag */
76    private transient boolean trace;
77    /** Max number of retries. -1 means retry until sucessful */
78    private transient int maxRetries = -1;
79    /** Number of ms to sleep before each attempt to reestablish the invoker */
80    private transient long sleepTime = 1000;
81
82    /**
83     * Set the HA-JNDI InitialContext env used to lookup the invoker proxy
84     * @param env the InitialContext env used to lookup the invoker proxy
85     */

86    public static void setRetryEnv(Properties JavaDoc env)
87    {
88       retryEnv = env;
89    }
90
91    /**
92     * No-argument constructor for externalization.
93     */

94    public RetryInterceptor()
95    {}
96    
97    /**
98     * Create a new RetryInterceptor that will retry the specified
99     * number of times.
100     *
101     * @param maxRetries the maximum number of retries to attempt. -1
102     * (the default) means retry until successful.
103     * @param sleepTime number of ms to pause between each retry attempt
104     */

105    protected RetryInterceptor(int maxRetries, long sleepTime)
106    {
107       this.maxRetries = maxRetries;
108       this.sleepTime = sleepTime;
109    }
110    
111    // Public --------------------------------------------------------
112

113    public void setRetry(boolean flag)
114    {
115       this.retry = flag;
116    }
117    public boolean getRetry()
118    {
119       return this.retry;
120    }
121
122    /**
123     * Gets the maximum number of retries that will be attempted.
124     */

125    public int getMaxRetries()
126    {
127       return maxRetries;
128    }
129
130    /**
131     * Sets the maximum number of retries that will be attempted.
132     *
133     * @param maxRetries the maximum number of retries to attempt. -1
134     * (the default) means retry until successful.
135     */

136    public void setMaxRetries(int maxRetries)
137    {
138       this.maxRetries = maxRetries;
139    }
140    
141    /**
142     * Gets the number of ms of sleep between each retry attempt.
143     */

144    public long getSleepTime()
145    {
146       return sleepTime;
147    }
148    
149    /**
150     * Sets the number of ms of sleep between each retry attempt.
151     */

152    public void setSleepTime(long sleepTime)
153    {
154       this.sleepTime = sleepTime;
155    }
156
157    /**
158     * InvocationHandler implementation.
159     *
160     * @throws Throwable Any exception or error thrown while processing.
161     */

162    public Object JavaDoc invoke(Invocation invocation)
163       throws Throwable JavaDoc
164    {
165       Object JavaDoc result = null;
166       InvocationContext ctx = invocation.getInvocationContext();
167       retry = true;
168       int retryCount = 0;
169       while( retry == true )
170       {
171          Interceptor next = getNext();
172          try
173          {
174             if( trace )
175                log.trace("invoke, method="+invocation.getMethod());
176             result = next.invoke(invocation);
177             break;
178          }
179          catch(ServiceUnavailableException e)
180          {
181             if( trace )
182                log.trace("Invocation failed", e);
183             
184             InvocationType type = invocation.getType();
185             if ((maxRetries > -1 && retryCount >= maxRetries)
186                   || reestablishInvokerProxy(ctx, type) == false)
187             {
188                throw e;
189             }
190             retryCount++;
191          }
192       }
193       return result;
194    }
195
196    /**
197     * Loop trying to lookup the proxy invoker from jndi. Continue trying until
198     * successful or {@link #getMaxRetries() maxRetries} attempts have been made
199     * without success. This sleeps 1 second between lookup operations.
200     *
201     * @param ctx - the invocation context to populate with the new invoker
202     * @param type - the type of the invocation, InvocationType.REMOTE or
203     * InvocationType.HOME
204     *
205     * @return <code>true</code> if a lookup was successful, <code>false</code>
206     * if {@link #getMaxRetries() maxRetries} attempts were made
207     * without success.
208     */

209    private boolean reestablishInvokerProxy(InvocationContext ctx, InvocationType type)
210    {
211       if( trace )
212          log.trace("Begin reestablishInvokerProxy");
213       
214       boolean isRemote = type == InvocationType.REMOTE;
215       String JavaDoc jndiName = (String JavaDoc) ctx.getValue(InvocationKey.JNDI_NAME);
216       if( isRemote == true )
217          jndiName += "-RemoteInvoker";
218       else
219          jndiName += "-HomeInvoker";
220       Hashtable JavaDoc retryProps = retryEnv;
221       if (retryProps == null)
222       {
223          retryProps = (Hashtable JavaDoc) NamingContextFactory.lastInitialContextEnv.get();
224          if ( trace )
225          {
226             if (retryProps != null)
227                log.trace("Using retry properties from NamingContextFactory");
228             else
229                log.trace("No retry properties available");
230          }
231       }
232       else if ( trace )
233       {
234          log.trace("Using static retry properties");
235       }
236       
237       int retryCount = 0;
238       Invoker newInvoker = null;
239       while( retry == true )
240       {
241          try
242          {
243             Thread.sleep(sleepTime);
244             InitialContext JavaDoc namingCtx = new InitialContext JavaDoc(retryProps);
245             if( trace )
246                log.trace("Looking for invoker: "+jndiName);
247             newInvoker = (Invoker) namingCtx.lookup(jndiName);
248             if( trace )
249                log.trace("Found invoker: "+newInvoker);
250             ctx.setInvoker(newInvoker);
251             break;
252          }
253          catch(Throwable JavaDoc t)
254          {
255             retryCount++;
256             if( trace )
257                log.trace("Retry attempt " + retryCount +
258                          ": Failed to lookup proxy", t);
259             if (maxRetries > -1 && retryCount >= maxRetries)
260             {
261                if ( trace)
262                   log.trace("Maximum retry attempts made");
263                break;
264             }
265          }
266       }
267       if( trace )
268          log.trace("End reestablishInvokerProxy");
269       
270       return (newInvoker != null);
271    }
272
273    /**
274     * Writes the next interceptor.
275     */

276    public void writeExternal(final ObjectOutput JavaDoc out)
277       throws IOException JavaDoc
278    {
279       super.writeExternal(out);
280       // Write out a version identifier for future extensibility
281
out.writeInt(EXTERNAL_VERSION);
282       // There is no additional data currently
283
}
284
285    /**
286     * Reads the next interceptor.
287     */

288    public void readExternal(final ObjectInput JavaDoc in)
289       throws IOException JavaDoc, ClassNotFoundException JavaDoc
290    {
291       super.readExternal(in);
292       // Read the version identifier
293
int version = in.readInt();
294       if( version == EXTERNAL_VERSION )
295       {
296          // This version has no additional data
297
}
298       // Set the logging trace level
299
trace = log.isTraceEnabled();
300    }
301 }
302
Popular Tags