View Javadoc

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