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 }