001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.factory;
018:
019: import java.util.Collections;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.Map;
023:
024: import javax.portlet.Portlet;
025: import javax.portlet.PortletConfig;
026: import javax.portlet.PortletContext;
027: import javax.portlet.PortletException;
028: import javax.portlet.PreferencesValidator;
029: import javax.portlet.UnavailableException;
030: import javax.servlet.ServletContext;
031:
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.apache.jetspeed.container.JetspeedPortletConfig;
035: import org.apache.jetspeed.container.PortalAccessor;
036: import org.apache.jetspeed.om.common.portlet.PortletApplication;
037: import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
038: import org.apache.jetspeed.portlet.PortletObjectProxy;
039: import org.apache.pluto.om.portlet.PortletDefinition;
040:
041: /**
042: * <p>
043: * JetspeedPortletFactory
044: * </p>
045: * <p>
046: *
047: * </p>
048: * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
049: * @version $Id: JetspeedPortletFactory.java 593513 2007-11-09 12:48:34Z woonsan $
050: *
051: */
052: public class JetspeedPortletFactory implements PortletFactory {
053:
054: private Map portletCache;
055: private Map validatorCache;
056:
057: private static final Log log = LogFactory
058: .getLog(JetspeedPortletFactory.class);
059: private final Map classLoaderMap;
060:
061: /**
062: * Flag whether this factory will create proxy instances for actual portlet instances or not.
063: */
064: private boolean portletProxyUsed;
065:
066: /**
067: * Flag whether the instantiated proxy will switch edit_defaults mode to edit mode automatically or not.
068: */
069: private boolean autoSwitchEditDefaultsModeToEditMode;
070:
071: /**
072: * Flag whether the instantiated proxy will switch config mode to built-in config edit page or not.
073: */
074: private boolean autoSwitchConfigMode;
075:
076: private String customConfigModePortletUniqueName;
077:
078: public JetspeedPortletFactory() {
079: this (false, false);
080: }
081:
082: public JetspeedPortletFactory(boolean autoSwitchConfigMode,
083: boolean autoSwitchEditDefaultsModeToEditMode) {
084: this .portletCache = Collections.synchronizedMap(new HashMap());
085: this .validatorCache = Collections
086: .synchronizedMap(new HashMap());
087: classLoaderMap = Collections.synchronizedMap(new HashMap());
088:
089: this .autoSwitchConfigMode = autoSwitchConfigMode;
090: this .autoSwitchEditDefaultsModeToEditMode = autoSwitchEditDefaultsModeToEditMode;
091:
092: this .portletProxyUsed = (this .autoSwitchConfigMode || this .autoSwitchEditDefaultsModeToEditMode);
093: }
094:
095: public void setPortletProxyUsed(boolean portletProxyUsed) {
096: this .portletProxyUsed = portletProxyUsed;
097: }
098:
099: public boolean getPortletProxyUsed() {
100: return this .portletProxyUsed;
101: }
102:
103: public void setCustomConfigModePortletUniqueName(
104: String customConfigModePortletUniqueName) {
105: this .customConfigModePortletUniqueName = customConfigModePortletUniqueName;
106: }
107:
108: public String getCustomConfigModePortletUniqueName() {
109: return this .customConfigModePortletUniqueName;
110: }
111:
112: public void registerPortletApplication(PortletApplication pa,
113: ClassLoader cl) {
114: synchronized (classLoaderMap) {
115: unregisterPortletApplication(pa);
116: classLoaderMap.put(pa.getId(), cl);
117: }
118: }
119:
120: public void unregisterPortletApplication(PortletApplication pa) {
121: synchronized (classLoaderMap) {
122: synchronized (portletCache) {
123: ClassLoader cl = (ClassLoader) classLoaderMap.remove(pa
124: .getId());
125: if (cl != null) {
126: ClassLoader currentContextClassLoader = Thread
127: .currentThread().getContextClassLoader();
128:
129: Iterator portletDefinitions = pa
130: .getPortletDefinitions().iterator();
131: while (portletDefinitions.hasNext()) {
132: PortletDefinition pd = (PortletDefinition) portletDefinitions
133: .next();
134: String pdId = pd.getId().toString();
135: Portlet portlet = (Portlet) portletCache
136: .remove(pdId);
137: if (portlet != null) {
138: try {
139: Thread.currentThread()
140: .setContextClassLoader(cl);
141: portlet.destroy();
142: } finally {
143: Thread
144: .currentThread()
145: .setContextClassLoader(
146: currentContextClassLoader);
147: }
148: }
149: validatorCache.remove(pdId);
150: }
151: }
152: }
153: }
154: }
155:
156: public PreferencesValidator getPreferencesValidator(
157: PortletDefinition pd) {
158: PreferencesValidator validator = null;
159: try {
160: String pdId = pd.getId().toString();
161:
162: synchronized (validatorCache) {
163: validator = (PreferencesValidator) validatorCache
164: .get(pdId);
165: if (validator == null) {
166: String className = ((PortletDefinitionComposite) pd)
167: .getPreferenceValidatorClassname();
168: if (className != null) {
169: PortletApplication pa = (PortletApplication) pd
170: .getPortletApplicationDefinition();
171: ClassLoader paCl = (ClassLoader) classLoaderMap
172: .get(pa.getId());
173: if (paCl == null) {
174: throw new UnavailableException(
175: "Portlet Application "
176: + pa.getName()
177: + " not available");
178: }
179:
180: ClassLoader currentContextClassLoader = Thread
181: .currentThread()
182: .getContextClassLoader();
183: try {
184: Class clazz = paCl.loadClass(className);
185: try {
186: Thread.currentThread()
187: .setContextClassLoader(paCl);
188: validator = (PreferencesValidator) clazz
189: .newInstance();
190: validatorCache.put(pdId, validator);
191: } finally {
192: Thread
193: .currentThread()
194: .setContextClassLoader(
195: currentContextClassLoader);
196: }
197: } catch (Exception e) {
198: String msg = "Cannot create PreferencesValidator instance "
199: + className
200: + " for Portlet "
201: + pd.getName();
202: log.error(msg, e);
203: }
204: }
205: }
206: }
207: } catch (Exception e) {
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(
221: ServletContext servletContext, PortletDefinition pd)
222: throws PortletException {
223: PortletInstance portlet = null;
224: String pdId = pd.getId().toString();
225: PortletApplication pa = (PortletApplication) pd
226: .getPortletApplicationDefinition();
227:
228: try {
229: synchronized (portletCache) {
230: portlet = (PortletInstance) portletCache.get(pdId);
231: if (null != portlet) {
232: return portlet;
233: }
234:
235: ClassLoader paCl = (ClassLoader) classLoaderMap.get(pa
236: .getId());
237: if (paCl == null) {
238: throw new UnavailableException(
239: "Portlet Application " + pa.getName()
240: + " not available");
241: }
242:
243: ClassLoader currentContextClassLoader = Thread
244: .currentThread().getContextClassLoader();
245:
246: try {
247: Class clazz = paCl.loadClass(pd.getClassName());
248: try {
249: Thread.currentThread().setContextClassLoader(
250: paCl);
251: // wrap new Portlet inside PortletInstance which ensures the destroy
252: // method will wait for all its invocation threads to complete
253: // and thereby releasing all its ClassLoader locks as needed for local portlets.
254:
255: if (this .portletProxyUsed
256: && !PortletObjectProxy
257: .isPortletObjectProxied()) {
258: portlet = new JetspeedPortletProxyInstance(
259: pd.getName(),
260: (Portlet) clazz.newInstance(),
261: this .autoSwitchEditDefaultsModeToEditMode,
262: this .autoSwitchConfigMode,
263: this .customConfigModePortletUniqueName);
264: } else {
265: portlet = new JetspeedPortletInstance(pd
266: .getName(), (Portlet) clazz
267: .newInstance());
268: }
269: } finally {
270: Thread.currentThread().setContextClassLoader(
271: currentContextClassLoader);
272: }
273: } catch (Exception e) {
274: String msg = "Cannot create Portlet instance "
275: + pd.getClassName()
276: + " for Portlet Application "
277: + pa.getName();
278: log.error(msg, e);
279: throw new UnavailableException(msg);
280: }
281:
282: PortletContext portletContext = PortalAccessor
283: .createPortletContext(servletContext, pa);
284: PortletConfig portletConfig = PortalAccessor
285: .createPortletConfig(portletContext, pd);
286:
287: try {
288: try {
289: Thread.currentThread().setContextClassLoader(
290: paCl);
291: portlet.init(portletConfig);
292: } finally {
293: Thread.currentThread().setContextClassLoader(
294: currentContextClassLoader);
295: }
296: } catch (PortletException e1) {
297: log.error("Failed to initialize Portlet "
298: + pd.getClassName()
299: + " for Portlet Application "
300: + pa.getName(), e1);
301: throw e1;
302: }
303: portletCache.put(pdId, portlet);
304: }
305: } catch (PortletException pe) {
306: throw pe;
307: } catch (Throwable e) {
308: log.error("PortletFactory: Failed to load portlet "
309: + pd.getClassName(), e);
310: throw new UnavailableException("Failed to load portlet "
311: + pd.getClassName() + ": " + e.toString());
312: }
313: return portlet;
314: }
315:
316: public void updatePortletConfig(PortletDefinition pd) {
317: if (pd != null) {
318: //System.out.println("$$$$ updating portlet config for " + pd.getName());
319: String key = pd.getId().toString();
320: PortletInstance instance = (PortletInstance) portletCache
321: .get(key);
322: if (instance != null) {
323: JetspeedPortletConfig config = (JetspeedPortletConfig) instance
324: .getConfig();
325: config.setPortletDefinition(pd);
326: }
327: }
328: }
329:
330: public ClassLoader getPortletApplicationClassLoader(
331: PortletApplication pa) {
332: synchronized (classLoaderMap) {
333: if (pa != null) {
334: return (ClassLoader) classLoaderMap.get(pa.getId());
335: }
336: return null;
337: }
338: }
339:
340: public boolean isPortletApplicationRegistered(PortletApplication pa) {
341: return getPortletApplicationClassLoader(pa) != null;
342: }
343: }
|