1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.factory;
18
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.Iterator;
22 import java.util.Map;
23
24 import javax.portlet.Portlet;
25 import javax.portlet.PortletConfig;
26 import javax.portlet.PortletContext;
27 import javax.portlet.PortletException;
28 import javax.portlet.PreferencesValidator;
29 import javax.portlet.UnavailableException;
30 import javax.servlet.ServletContext;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.jetspeed.container.JetspeedPortletConfig;
35 import org.apache.jetspeed.container.PortalAccessor;
36 import org.apache.jetspeed.om.common.portlet.PortletApplication;
37 import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
38 import org.apache.jetspeed.portlet.PortletObjectProxy;
39 import org.apache.pluto.om.portlet.PortletDefinition;
40
41 /***
42 * <p>
43 * JetspeedPortletFactory
44 * </p>
45 * <p>
46 *
47 * </p>
48 * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
49 * @version $Id: JetspeedPortletFactory.java 593513 2007-11-09 12:48:34Z woonsan $
50 *
51 */
52 public class JetspeedPortletFactory implements PortletFactory
53 {
54
55 private Map portletCache;
56 private Map validatorCache;
57
58 private static final Log log = LogFactory.getLog(JetspeedPortletFactory.class);
59 private final Map classLoaderMap;
60
61 /***
62 * Flag whether this factory will create proxy instances for actual portlet instances or not.
63 */
64 private boolean portletProxyUsed;
65
66 /***
67 * Flag whether the instantiated proxy will switch edit_defaults mode to edit mode automatically or not.
68 */
69 private boolean autoSwitchEditDefaultsModeToEditMode;
70
71 /***
72 * Flag whether the instantiated proxy will switch config mode to built-in config edit page or not.
73 */
74 private boolean autoSwitchConfigMode;
75
76 private String customConfigModePortletUniqueName;
77
78 public JetspeedPortletFactory()
79 {
80 this(false, false);
81 }
82
83 public JetspeedPortletFactory(boolean autoSwitchConfigMode, boolean autoSwitchEditDefaultsModeToEditMode)
84 {
85 this.portletCache = Collections.synchronizedMap(new HashMap());
86 this.validatorCache = Collections.synchronizedMap(new HashMap());
87 classLoaderMap = Collections.synchronizedMap(new HashMap());
88
89 this.autoSwitchConfigMode = autoSwitchConfigMode;
90 this.autoSwitchEditDefaultsModeToEditMode = autoSwitchEditDefaultsModeToEditMode;
91
92 this.portletProxyUsed = (this.autoSwitchConfigMode || this.autoSwitchEditDefaultsModeToEditMode);
93 }
94
95 public void setPortletProxyUsed(boolean portletProxyUsed)
96 {
97 this.portletProxyUsed = portletProxyUsed;
98 }
99
100 public boolean getPortletProxyUsed()
101 {
102 return this.portletProxyUsed;
103 }
104
105 public void setCustomConfigModePortletUniqueName(String customConfigModePortletUniqueName)
106 {
107 this.customConfigModePortletUniqueName = customConfigModePortletUniqueName;
108 }
109
110 public String getCustomConfigModePortletUniqueName()
111 {
112 return this.customConfigModePortletUniqueName;
113 }
114
115 public void registerPortletApplication(PortletApplication pa, ClassLoader cl)
116 {
117 synchronized (classLoaderMap)
118 {
119 unregisterPortletApplication(pa);
120 classLoaderMap.put(pa.getId(), cl);
121 }
122 }
123
124 public void unregisterPortletApplication(PortletApplication pa)
125 {
126 synchronized (classLoaderMap)
127 {
128 synchronized (portletCache)
129 {
130 ClassLoader cl = (ClassLoader) classLoaderMap.remove(pa.getId());
131 if (cl != null)
132 {
133 ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
134
135 Iterator portletDefinitions = pa.getPortletDefinitions().iterator();
136 while (portletDefinitions.hasNext())
137 {
138 PortletDefinition pd = (PortletDefinition) portletDefinitions.next();
139 String pdId = pd.getId().toString();
140 Portlet portlet = (Portlet) portletCache.remove(pdId);
141 if (portlet != null)
142 {
143 try
144 {
145 Thread.currentThread().setContextClassLoader(cl);
146 portlet.destroy();
147 }
148 finally
149 {
150 Thread.currentThread().setContextClassLoader(currentContextClassLoader);
151 }
152 }
153 validatorCache.remove(pdId);
154 }
155 }
156 }
157 }
158 }
159
160 public PreferencesValidator getPreferencesValidator(PortletDefinition pd)
161 {
162 PreferencesValidator validator = null;
163 try
164 {
165 String pdId = pd.getId().toString();
166
167 synchronized (validatorCache)
168 {
169 validator = (PreferencesValidator)validatorCache.get(pdId);
170 if ( validator == null )
171 {
172 String className = ((PortletDefinitionComposite)pd).getPreferenceValidatorClassname();
173 if ( className != null )
174 {
175 PortletApplication pa = (PortletApplication)pd.getPortletApplicationDefinition();
176 ClassLoader paCl = (ClassLoader)classLoaderMap.get(pa.getId());
177 if ( paCl == null )
178 {
179 throw new UnavailableException("Portlet Application "+pa.getName()+" not available");
180 }
181
182 ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
183 try
184 {
185 Class clazz = paCl.loadClass(className);
186 try
187 {
188 Thread.currentThread().setContextClassLoader(paCl);
189 validator = (PreferencesValidator)clazz.newInstance();
190 validatorCache.put(pdId, validator);
191 }
192 finally
193 {
194 Thread.currentThread().setContextClassLoader(currentContextClassLoader);
195 }
196 }
197 catch (Exception e)
198 {
199 String msg = "Cannot create PreferencesValidator instance "+className+" for Portlet "+pd.getName();
200 log.error(msg,e);
201 }
202 }
203 }
204 }
205 }
206 catch (Exception e)
207 {
208 log.error(e);
209 }
210 return validator;
211 }
212
213 /***
214 * Gets a portlet by either creating it or returning a handle to it from the portlet 'cache'
215 *
216 * @param portletDefinition The definition of the portlet
217 * @return PortletInstance
218 * @throws PortletException
219 */
220 public PortletInstance getPortletInstance( ServletContext servletContext, PortletDefinition pd ) throws PortletException
221 {
222 PortletInstance portlet = null;
223 String pdId = pd.getId().toString();
224 PortletApplication pa = (PortletApplication)pd.getPortletApplicationDefinition();
225
226 try
227 {
228 synchronized (portletCache)
229 {
230 portlet = (PortletInstance)portletCache.get(pdId);
231 if (null != portlet)
232 {
233 return portlet;
234 }
235
236 ClassLoader paCl = (ClassLoader)classLoaderMap.get(pa.getId());
237 if ( paCl == null )
238 {
239 throw new UnavailableException("Portlet Application "+pa.getName()+" not available");
240 }
241
242 ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
243
244 try
245 {
246 Class clazz = paCl.loadClass(pd.getClassName());
247 try
248 {
249 Thread.currentThread().setContextClassLoader(paCl);
250
251
252
253
254 if (this.portletProxyUsed && !PortletObjectProxy.isPortletObjectProxied())
255 {
256 portlet = new JetspeedPortletProxyInstance(pd.getName(), (Portlet)clazz.newInstance(), this.autoSwitchEditDefaultsModeToEditMode, this.autoSwitchConfigMode, this.customConfigModePortletUniqueName);
257 }
258 else
259 {
260 portlet = new JetspeedPortletInstance(pd.getName(), (Portlet)clazz.newInstance());
261 }
262 }
263 finally
264 {
265 Thread.currentThread().setContextClassLoader(currentContextClassLoader);
266 }
267 }
268 catch (Exception e)
269 {
270 String msg = "Cannot create Portlet instance "+pd.getClassName()+" for Portlet Application "+pa.getName();
271 log.error(msg,e);
272 throw new UnavailableException(msg);
273 }
274
275 PortletContext portletContext = PortalAccessor.createPortletContext(servletContext, pa);
276 PortletConfig portletConfig = PortalAccessor.createPortletConfig(portletContext, pd);
277
278 try
279 {
280 try
281 {
282 Thread.currentThread().setContextClassLoader(paCl);
283 portlet.init(portletConfig);
284 }
285 finally
286 {
287 Thread.currentThread().setContextClassLoader(currentContextClassLoader);
288 }
289 }
290 catch (PortletException e1)
291 {
292 log.error("Failed to initialize Portlet "+pd.getClassName()+" for Portlet Application "+pa.getName(), e1);
293 throw e1;
294 }
295 portletCache.put(pdId, portlet);
296 }
297 }
298 catch (PortletException pe)
299 {
300 throw pe;
301 }
302 catch (Throwable e)
303 {
304 log.error("PortletFactory: Failed to load portlet "+pd.getClassName(), e);
305 throw new UnavailableException( "Failed to load portlet " + pd.getClassName() +": "+e.toString());
306 }
307 return portlet;
308 }
309
310 public void updatePortletConfig(PortletDefinition pd)
311 {
312 if (pd != null)
313 {
314
315 String key = pd.getId().toString();
316 PortletInstance instance = (PortletInstance)portletCache.get(key);
317 if (instance != null)
318 {
319 JetspeedPortletConfig config = (JetspeedPortletConfig)instance.getConfig();
320 config.setPortletDefinition(pd);
321 }
322 }
323 }
324
325 public ClassLoader getPortletApplicationClassLoader(PortletApplication pa)
326 {
327 synchronized (classLoaderMap)
328 {
329 if ( pa != null )
330 {
331 return (ClassLoader)classLoaderMap.get(pa.getId());
332 }
333 return null;
334 }
335 }
336
337 public boolean isPortletApplicationRegistered(PortletApplication pa)
338 {
339 return getPortletApplicationClassLoader(pa) != null;
340 }
341 }