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.util.descriptor;
18  
19  import java.io.Reader;
20  import java.util.Collection;
21  import java.util.Iterator;
22  
23  import org.apache.commons.digester.Digester;
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.jetspeed.om.common.Support;
27  import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
28  import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
29  import org.apache.jetspeed.om.impl.LanguageImpl;
30  import org.apache.jetspeed.om.impl.ParameterDescriptionImpl;
31  import org.apache.jetspeed.om.impl.PortletDescriptionImpl;
32  import org.apache.jetspeed.om.impl.PortletDisplayNameImpl;
33  import org.apache.jetspeed.om.impl.PortletInitParameterImpl;
34  import org.apache.jetspeed.om.impl.SecurityRoleRefDescriptionImpl;
35  import org.apache.jetspeed.om.impl.SecurityRoleRefImpl;
36  import org.apache.jetspeed.om.impl.UserAttributeImpl;
37  import org.apache.jetspeed.om.portlet.impl.ContentTypeImpl;
38  import org.apache.jetspeed.om.portlet.impl.CustomPortletModeImpl;
39  import org.apache.jetspeed.om.portlet.impl.CustomWindowStateImpl;
40  import org.apache.jetspeed.om.portlet.impl.PortletApplicationDefinitionImpl;
41  import org.apache.jetspeed.tools.pamanager.PortletApplicationException;
42  import org.apache.pluto.om.common.SecurityRoleRef;
43  import org.apache.pluto.om.common.SecurityRoleRefSet;
44  import org.apache.pluto.om.common.SecurityRoleSet;
45  import org.apache.pluto.om.portlet.PortletDefinition;
46  
47  /***
48   * 
49   * Object used to perform operation upon a portlet application descriptor,
50   * usually, portlet.xml.
51   *
52   * @author <a href="mailto:roger.ruttimann@earthlink.net">Roger Ruttimann</a>
53   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a> 
54   * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
55   *  
56   * @version $Id: PortletApplicationDescriptor.java 516448 2007-03-09 16:25:47Z ate $
57   */
58  public class PortletApplicationDescriptor
59  {
60      protected final static Log log = LogFactory.getLog(PortletApplicationDescriptor.class);
61      protected Reader portletXmlReader;
62      private String appName;
63  
64     
65      public PortletApplicationDescriptor(Reader portletXmlReader, String appName)
66      {
67          this.portletXmlReader = portletXmlReader;
68          this.appName = appName;
69      }
70  
71      public MutablePortletApplication createPortletApplication()
72      throws PortletApplicationException
73      {
74          return createPortletApplication(this.getClass().getClassLoader());
75      }
76      
77      /***
78       * Maps the content of the portlet application descriptor into
79       * a new <code>MutablePortletApplication object</code>
80       * 
81       * @return MutablePortletApplication newly created MutablePortletApplication with
82       * all values of the portlet application descriptor mapped into it.
83       */
84      public MutablePortletApplication createPortletApplication(ClassLoader classLoader)
85          throws PortletApplicationException
86      {
87          try
88          {
89              // TODO move config to digester-rules.xml. Example: http://www.onjava.com/pub/a/onjava/2002/10/23/digester.html?page=3
90              Digester digester = new Digester();
91              digester.setValidating(false);
92              digester.setClassLoader(this.getClass().getClassLoader());
93                         
94              // digester.addRuleSet(new PortletApplicationRuleSet(appName));
95              
96              digester.addRule("portlet-app", new PortletApplicationRule(appName));
97              digester.addSetProperties("portlet-app", "id", "applicationIdentifier");
98  
99  
100             digester.addRule("portlet-app/portlet", new PortletRule());
101             
102             digester.addSetProperties("portlet-app/portlet", "id", "portletIdentifier");
103             digester.addBeanPropertySetter("portlet-app/portlet/portlet-name", "name");
104             digester.addBeanPropertySetter("portlet-app/portlet/portlet-class", "className");
105             digester.addBeanPropertySetter("portlet-app/portlet/expiration-cache", "expirationCache");
106             digester.addBeanPropertySetter("portlet-app/portlet/resource-bundle", "resourceBundle");
107             digester.addCallMethod("portlet-app/portlet/supported-locale", "addSupportedLocale", 0);
108             
109             digester.addObjectCreate("portlet-app/portlet/display-name", PortletDisplayNameImpl.class);
110             digester.addSetProperties("portlet-app/portlet/display-name", "xml:lang", "language");
111             digester.addBeanPropertySetter("portlet-app/portlet/display-name", "displayName");
112             digester.addSetNext("portlet-app/portlet/display-name", "addDisplayName");
113 
114             digester.addObjectCreate("portlet-app/portlet/description", PortletDescriptionImpl.class);
115             digester.addSetProperties("portlet-app/portlet/description", "xml:lang", "language");
116             digester.addBeanPropertySetter("portlet-app/portlet/description", "description");
117             digester.addSetNext("portlet-app/portlet/description", "addDescription");
118 
119             digester.addObjectCreate("portlet-app/portlet/init-param", PortletInitParameterImpl.class);
120             digester.addBeanPropertySetter("portlet-app/portlet/init-param/name", "name");
121             digester.addBeanPropertySetter("portlet-app/portlet/init-param/value", "value");
122             digester.addSetNext("portlet-app/portlet/init-param", "addInitParameter");
123 
124             digester.addObjectCreate("portlet-app/portlet/init-param/description", ParameterDescriptionImpl.class);
125             digester.addSetProperties("portlet-app/portlet/init-param/description", "xml:lang", "language");
126             digester.addBeanPropertySetter("portlet-app/portlet/init-param/description", "description");
127             digester.addSetNext("portlet-app/portlet/init-param/description", "addDescription");
128 
129             digester.addObjectCreate("portlet-app/portlet/supports", ContentTypeImpl.class);
130             digester.addBeanPropertySetter("portlet-app/portlet/supports/mime-type", "contentType");
131             digester.addCallMethod("portlet-app/portlet/supports/portlet-mode", "addPortletMode", 0);
132             digester.addSetNext("portlet-app/portlet/supports", "addContentType");
133 
134             digester.addObjectCreate("portlet-app/portlet/portlet-info", LanguageImpl.class);
135             digester.addBeanPropertySetter("portlet-app/portlet/portlet-info/title", "title");
136             digester.addBeanPropertySetter("portlet-app/portlet/portlet-info/short-title", "shortTitle");
137             digester.addCallMethod("portlet-app/portlet/portlet-info/keywords", "setKeywords", 0, new Class[]{String.class});
138             digester.addSetNext("portlet-app/portlet/portlet-info", "addLanguage");
139             
140             digester.addRuleSet(new PortletPreferenceRuleSet());
141 
142             
143             digester.addObjectCreate("portlet-app/user-attribute", UserAttributeImpl.class);
144             digester.addBeanPropertySetter("portlet-app/user-attribute/description", "description");
145             digester.addBeanPropertySetter("portlet-app/user-attribute/name", "name");
146             digester.addSetNext("portlet-app/user-attribute", "addUserAttribute");
147             
148             digester.addObjectCreate("portlet-app/custom-portlet-mode", CustomPortletModeImpl.class);
149             digester.addBeanPropertySetter("portlet-app/custom-portlet-mode/description", "description");
150             // support both custom-portlet-mode/portlet-mode (correct) and custom-portlet-mode/name (incorrect but needed for backwards compatibility)
151             // see: http://issues.apache.org/jira/browse/JS2-611
152             // TODO: when portlet.xml xsd validation is added the custom-portlet-mode/name definition will no longer be needed/supported
153             digester.addBeanPropertySetter("portlet-app/custom-portlet-mode/portlet-mode", "customName");
154             digester.addBeanPropertySetter("portlet-app/custom-portlet-mode/name", "customName");
155             digester.addSetNext("portlet-app/custom-portlet-mode", "addCustomPortletMode");
156             
157             digester.addObjectCreate("portlet-app/custom-window-state", CustomWindowStateImpl.class);
158             digester.addBeanPropertySetter("portlet-app/custom-window-state/description", "description");
159             // support both custom-window-state/window-state (correct) and custom-window-state/name (incorrect but needed for backwards compatibility)
160             // see: http://issues.apache.org/jira/browse/JS2-611
161             // TODO: when portlet.xml xsd validation is added the custom-window-state/name definition will no longer be needed/supported
162             digester.addBeanPropertySetter("portlet-app/custom-window-state/window-state", "customName");
163             digester.addBeanPropertySetter("portlet-app/custom-window-state/name", "customName");
164             digester.addSetNext("portlet-app/custom-window-state", "addCustomWindowState");
165             
166             digester.addObjectCreate("portlet-app/portlet/security-role-ref", SecurityRoleRefImpl.class);
167             digester.addBeanPropertySetter("portlet-app/portlet/security-role-ref/role-name", "roleName");
168             digester.addBeanPropertySetter("portlet-app/portlet/security-role-ref/role-link", "roleLink");
169             digester.addSetNext("portlet-app/portlet/security-role-ref", "addSecurityRoleRef");
170 
171             digester.addObjectCreate("portlet-app/portlet/security-role-ref/description", SecurityRoleRefDescriptionImpl.class);
172             digester.addSetProperties("portlet-app/portlet/security-role-ref/description", "xml:lang", "language");
173             digester.addBeanPropertySetter("portlet-app/portlet/security-role-ref/description", "description");
174             digester.addSetNext("portlet-app/portlet/security-role-ref/description", "addDescription");
175             
176             PortletApplicationDefinitionImpl pd = (PortletApplicationDefinitionImpl) digester.parse(portletXmlReader);
177 
178            
179             if(pd.getApplicationIdentifier() == null)
180             {
181                 pd.setApplicationIdentifier(appName);
182             }
183             
184             Iterator portletDefs = pd.getPortletDefinitions().iterator();
185             while(portletDefs.hasNext())
186             {
187                 Object obj = portletDefs.next();
188                 PortletDefinitionComposite portletDef = (PortletDefinitionComposite) obj;
189                 if(portletDef.getPortletIdentifier() == null)
190                 {
191                     portletDef.setPortletIdentifier(portletDef.getName());
192                 }
193                 
194                 ((Support)obj).postLoad(classLoader);
195             }
196             
197             return pd;
198 
199         }
200         catch (Throwable t)
201         {
202             String msg = "Could not unmarshal portlet.xml. " + t.toString();
203             throw new PortletApplicationException(msg, t);
204         }
205     }
206     
207 
208 
209     /***
210      * Validate a PortletApplicationDefinition tree AFTER its
211      * WebApplicationDefinition has been loaded. Currently, only the security
212      * role references of the portlet definitions are validated:
213      * <ul>
214      * <li>A security role reference should reference a security role through a
215      * roleLink. A warning message is logged if a direct reference is used.
216      * <li>For a security role reference a security role must be defined in the
217      * web application. An error message is logged and a
218      * PortletApplicationException is thrown if not.
219      * </ul>
220      * 
221      * @param app
222      *            The PortletApplicationDefinition to validate
223      * @throws PortletApplicationException
224      */
225     public void validate(MutablePortletApplication app)
226             throws PortletApplicationException
227     {
228         SecurityRoleSet roles = app.getWebApplicationDefinition()
229                 .getSecurityRoles();
230         Collection portlets = app.getPortletDefinitions();
231         Iterator portletIterator = portlets.iterator();
232         while (portletIterator.hasNext())
233         {
234             PortletDefinition portlet = (PortletDefinition) portletIterator
235                     .next();
236             SecurityRoleRefSet securityRoleRefs = portlet
237                     .getInitSecurityRoleRefSet();
238             Iterator roleRefsIterator = securityRoleRefs.iterator();
239             while (roleRefsIterator.hasNext())
240             {
241                 SecurityRoleRef roleRef = (SecurityRoleRef) roleRefsIterator
242                         .next();
243                 String roleName = roleRef.getRoleLink();
244                 if (roleName == null || roleName.length() == 0)
245                 {
246                     roleName = roleRef.getRoleName();
247                 }
248                 if (roles.get(roleName) == null)
249                 {
250                     String errorMsg = "Undefined security role " + roleName
251                             + " referenced from portlet " + portlet.getName();
252                     log.error(errorMsg);
253                     throw new PortletApplicationException(errorMsg);
254                 }
255             }
256         }
257     }
258 }