View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.orchestra.frameworkAdapter;
20  
21  import java.io.IOException;
22  
23  import org.apache.myfaces.orchestra.conversation.ConversationMessager;
24  
25  /**
26   * An interface that provides access to all the data necessary for Orchestra to work while isolating Orchestra
27   * from the actual UI presentation framework being used.
28   * <p>
29   * A different concrete subclass of this type is then provided for each UI framework that Orchestra supports
30   * (and additional subtypes can be defined by users if required). This allows Orchestra to support multiple
31   * presentation frameworks, such as JSF and plain JSP. Method getCurrentInstance is used by Orchestra code
32   * to locate the appropriate adapter instance when needed.
33   * <p>
34   * The method setCurrentInstance must be called at the start of each request in order to set the
35   * appropriate adapter instance for whatever UI framework will be handing that request.
36   */
37  public abstract class FrameworkAdapter
38  {
39      private final static ThreadLocal instanceThreadLocal = new ThreadLocal();
40  
41      private ConversationMessager conversationMessager;
42      private boolean prepared = false;
43  
44      /**
45       * Expected to be called only by a servlet filter at the start and end of each request.
46       * <p>
47       * The prepare method of the provided frameworkAdapter is called if it has not already
48       * been done. This ensures that the object is valid before the request begins. An
49       * unchecked exception may therefore be thrown if the instance is misconfigured.
50       */
51      public static void setCurrentInstance(FrameworkAdapter frameworkAdapter)
52      {
53          if (frameworkAdapter == null)
54          {
55              instanceThreadLocal.remove();
56              return;
57          }
58              
59          synchronized(frameworkAdapter)
60          {
61              if (!frameworkAdapter.prepared)
62              {
63                  frameworkAdapter.prepare();
64              }
65          }
66  
67          instanceThreadLocal.set(frameworkAdapter);
68      }
69  
70      /**
71       * Return an object that implements the non-static methods of this abstract
72       * class in a manner appropriate for whatever UI framework is handling the
73       * current request.
74       */
75      public static FrameworkAdapter getCurrentInstance()
76      {
77          return (FrameworkAdapter) instanceThreadLocal.get();
78      }
79  
80      /**
81       * Constructor.
82       * <p>
83       * This constructor deliberately takes no parameters, as this class may be extended
84       * in future releases, adding new framework-specific properties if more are needed.
85       * Changing the constructor would not be elegant, so instead this class uses 
86       * "setter" methods to set the properties of this object, and the prepare() method
87       * to ensure object integrity.
88       */
89      public FrameworkAdapter()
90      {
91      }
92  
93      /**
94       * Ensure this object is valid, and perform any once-only initialisation required. 
95       * <p>
96       * This method must be called before any call to any method on this class
97       * other than setters. Multiple calls to this method are safe; all except the first
98       * one will be ignored. The setCurrentInstance method calls this method
99       * automatically.
100      * <p>
101      * This method may be overridden by subclasses to perform once-only initialisation.
102      * If this is done, call super.prepare at the end of the subclass implementation.
103      * <p>
104      * This method can throw unchecked exceptions if there is a problem with the
105      * configuration of this object.
106      */
107     public void prepare()
108     {
109         if (conversationMessager == null)
110         {
111             // Not set via an explicit call to the setter, and not set
112             // from a child class implementation of this method, so
113             // try to do it here.
114             conversationMessager = createConversationMessager();
115         }
116 
117         synchronized(this)
118         {
119             prepared = true;
120         }
121     }
122 
123     /**
124      * If this method is not overridden by a subclass, then method setConversationMessager
125      * must be used to explicitly provide an instance.
126      */
127     protected ConversationMessager createConversationMessager()
128     {
129         throw new IllegalStateException("conversation messager configuration missing"); // NON-NLS
130     }
131 
132     /**
133      * Return an object that can report internal application problems to the user associated
134      * with the current request.
135      * <p>
136      * If setConversationManager was called explicitly when this object was set up, then the
137      * provided instance is returned. Otherwise what is returned is determined by the
138      * concrete subclass. See the appropriate subclass documentation for details.
139      */
140     public ConversationMessager getConversationMessager()
141     {
142         return conversationMessager;
143     }
144 
145     /**
146      * Set the object that can report internal application problems to the user associated
147      * with a request. This method is only ever expected to be called once, during
148      * configuration of a FrameworkAdapter instance.
149      */
150     public void setConversationMessager(ConversationMessager conversationMessager)
151     {
152         this.conversationMessager = conversationMessager;
153     }
154 
155     /**
156      * Return the global init parameter with the specified name.
157      * In most cases this is expected to return data from the ServletContext.
158      */
159     public abstract String getInitParameter(String key);
160 
161     /**
162      * Get a value from the set of input parameters sent by the user as part
163      * of the request.
164      */
165     public abstract Object getRequestParameterAttribute(String key);
166 
167     public abstract boolean containsRequestParameterAttribute(String key);
168 
169     /**
170      * Get a request-scope variable.
171      */
172     public abstract Object getRequestAttribute(String key);
173 
174     public abstract void setRequestAttribute(String key, Object value);
175 
176     public abstract boolean containsRequestAttribute(String key);
177 
178     /**
179      * Get a variable from the session-scope of the current user.
180      */
181     public abstract Object getSessionAttribute(String key);
182 
183     public abstract void setSessionAttribute(String key, Object value);
184 
185     public abstract boolean containsSessionAttribute(String key);
186 
187     /**
188      * Instruct the remote browser to fetch the specified URL.
189      */
190     public abstract void redirect(String url) throws IOException;
191 
192     /**
193      * Return the variable with the specified name, or null if no such bean exists.
194      * <p>
195      * In frameworks that support "managed beans", ie creation of objects on demand then
196      * this may trigger the creation of the specified object. In frameworks that do not
197      * support this, then the lookup may just return null if no object with the specified
198      * name currently exists.
199      * <p>
200      * Note that no "property traversal" is required or expected; a name of "a.b.c"
201      * is NOT evaluated as "property c of property b of bean a", but as the bean
202      * with name 'a.b.c'.
203      */
204     public abstract Object getBean(String name);
205 
206     /**
207      * Navigate to the specified logical destination.
208      * <p>
209      * For frameworks that have a built-in navigation system, that system should be
210      * invoked.
211      * <p>
212      * For frameworks with no logical navigation system, the navigationName is treated
213      * as a plain URL. Whether a FORWARD or a REDIRECT to this URL is perfomed is
214      * determined by the subclass.
215      */
216     public abstract void invokeNavigation(String navigationName) throws IOException;
217 
218     /**
219      * Return a string that identifies what view (logical application page) the user is
220      * currently working with. 
221      * <p>
222      * The primary use of this is to pass it to the "view controller manager" to obtain
223      * the "view controller" bean that holds the lifecycle methods needed for the current
224      * view.
225      * <p>
226      * For frameworks like JSF, this is the "view id". 
227      * <p>
228      * By default a fixed value is returned, which allows frameworks that do not have
229      * a concept of a "current logical page" to automatically support a single
230      * "view controller" bean for the whole application.
231      */
232     public String getCurrentViewId()
233     {
234         return "defaultView";
235     }
236 }