KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icesoft > util > SeamUtilities


1 package com.icesoft.util;
2
3 import org.apache.commons.logging.Log;
4 import org.apache.commons.logging.LogFactory;
5
6 import java.lang.reflect.Method JavaDoc;
7 import java.lang.reflect.Field JavaDoc;
8 import java.util.StringTokenizer JavaDoc;
9
10 import javax.faces.event.PhaseListener;
11 import javax.faces.lifecycle.Lifecycle;
12 import javax.faces.context.FacesContext;
13
14 /**
15  * @author ICEsoft Technologies, Inc.
16  *
17  * Purpose of this class is to localize Seam Introspection code
18  * in one place, and get rid of the variables cluttering up a few
19  * of the ICEfaces classes
20  *
21  * Jun 2007 - removed reference to ConversationIsLongRunningParameter
22  * since seam1.3.0.ALPHA has removed all reference to it in Manager Class
23  *
24  */

25 public class SeamUtilities {
26
27      private static final Log log =
28             LogFactory.getLog(SeamUtilities.class);
29
30     // Seam vars
31

32     private static Class JavaDoc seamManagerClass;
33     
34     private static Class JavaDoc[] seamClassArgs = new Class JavaDoc[0];
35     private static Object JavaDoc[] seamInstanceArgs = new Object JavaDoc[0];
36     private static Class JavaDoc[] seamGetEncodeMethodArgs = {String JavaDoc.class, String JavaDoc.class};
37     private static Object JavaDoc[] seamEncodeMethodArgs = new Object JavaDoc[2];
38
39     private static Object JavaDoc[] seamMethodNoArgs = new Object JavaDoc[0];
40
41     private static Method JavaDoc seamConversationIdMethodInstance;
42     private static Method JavaDoc seamLongRunningMethodInstance;
43     private static Method JavaDoc seamAppendConversationMethodInstance;
44     private static Method JavaDoc seamInstanceMethod;
45     private static Method JavaDoc seamPageContextGetPrefixInstance;
46
47     // The method for getting the conversationId parameter name
48
private static Method JavaDoc seamConversationIdParameterMethod;
49
50     // The method for getting the parent conversationId parameter name
51
// private static Method seamParentConversationIdParameterMethod;
52

53     // the method for getting the longRunningConversation parameter name
54
// private static Method seamLongRunningConversationParameterMethod;
55

56 // private static Method seamBeforeRedirectMethodInstance;
57

58     private static Object JavaDoc pageContextInstance;
59
60     // This is just convenience, to avoid rebuilding the String
61
private static String JavaDoc conversationIdParameter;
62     private static String JavaDoc conversationParentParameter = "parentConversationId";
63 // private static String conversationLongRunningParameter;
64

65     // since seam1.3.0Alpha has api changes, detect which version we are using
66
private static String JavaDoc seamVersion = "none";
67     private static Method JavaDoc seamVersionMethod;
68     
69     private static String JavaDoc SPRING_CLASS_NAME =
70             "org.springframework.webflow.executor.jsf.FlowVariableResolver";
71
72     private static boolean isSpringLoaded;
73
74     static {
75         loadSeamEnvironment();
76         loadSpringEnvironment();
77     }
78     
79     /**
80      * Utility method to determine if the Seam classes can be loaded.
81      *
82      * @return true if Seam classes can be loaded
83      */

84     public static boolean isSeamEnvironment() {
85         return seamManagerClass != null;
86     }
87     
88     /**
89      * Utility method to determine if D2DSeamFaceletViewHandler requires
90      * SeamExpressionFactory Class
91      * @return false if Seam version 1.3.0.ALPHA
92      * false otherwise
93      */

94     public static boolean requiresSeamExpressionFactory(){
95         return (seamVersion.startsWith("1.2.1"));
96     }
97     
98     /**
99      * Called on a redirect to invoke any Seam redirection code. Seam uses
100      * the sendRedirect method to preserve temporary conversations for the
101      * duration of redirects. ICEfaces does not call this method, so this
102      * method attempts to call the same Seam code introspectively. Seam will
103      * encode the <code>conversationId</code> to the end of the argument URI.
104      *
105      * @param uri the redirect URI to redirect to, before the
106      * conversationId is encoded
107      * @return the URI, with the conversationId if Seam is detected
108      */

109     public static String JavaDoc encodeSeamConversationId(String JavaDoc uri, String JavaDoc viewId) {
110
111         // If Seam's not loaded, no changes necessary
112
if (! isSeamEnvironment() ) {
113             return uri;
114         }
115
116         String JavaDoc cleanedUrl = uri;
117
118         if (conversationIdParameter == null) {
119             getConversationIdParameterName();
120         }
121
122         // IF the URI already contains a conversationId, the isLongRunning parameter, or the
123
// parentConversationId parameter, strip it out, and start again.
124

125         // Maybe all of this has changed. This used to be necessary because the
126
//
127

128         if (log.isTraceEnabled()) {
129             log.trace("SeamConversationURLParam: " + conversationIdParameter);
130         }
131         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc( uri, "?&");
132         StringBuffer JavaDoc builder = new StringBuffer JavaDoc();
133
134         String JavaDoc token;
135         boolean first = true;
136         while(st.hasMoreTokens() ){
137             token = st.nextToken();
138             if ( (token.indexOf(conversationIdParameter) > -1) ||
139                  (token.indexOf(conversationParentParameter) > -1) ||
140 // (token.indexOf(conversationLongRunningParameter) > -1) ||
141
token.indexOf("rvn") > -1 ) {
142                 continue;
143             }
144             builder.append(token);
145
146             if (st.hasMoreTokens() ) {
147                 if (first) {
148                     builder.append('?');
149                     first = false;
150                 } else {
151                     builder.append('&');
152                 }
153             }
154         }
155
156         if (builder.length() > 0) {
157             cleanedUrl = builder.toString();
158         }
159         // The manager instance is a singleton, but it's continuously destroyed
160
// after each request and thus must be re-obtained during each redirect.
161
try {
162
163             // Get the singleton instance of the Seam Manager each time through
164
Object JavaDoc seamManagerInstance =
165                     seamInstanceMethod.invoke(null, seamInstanceArgs);
166
167             if (seamAppendConversationMethodInstance != null) {
168                 seamEncodeMethodArgs[0] = cleanedUrl;
169                 if (seamEncodeMethodArgs.length == 2) {
170                     seamEncodeMethodArgs[1] = viewId;
171                 }
172
173 // seamBeforeRedirectMethodInstance.invoke(
174
// seamManagerInstance, seamMethodNoArgs);
175

176                 
177                // This has to do what the Manager.redirect method does.
178
cleanedUrl = (String JavaDoc) seamAppendConversationMethodInstance
179                         .invoke(seamManagerInstance, seamEncodeMethodArgs);
180
181
182
183                 if (log.isDebugEnabled()) {
184                     log.debug("Enabled redirect from: " +
185                             uri + ", to: " + cleanedUrl);
186                 }
187             }
188         } catch (Exception JavaDoc e) {
189             seamInstanceMethod = null;
190             seamManagerClass = null;
191             log.error("Exception encoding seam conversationId: ", e);
192
193         }
194         return cleanedUrl;
195     }
196
197     /**
198      * Retrieve the current Seam conversationId (if any) by introspection from
199      * the SeamManager. The seam Conversation must be a long running
200      * conversation, otherwise it isn't useful to encode it in the form. Long
201      * running conversations are started by Seam components at various parts of
202      * the application lifecycle, and their Id is necessary during a partial
203      * submit to continue the thread of the conversation.
204      *
205      * @return The current conversation id, or null if not a seam environment,
206      * or there is no current long running conversation.
207      */

208     public static String JavaDoc getSeamConversationId() {
209
210         if ( !isSeamEnvironment()) {
211             return null;
212         }
213         
214         String JavaDoc returnVal = null;
215
216         try {
217             // The manager instance is a singleton, but it's continuously
218
// destroyed after each request and thus must be re-obtained.
219
Object JavaDoc seamManagerInstance =
220                     seamInstanceMethod.invoke(null, seamMethodNoArgs);
221
222             if (seamConversationIdMethodInstance != null) {
223
224                 String JavaDoc conversationId =
225                         (String JavaDoc) seamConversationIdMethodInstance.invoke(
226                                 seamManagerInstance, seamMethodNoArgs);
227
228                 Boolean JavaDoc is = (Boolean JavaDoc) seamLongRunningMethodInstance
229                         .invoke(seamManagerInstance,
230                                 seamMethodNoArgs);
231
232                 if (is.booleanValue()) {
233                     returnVal = conversationId;
234                 }
235             }
236
237         } catch (Exception JavaDoc e) {
238             seamInstanceMethod = null;
239             seamManagerClass = null;
240             log.error("Exception determining Seam ConversationId: ", e);
241
242         }
243         return returnVal;
244     }
245
246     /**
247      * Retrieve the PageContext key. Equivalent to
248      * <code>ScopeType.PAGE.getPrefix()</code>. Can be used to
249      * manipulate the PageContext, without loading the class.
250      *
251      * This String is used as the key to store the PageContext in the
252      * ViewRoot attribute map, and does not equal the string
253      * "org.jboss.seam.PAGE"
254      *
255      * @return The String Key that can be used to find the Seam PageContext
256      */

257     public static String JavaDoc getPageContextKey() {
258
259         String JavaDoc returnVal = "";
260         if (!isSeamEnvironment()) {
261             return returnVal;
262         }
263
264         try {
265
266             if (seamConversationIdMethodInstance != null) {
267                 returnVal = (String JavaDoc) seamPageContextGetPrefixInstance.invoke(
268                         pageContextInstance, seamMethodNoArgs);
269             }
270
271         } catch (Exception JavaDoc e) {
272             log.error("Exception fetching Page from ScopeType: ", e);
273
274         }
275         return returnVal;
276     }
277
278
279
280     /**
281      * Attempt to load the classes from the Seam jars. The methods I
282      * can locate and load here, but the values (for example, the
283      * conversationIdParameter name which is not mutable) have to be
284      * retrieved from a Manager instance when the Manager object is
285      * available, and that is only during a valid EventContext.
286      */

287     private static void loadSeamEnvironment() {
288         try {
289             
290             // load classes
291
seamManagerClass = Class.forName("org.jboss.seam.core.Manager");
292             Class JavaDoc seamScopeTypeClass = Class.forName("org.jboss.seam.ScopeType");
293             
294
295
296             // load method instances
297
seamInstanceMethod = seamManagerClass.getMethod("instance",
298                                                             seamClassArgs);
299
300             Field JavaDoc fieldInstance = seamScopeTypeClass.getField("PAGE");
301
302             
303             
304             pageContextInstance = fieldInstance.get(seamScopeTypeClass);
305
306
307             seamPageContextGetPrefixInstance = seamScopeTypeClass.getMethod(
308                     "getPrefix", seamClassArgs);
309             
310             // for D2DSeamFaceletViewHandler need to know version
311
try {
312                Class JavaDoc seamClass = Class.forName("org.jboss.seam.Seam");
313                seamVersionMethod = seamClass.getMethod("getVersion",null);
314                if (seamVersionMethod!=null){
315                    seamVersion = (String JavaDoc)seamVersionMethod.invoke(null,seamMethodNoArgs);
316                    log.info("SeamUtilities: loadSeam.. seamVersion="+seamVersion);
317                }
318             } catch (NoSuchMethodException JavaDoc e){
319                     /* no getVersion method exists for Seam1.2.1 or earlier */
320                     seamVersion="1.2.1.GA";
321                     log.info("\t -->>>> seamVersion is null");
322             }
323             log.info("\t ->>> seamVersion="+seamVersion);
324             
325             try {
326                 seamAppendConversationMethodInstance =
327                         seamManagerClass.getMethod("encodeConversationId",
328                                                    seamGetEncodeMethodArgs);
329             } catch (NoSuchMethodException JavaDoc e) {
330                 /* revert our reflectively discovered Seam method
331                    to the Seam 1.2.0 API
332                 */

333                 seamGetEncodeMethodArgs = new Class JavaDoc[] {String JavaDoc.class};
334                 seamEncodeMethodArgs = new Object JavaDoc[1];
335                 seamAppendConversationMethodInstance =
336                         seamManagerClass.getMethod("encodeConversationId",
337                                                    seamGetEncodeMethodArgs);
338             }
339
340             seamConversationIdMethodInstance =
341                     seamManagerClass.getMethod("getCurrentConversationId",
342                                                seamClassArgs);
343             seamLongRunningMethodInstance =
344                     seamManagerClass.getMethod("isLongRunningConversation",
345                                                seamClassArgs);
346
347
348             seamConversationIdParameterMethod =
349                     seamManagerClass.getMethod("getConversationIdParameter",
350                                                seamClassArgs);
351
352             // This method is protected
353
// seamParentConversationIdParameterMethod =
354
// seamManagerClass.getMethod("getParentConversationIdParameter",
355
// seamClassArgs);
356

357
358 // seamLongRunningConversationParameterMethod =
359
// seamManagerClass.getMethod("getConversationIsLongRunningParameter",
360
// seamClassArgs);
361

362 // seamBeforeRedirectMethodInstance =
363
// seamManagerClass.getMethod("beforeRedirect",
364
// seamClassArgs);
365

366
367
368             Class.forName("org.jboss.seam.util.Parameters");
369
370
371         } catch (ClassNotFoundException JavaDoc cnf) {
372 // log.info ("Seam environment not detected ");
373
} catch (Exception JavaDoc e) {
374             seamInstanceMethod = null;
375             seamManagerClass = null;
376             log.info("Exception loading seam environment: ", e);
377         }
378         
379         if (seamManagerClass != null) {
380             log.info("Seam environment detected ");
381         }
382     }
383
384
385     /**
386      * Seam 1.0.1 uses an element <code>'conversationId'</code> as the
387      * parameter name, whereas Seam 1.1 has it as a configurable item. This method
388      * will call the Manager instance to retrieve the current parameter name
389      * defining containing the conversation ID. This method must only be called
390      * when the EventContext is valid (and thus the Manager
391      * instance is retrievable). The parameter is configurable on a
392      * per application basis, so it wont change at runtime.
393      *
394      * <p>
395      * Calling this method also fills in the conversationIdParameter,
396      * the conversationIsLongRunningParameter, and the conversationParentIdParameter
397      * fields, as they are all configurable, and used in the encoding conversation
398      * id method
399      *
400      * @return the appropriate parameter name for the application
401      */

402     public static String JavaDoc getConversationIdParameterName() {
403         if (!isSeamEnvironment()) {
404             return null;
405         }
406         if (conversationIdParameter != null ) {
407             return conversationIdParameter;
408         }
409
410         String JavaDoc returnVal = null;
411         try {
412
413             Object JavaDoc seamManagerInstance =
414                     seamInstanceMethod.invoke(null, seamMethodNoArgs);
415
416             // The method may not be available on all versions of Manager
417
if (seamConversationIdParameterMethod != null) {
418
419                 returnVal = (String JavaDoc) seamConversationIdParameterMethod.
420                         invoke(seamManagerInstance, seamMethodNoArgs);
421                 conversationIdParameter = returnVal;
422             }
423
424 // if (seamParentConversationIdParameterMethod != null) {
425
// conversationParentParameter = (String)
426
// seamParentConversationIdParameterMethod.
427
// invoke(seamManagerInstance, seamMethodNoArgs);
428
// }
429

430 // if (seamLongRunningConversationParameterMethod != null) {
431
// conversationLongRunningParameter = (String)
432
// seamLongRunningConversationParameterMethod.invoke(
433
// seamManagerInstance, seamMethodNoArgs);
434
// }
435

436
437         } catch (Exception JavaDoc e) {
438             log.error("Exception fetching conversationId Parameter name: ", e);
439
440         }
441         return returnVal;
442     }
443
444     /**
445      * ICE-1084 : We have to turn off Seam's PhaseListener that makes
446      * it's debug page appear, so that our SeamDebugResourceResolver
447      * can do its work.
448      *
449      * @param lifecycle The Lifecycle maintains the list of PhaseListeners
450      */

451     public static void removeSeamDebugPhaseListener(Lifecycle lifecycle) {
452         PhaseListener[] phaseListeners = lifecycle.getPhaseListeners();
453 // System.out.println("*** SeamUtilities.removeSeamDebugPhaseListener()");
454
// System.out.println("*** phaseListeners: " + phaseListeners.length);
455
for(int i = 0; i < phaseListeners.length; i++) {
456 // System.out.println("*** phaseListeners["+i+"]: " + phaseListeners[i]);
457
if( phaseListeners[i].getClass().getName().equals(
458                 "org.jboss.seam.debug.jsf.SeamDebugPhaseListener") )
459             {
460                 lifecycle.removePhaseListener(phaseListeners[i]);
461 //System.out.println("*** REMOVED: " + phaseListeners[i]);
462
seamDebugPhaseListenerClassLoader = phaseListeners[i].getClass().getClassLoader();
463 //System.out.println("****** SeamDebugPhaseListener.class.getClassLoader(): " + phaseListeners[i].getClass().getClassLoader());
464
}
465         }
466     }
467     
468     public static ClassLoader JavaDoc getSeamDebugPhaseListenerClassLoader() {
469         return seamDebugPhaseListenerClassLoader;
470     }
471     
472     private static ClassLoader JavaDoc seamDebugPhaseListenerClassLoader;
473     
474
475     
476     /**
477      * Perform any needed Spring initialization.
478      */

479     private static void loadSpringEnvironment() {
480         Class JavaDoc flowVariableResolver = null;
481         try {
482             flowVariableResolver = Class.forName(SPRING_CLASS_NAME);
483         } catch (Throwable JavaDoc t) {
484             if (log.isDebugEnabled()) {
485                 log.debug("Spring webflow not detected: " + t);
486             }
487         }
488         if (null != flowVariableResolver) {
489             isSpringLoaded = true;
490             if (log.isDebugEnabled()) {
491                 log.debug("Spring webflow detected: " + flowVariableResolver);
492             }
493         }
494
495     }
496
497     /**
498      * Utility method to determine if Spring WebFlow is active.
499      *
500      * @return true if Spring WebFlow is enabled
501      */

502     public static boolean isSpringEnvironment() {
503         return isSpringLoaded;
504     }
505
506     /**
507      * Retrieve the current Spring flowId (if any).
508      *
509      * @return The current Spring flowId.
510      */

511     public static String JavaDoc getSpringFlowId() {
512         if ( !isSpringEnvironment()) {
513             return null;
514         }
515         FacesContext facesContext = FacesContext.getCurrentInstance();
516         //obtain key by evaluating expression with Spring VariableResolver
517
Object JavaDoc value = facesContext.getApplication()
518                 .createValueBinding("#{flowExecutionKey}").getValue(facesContext);
519         if (null == value) {
520             return null;
521         }
522         
523         return value.toString();
524     }
525     /**
526      * Return the parameter name for the Spring Flow Id
527      *
528      * @return the appropriate parameter name for the application
529      */

530     public static String JavaDoc getFlowIdParameterName() {
531         return "_flowExecutionKey";
532     }
533
534 }
535
Popular Tags