KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > vlib > VirtualLibraryEngine


1 // Copyright 2004 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.tapestry.vlib;
16
17 import java.io.IOException JavaDoc;
18 import java.rmi.RemoteException JavaDoc;
19
20 import javax.ejb.CreateException JavaDoc;
21 import javax.ejb.FinderException JavaDoc;
22 import javax.servlet.ServletException JavaDoc;
23 import javax.servlet.http.HttpSession JavaDoc;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hivemind.ApplicationRuntimeException;
28 import org.apache.tapestry.IRequestCycle;
29 import org.apache.tapestry.StaleSessionException;
30 import org.apache.tapestry.engine.BaseEngine;
31 import org.apache.tapestry.form.IPropertySelectionModel;
32 import org.apache.tapestry.request.ResponseOutputStream;
33 import org.apache.tapestry.vlib.ejb.IBookQuery;
34 import org.apache.tapestry.vlib.ejb.IBookQueryHome;
35 import org.apache.tapestry.vlib.ejb.IOperations;
36 import org.apache.tapestry.vlib.ejb.IOperationsHome;
37 import org.apache.tapestry.vlib.ejb.Person;
38 import org.apache.tapestry.vlib.ejb.Publisher;
39 import org.apache.tapestry.vlib.pages.ApplicationUnavailable;
40
41 /**
42  *
43  * The engine for the Virtual Library.
44  * This exists to implement the external
45  * service, which allows the {@link org.apache.tapestry.vlib.pages.ViewBook}
46  * and {@link org.apache.tapestry.vlib.pages.ViewPerson}
47  * pages to be bookmarked, and to provide
48  * a way for shutting down the application when the user logs out.
49  *
50  *
51  * @version $Id: VirtualLibraryEngine.java,v 1.12 2004/04/30 15:17:22 hlship Exp $
52  * @author Howard Lewis Ship
53  *
54  **/

55
56 public class VirtualLibraryEngine extends BaseEngine
57 {
58     public static final Log LOG = LogFactory.getLog(VirtualLibraryEngine.class);
59
60     private static final boolean DEBUG_ENABLED =
61         Boolean.getBoolean("org.apache.tapestry.vlib.debug-enabled");
62
63     private transient boolean _killSession;
64
65     private transient IOperations _operations;
66     private transient IPropertySelectionModel _publisherModel;
67     private transient IPropertySelectionModel _personModel;
68
69     private transient String JavaDoc _applicationUnavailableMessage;
70
71     /**
72      * Removes the operations bean instance, if accessed this request cycle.
73      *
74      * <p>May invalidate the {@link HttpSession} (see {@link #logout()}).
75      **/

76
77     protected void cleanupAfterRequest(IRequestCycle cycle)
78     {
79         clearCache();
80
81         _applicationUnavailableMessage = null;
82
83         if (_killSession)
84         {
85             try
86             {
87                 HttpSession JavaDoc session = cycle.getRequestContext().getSession();
88
89                 if (session != null)
90                     session.invalidate();
91             }
92             catch (IllegalStateException JavaDoc ex)
93             {
94                 // Ignore.
95
}
96         }
97     }
98
99     /**
100      * Sets the visit property to null, and sets a flag that
101      * invalidates the {@link HttpSession} at the end of the request cycle.
102      *
103      **/

104
105     public void logout()
106     {
107         Visit visit = (Visit) getVisit();
108
109         if (visit != null)
110             visit.setUser(null);
111
112         _killSession = true;
113     }
114
115     public boolean isDebugEnabled()
116     {
117         return DEBUG_ENABLED;
118     }
119
120     /**
121      * Returns an instance of the Vlib Operations beans, which is a stateless
122      * session bean for performing certain operations.
123      *
124      * <p>The bean is automatically removed at the end of the request cycle.
125      *
126      **/

127
128     public IOperations getOperations()
129     {
130         Global global = (Global) getGlobal();
131
132         if (_operations == null)
133         {
134             int i = 0;
135             while (true)
136             {
137                 try
138                 {
139                     IOperationsHome home = global.getOperationsHome();
140
141                     _operations = home.create();
142
143                     break;
144                 }
145                 catch (CreateException JavaDoc ex)
146                 {
147                     throw new ApplicationRuntimeException("Error creating operations bean.", ex);
148                 }
149                 catch (RemoteException JavaDoc ex)
150                 {
151                     rmiFailure("Remote exception creating operations bean.", ex, i++);
152                 }
153             }
154         }
155
156         return _operations;
157     }
158
159     /**
160      * Builds a model for entering in a publisher name, including an intial
161      * blank option.
162      *
163      **/

164
165     public IPropertySelectionModel getPublisherModel()
166     {
167         if (_publisherModel == null)
168             _publisherModel = buildPublisherModel();
169
170         return _publisherModel;
171     }
172
173     private IPropertySelectionModel buildPublisherModel()
174     {
175         Publisher[] publishers = null;
176
177         EntitySelectionModel model = new EntitySelectionModel();
178
179         // Add in a default null value, such that the user can
180
// not select a specific Publisher.
181

182         model.add(null, "");
183
184         int i = 0;
185         while (true)
186         {
187             IOperations operations = getOperations();
188
189             try
190             {
191                 publishers = operations.getPublishers();
192
193                 // Exit the retry loop
194

195                 break;
196             }
197             catch (RemoteException JavaDoc ex)
198             {
199                 rmiFailure("Unable to obtain list of publishers.", ex, i++);
200             }
201         }
202
203         // Add in the actual publishers. They are sorted by name.
204

205         for (i = 0; i < publishers.length; i++)
206             model.add(publishers[i].getId(), publishers[i].getName());
207
208         return model;
209     }
210
211     /**
212      * Invoked from {@link Visit#clearCache()} (and at the end of the request
213      * cycle) to clear the publisher and person
214      * {@link IPropertySelectionModel} models.
215      *
216      **/

217
218     public void clearCache()
219     {
220         _publisherModel = null;
221         _personModel = null;
222
223         Visit visit = (Visit) getVisit();
224
225         if (visit != null)
226             visit.clearCache();
227     }
228
229     /**
230      * Returns a model that contains all the known Person's, sorted by last name,
231      * then first. The label for the model matches the user's natural name.
232      *
233      **/

234
235     public IPropertySelectionModel getPersonModel()
236     {
237         if (_personModel == null)
238             _personModel = buildPersonModel(false);
239
240         return _personModel;
241     }
242
243     public IPropertySelectionModel buildPersonModel(boolean includeEmpty)
244     {
245         Person[] persons = null;
246
247         int i = 0;
248         while (true)
249         {
250             IOperations operations = getOperations();
251
252             try
253             {
254                 persons = operations.getPersons();
255
256                 break;
257             }
258             catch (RemoteException JavaDoc ex)
259             {
260                 rmiFailure("Unable to obtain list of persons.", ex, i++);
261             }
262         }
263
264         EntitySelectionModel model = new EntitySelectionModel();
265
266         if (includeEmpty)
267             model.add(null, "");
268
269         for (i = 0; i < persons.length; i++)
270             model.add(persons[i].getId(), persons[i].getNaturalName());
271
272         return model;
273
274     }
275
276     /**
277      * Creates a new {@link IBookQuery} EJB instance.
278      *
279      **/

280
281     public IBookQuery createNewQuery()
282     {
283         Global global = (Global) getGlobal();
284
285         IBookQuery result = null;
286
287         int i = 0;
288         while (true)
289         {
290             IBookQueryHome home = global.getBookQueryHome();
291
292             try
293             {
294                 result = home.create();
295
296                 break;
297             }
298             catch (CreateException JavaDoc ex)
299             {
300                 throw new ApplicationRuntimeException("Could not create BookQuery bean.", ex);
301             }
302             catch (RemoteException JavaDoc ex)
303             {
304                 rmiFailure("Remote exception creating BookQuery bean.", ex, i++);
305             }
306         }
307
308         return result;
309     }
310
311     /**
312      * Invoked in various places to present an error message to the user.
313      * This sets the error property of either the
314      * {@link org.apache.tapestry.vlib.pages.Home} or
315      * {@link org.apache.tapestry.vlib.pages.MyLibrary} page
316      * (the latter only if the user is logged in),
317      * and sets the selected page for rendering the response.
318      *
319      **/

320
321     public void presentError(String JavaDoc error, IRequestCycle cycle)
322     {
323         String JavaDoc pageName = "Home";
324         // Get, but don't create, the visit.
325
Visit visit = (Visit) getVisit();
326
327         if (visit != null && visit.isUserLoggedIn())
328             pageName = "MyLibrary";
329
330         IErrorProperty page = (IErrorProperty) cycle.getPage(pageName);
331
332         page.setError(error);
333
334         cycle.activate(page);
335     }
336
337     /**
338      * Invoked after an operation on a home or remote interface
339      * throws a RemoteException; this clears any cache of
340      * home and remote interfaces.
341      *
342      * @param message the message for the exception, or for the log message
343      * @param ex the exception thrown
344      * @param attempt the attempt number. Attempt #0 simply clears the EJBs,
345      * attempt #1 is the real failure.
346      *
347      **/

348
349     public void rmiFailure(String JavaDoc message, RemoteException JavaDoc ex, int attempt)
350     {
351         LOG.error(message, ex);
352
353         clearEJBs();
354
355         if (attempt > 0)
356             punt(message, ex);
357
358     }
359
360     private void punt(String JavaDoc message, Throwable JavaDoc ex)
361     {
362         _applicationUnavailableMessage = message;
363
364         throw new ApplicationRuntimeException(message, ex);
365     }
366
367     private void clearEJBs()
368     {
369         Global global = (Global) getGlobal();
370
371         global.clear();
372
373         _operations = null;
374     }
375
376     /**
377      * Invoked when any kind of runtime exception percolates up to the
378      * top level service method. Normally, the standard Exception
379      * page is displayed; we logout and setup our own version of the page
380      * instead.
381      *
382      **/

383
384     protected void activateExceptionPage(
385         IRequestCycle cycle,
386         ResponseOutputStream output,
387         Throwable JavaDoc cause)
388         throws ServletException JavaDoc
389     {
390         try
391         {
392             logout();
393
394             ApplicationUnavailable page =
395                 (ApplicationUnavailable) cycle.getPage("ApplicationUnavailable");
396
397             String JavaDoc message = _applicationUnavailableMessage;
398
399             if (message == null)
400                 message = cause.getMessage();
401
402             if (message == null)
403                 message = cause.getClass().getName();
404
405             page.activate(message, cause);
406
407             cycle.activate(page);
408
409             renderResponse(cycle, output);
410         }
411         catch (Throwable JavaDoc t)
412         {
413             super.activateExceptionPage(cycle, output, cause);
414         }
415     }
416
417     /**
418      * Reads a person by id.
419      *
420      **/

421
422     public Person readPerson(Integer JavaDoc personId)
423     {
424         Person result = null;
425
426         int i = 0;
427         while (true)
428         {
429             IOperations operations = getOperations();
430
431             try
432             {
433                 result = operations.getPerson(personId);
434
435                 break;
436             }
437             catch (FinderException JavaDoc ex)
438             {
439                 throw new ApplicationRuntimeException("No such Person #" + personId + ".", ex);
440             }
441             catch (RemoteException JavaDoc ex)
442             {
443                 rmiFailure("Unable to read Person #" + personId + ".", ex, i++);
444             }
445         }
446
447         return result;
448     }
449
450     protected void handleStaleSessionException(
451         StaleSessionException ex,
452         IRequestCycle cycle,
453         ResponseOutputStream output)
454         throws IOException JavaDoc, ServletException JavaDoc
455     {
456         IMessageProperty home = (IMessageProperty)cycle.getPage("Home");
457         
458         home.setMessage("You have been logged out due to inactivity.");
459         
460         redirect("Home", cycle, output, ex);
461     }
462
463 }
Popular Tags