View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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.pluto.om.portlet.PortletDefinition;
39  
40  /***
41   * <p>
42   * JetspeedPortletFactory
43   * </p>
44   * <p>
45   *
46   * </p>
47   * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
48   * @version $Id: JetspeedPortletFactory.java 516448 2007-03-09 16:25:47Z ate $
49   *
50   */
51  public class JetspeedPortletFactory implements PortletFactory
52  {
53  
54      private Map portletCache;
55      private Map validatorCache;
56      
57      private static final Log log = LogFactory.getLog(JetspeedPortletFactory.class);
58      private final Map classLoaderMap;
59  
60      /***
61       * 
62       */
63      public JetspeedPortletFactory()
64      {
65          this.portletCache =  Collections.synchronizedMap(new HashMap());
66          this.validatorCache = Collections.synchronizedMap(new HashMap());
67          classLoaderMap = Collections.synchronizedMap(new HashMap());
68      }
69  
70      public void registerPortletApplication(PortletApplication pa, ClassLoader cl)
71          {
72              synchronized (classLoaderMap)
73              {
74                  unregisterPortletApplication(pa);
75                  classLoaderMap.put(pa.getId(), cl);
76              }
77      }
78      
79      public void unregisterPortletApplication(PortletApplication pa)
80      {
81          synchronized (classLoaderMap)
82          {
83              synchronized (portletCache)
84              {
85                  ClassLoader cl = (ClassLoader) classLoaderMap.remove(pa.getId());
86                  if (cl != null)
87                  {
88                      ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
89  
90                      Iterator portletDefinitions = pa.getPortletDefinitions().iterator();
91                      while (portletDefinitions.hasNext())
92                      {
93                          PortletDefinition pd = (PortletDefinition) portletDefinitions.next();
94                          String pdId = pd.getId().toString();
95                          Portlet portlet = (Portlet) portletCache.remove(pdId);
96                          if (portlet != null)
97                          {
98                              try
99                              {
100                                 Thread.currentThread().setContextClassLoader(cl);
101                                 portlet.destroy();
102                             }
103                             finally
104                             {
105                                 Thread.currentThread().setContextClassLoader(currentContextClassLoader);
106                             }
107                         }
108                         validatorCache.remove(pdId);
109                     }
110                 }
111             }
112         }
113     }
114     
115     public PreferencesValidator getPreferencesValidator(PortletDefinition pd)
116     {
117         PreferencesValidator validator = null;
118         try
119         {
120             String pdId = pd.getId().toString();
121             
122             synchronized (validatorCache)
123             {
124                 validator = (PreferencesValidator)validatorCache.get(pdId);
125                 if ( validator == null )
126                 {
127                     String className = ((PortletDefinitionComposite)pd).getPreferenceValidatorClassname();
128                     if ( className != null )
129                     {
130                         PortletApplication pa = (PortletApplication)pd.getPortletApplicationDefinition();
131                         ClassLoader paCl = (ClassLoader)classLoaderMap.get(pa.getId());
132                         if ( paCl == null )
133                         {
134                             throw new UnavailableException("Portlet Application "+pa.getName()+" not available");
135                         }
136                         
137                         ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
138                         try
139                         {
140                             Class clazz = paCl.loadClass(className);
141                             try
142                             {
143                                 Thread.currentThread().setContextClassLoader(paCl);
144                                 validator = (PreferencesValidator)clazz.newInstance();
145                                 validatorCache.put(pdId, validator);
146                             }
147                             finally
148                             {
149                                 Thread.currentThread().setContextClassLoader(currentContextClassLoader);
150                             }
151                         }
152                         catch (Exception e)
153                         {
154                             String msg = "Cannot create PreferencesValidator instance "+className+" for Portlet "+pd.getName();
155                             log.error(msg,e);
156                         }
157                     }
158                 }
159             }
160         }
161         catch (Exception e)
162         {
163             log.error(e);
164         }
165         return validator;
166     }
167 
168     /***
169      * Gets a portlet by either creating it or returning a handle to it from the portlet 'cache'
170      * 
171      * @param portletDefinition The definition of the portlet
172      * @return PortletInstance 
173      * @throws PortletException
174      */
175     public PortletInstance getPortletInstance( ServletContext servletContext, PortletDefinition pd ) throws PortletException
176     {
177         PortletInstance portlet = null;
178         String pdId = pd.getId().toString();
179         PortletApplication pa = (PortletApplication)pd.getPortletApplicationDefinition();
180 
181         try
182         {                        
183           synchronized (portletCache)
184           {
185             portlet = (PortletInstance)portletCache.get(pdId);
186             if (null != portlet)
187             {
188                 return portlet;
189             }
190             
191             ClassLoader paCl = (ClassLoader)classLoaderMap.get(pa.getId());
192             if ( paCl == null )
193             {
194                 throw new UnavailableException("Portlet Application "+pa.getName()+" not available");
195             }
196             
197             ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
198  
199             try
200             {
201               Class clazz = paCl.loadClass(pd.getClassName());
202               try
203             {
204                 Thread.currentThread().setContextClassLoader(paCl);
205                 // wrap new Portlet inside PortletInstance which ensures the destroy
206                 // method will wait for all its invocation threads to complete
207                 // and thereby releasing all its ClassLoader locks as needed for local portlets.
208                 portlet = new JetspeedPortletInstance(pd.getName(), (Portlet)clazz.newInstance());
209             }
210               finally
211             {
212                 Thread.currentThread().setContextClassLoader(currentContextClassLoader);
213               }
214             }
215             catch (Exception e)
216             {
217                 String msg = "Cannot create Portlet instance "+pd.getClassName()+" for Portlet Application "+pa.getName();
218                 log.error(msg,e);
219                 throw new UnavailableException(msg);
220             }
221       
222             PortletContext portletContext = PortalAccessor.createPortletContext(servletContext, pa);            
223             PortletConfig portletConfig = PortalAccessor.createPortletConfig(portletContext, pd);
224             
225             try
226             {
227               try
228               {
229                 Thread.currentThread().setContextClassLoader(paCl);
230             portlet.init(portletConfig);            
231               }
232               finally
233               {
234                 Thread.currentThread().setContextClassLoader(currentContextClassLoader);
235               }
236             }
237             catch (PortletException e1)
238             {
239                 log.error("Failed to initialize Portlet "+pd.getClassName()+" for Portlet Application "+pa.getName(), e1);
240                 throw e1;
241             }            
242             portletCache.put(pdId, portlet);
243           }
244         }
245         catch (PortletException pe)
246         {
247             throw pe;
248         }
249         catch (Throwable e)
250         {
251             log.error("PortletFactory: Failed to load portlet "+pd.getClassName(), e);
252             throw new UnavailableException( "Failed to load portlet " + pd.getClassName() +": "+e.toString());
253         }
254         return portlet;
255     }
256     
257     public void updatePortletConfig(PortletDefinition pd)
258     {
259         if (pd != null)
260         {
261             //System.out.println("$$$$ updating portlet config for " + pd.getName());
262             String key = pd.getId().toString();
263             PortletInstance instance = (PortletInstance)portletCache.get(key);
264             if (instance != null)
265             {
266                 JetspeedPortletConfig config = (JetspeedPortletConfig)instance.getConfig();
267                 config.setPortletDefinition(pd);
268             }
269         }
270     }
271     
272     public ClassLoader getPortletApplicationClassLoader(PortletApplication pa)
273     {
274         synchronized (classLoaderMap)
275         {
276           if ( pa != null )
277         {
278               return (ClassLoader)classLoaderMap.get(pa.getId());
279         }
280           return null;
281         }
282     }
283     
284     public boolean isPortletApplicationRegistered(PortletApplication pa)
285     {
286         return getPortletApplicationClassLoader(pa) != null;
287     }
288 }