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 }