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.util.descriptor;
018:
019: import java.io.Reader;
020: import java.util.Collection;
021: import java.util.Iterator;
022:
023: import org.apache.commons.digester.Digester;
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.apache.jetspeed.om.common.Support;
027: import org.apache.jetspeed.om.common.portlet.MutablePortletApplication;
028: import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
029: import org.apache.jetspeed.om.impl.LanguageImpl;
030: import org.apache.jetspeed.om.impl.ParameterDescriptionImpl;
031: import org.apache.jetspeed.om.impl.PortletDescriptionImpl;
032: import org.apache.jetspeed.om.impl.PortletDisplayNameImpl;
033: import org.apache.jetspeed.om.impl.PortletInitParameterImpl;
034: import org.apache.jetspeed.om.impl.SecurityRoleRefDescriptionImpl;
035: import org.apache.jetspeed.om.impl.SecurityRoleRefImpl;
036: import org.apache.jetspeed.om.impl.UserAttributeImpl;
037: import org.apache.jetspeed.om.portlet.impl.ContentTypeImpl;
038: import org.apache.jetspeed.om.portlet.impl.CustomPortletModeImpl;
039: import org.apache.jetspeed.om.portlet.impl.CustomWindowStateImpl;
040: import org.apache.jetspeed.om.portlet.impl.PortletApplicationDefinitionImpl;
041: import org.apache.jetspeed.tools.pamanager.PortletApplicationException;
042: import org.apache.pluto.om.common.SecurityRoleRef;
043: import org.apache.pluto.om.common.SecurityRoleRefSet;
044: import org.apache.pluto.om.common.SecurityRoleSet;
045: import org.apache.pluto.om.portlet.PortletDefinition;
046:
047: /**
048: *
049: * Object used to perform operation upon a portlet application descriptor,
050: * usually, portlet.xml.
051: *
052: * @author <a href="mailto:roger.ruttimann@earthlink.net">Roger Ruttimann</a>
053: * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
054: * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
055: *
056: * @version $Id: PortletApplicationDescriptor.java 516448 2007-03-09 16:25:47Z ate $
057: */
058: public class PortletApplicationDescriptor {
059: protected final static Log log = LogFactory
060: .getLog(PortletApplicationDescriptor.class);
061: protected Reader portletXmlReader;
062: private String appName;
063:
064: public PortletApplicationDescriptor(Reader portletXmlReader,
065: String appName) {
066: this .portletXmlReader = portletXmlReader;
067: this .appName = appName;
068: }
069:
070: public MutablePortletApplication createPortletApplication()
071: throws PortletApplicationException {
072: return createPortletApplication(this .getClass()
073: .getClassLoader());
074: }
075:
076: /**
077: * Maps the content of the portlet application descriptor into
078: * a new <code>MutablePortletApplication object</code>
079: *
080: * @return MutablePortletApplication newly created MutablePortletApplication with
081: * all values of the portlet application descriptor mapped into it.
082: */
083: public MutablePortletApplication createPortletApplication(
084: ClassLoader classLoader) throws PortletApplicationException {
085: try {
086: // TODO move config to digester-rules.xml. Example: http://www.onjava.com/pub/a/onjava/2002/10/23/digester.html?page=3
087: Digester digester = new Digester();
088: digester.setValidating(false);
089: digester.setClassLoader(this .getClass().getClassLoader());
090:
091: // digester.addRuleSet(new PortletApplicationRuleSet(appName));
092:
093: digester.addRule("portlet-app", new PortletApplicationRule(
094: appName));
095: digester.addSetProperties("portlet-app", "id",
096: "applicationIdentifier");
097:
098: digester.addRule("portlet-app/portlet", new PortletRule());
099:
100: digester.addSetProperties("portlet-app/portlet", "id",
101: "portletIdentifier");
102: digester.addBeanPropertySetter(
103: "portlet-app/portlet/portlet-name", "name");
104: digester.addBeanPropertySetter(
105: "portlet-app/portlet/portlet-class", "className");
106: digester.addBeanPropertySetter(
107: "portlet-app/portlet/expiration-cache",
108: "expirationCache");
109: digester.addBeanPropertySetter(
110: "portlet-app/portlet/resource-bundle",
111: "resourceBundle");
112: digester.addCallMethod(
113: "portlet-app/portlet/supported-locale",
114: "addSupportedLocale", 0);
115:
116: digester.addObjectCreate(
117: "portlet-app/portlet/display-name",
118: PortletDisplayNameImpl.class);
119: digester.addSetProperties(
120: "portlet-app/portlet/display-name", "xml:lang",
121: "language");
122: digester.addBeanPropertySetter(
123: "portlet-app/portlet/display-name", "displayName");
124: digester.addSetNext("portlet-app/portlet/display-name",
125: "addDisplayName");
126:
127: digester.addObjectCreate("portlet-app/portlet/description",
128: PortletDescriptionImpl.class);
129: digester.addSetProperties(
130: "portlet-app/portlet/description", "xml:lang",
131: "language");
132: digester.addBeanPropertySetter(
133: "portlet-app/portlet/description", "description");
134: digester.addSetNext("portlet-app/portlet/description",
135: "addDescription");
136:
137: digester.addObjectCreate("portlet-app/portlet/init-param",
138: PortletInitParameterImpl.class);
139: digester.addBeanPropertySetter(
140: "portlet-app/portlet/init-param/name", "name");
141: digester.addBeanPropertySetter(
142: "portlet-app/portlet/init-param/value", "value");
143: digester.addSetNext("portlet-app/portlet/init-param",
144: "addInitParameter");
145:
146: digester.addObjectCreate(
147: "portlet-app/portlet/init-param/description",
148: ParameterDescriptionImpl.class);
149: digester.addSetProperties(
150: "portlet-app/portlet/init-param/description",
151: "xml:lang", "language");
152: digester.addBeanPropertySetter(
153: "portlet-app/portlet/init-param/description",
154: "description");
155: digester.addSetNext(
156: "portlet-app/portlet/init-param/description",
157: "addDescription");
158:
159: digester.addObjectCreate("portlet-app/portlet/supports",
160: ContentTypeImpl.class);
161: digester.addBeanPropertySetter(
162: "portlet-app/portlet/supports/mime-type",
163: "contentType");
164: digester.addCallMethod(
165: "portlet-app/portlet/supports/portlet-mode",
166: "addPortletMode", 0);
167: digester.addSetNext("portlet-app/portlet/supports",
168: "addContentType");
169:
170: digester.addObjectCreate(
171: "portlet-app/portlet/portlet-info",
172: LanguageImpl.class);
173: digester.addBeanPropertySetter(
174: "portlet-app/portlet/portlet-info/title", "title");
175: digester.addBeanPropertySetter(
176: "portlet-app/portlet/portlet-info/short-title",
177: "shortTitle");
178: digester.addCallMethod(
179: "portlet-app/portlet/portlet-info/keywords",
180: "setKeywords", 0, new Class[] { String.class });
181: digester.addSetNext("portlet-app/portlet/portlet-info",
182: "addLanguage");
183:
184: digester.addRuleSet(new PortletPreferenceRuleSet());
185:
186: digester.addObjectCreate("portlet-app/user-attribute",
187: UserAttributeImpl.class);
188: digester.addBeanPropertySetter(
189: "portlet-app/user-attribute/description",
190: "description");
191: digester.addBeanPropertySetter(
192: "portlet-app/user-attribute/name", "name");
193: digester.addSetNext("portlet-app/user-attribute",
194: "addUserAttribute");
195:
196: digester.addObjectCreate("portlet-app/custom-portlet-mode",
197: CustomPortletModeImpl.class);
198: digester.addBeanPropertySetter(
199: "portlet-app/custom-portlet-mode/description",
200: "description");
201: // support both custom-portlet-mode/portlet-mode (correct) and custom-portlet-mode/name (incorrect but needed for backwards compatibility)
202: // see: http://issues.apache.org/jira/browse/JS2-611
203: // TODO: when portlet.xml xsd validation is added the custom-portlet-mode/name definition will no longer be needed/supported
204: digester.addBeanPropertySetter(
205: "portlet-app/custom-portlet-mode/portlet-mode",
206: "customName");
207: digester.addBeanPropertySetter(
208: "portlet-app/custom-portlet-mode/name",
209: "customName");
210: digester.addSetNext("portlet-app/custom-portlet-mode",
211: "addCustomPortletMode");
212:
213: digester.addObjectCreate("portlet-app/custom-window-state",
214: CustomWindowStateImpl.class);
215: digester.addBeanPropertySetter(
216: "portlet-app/custom-window-state/description",
217: "description");
218: // support both custom-window-state/window-state (correct) and custom-window-state/name (incorrect but needed for backwards compatibility)
219: // see: http://issues.apache.org/jira/browse/JS2-611
220: // TODO: when portlet.xml xsd validation is added the custom-window-state/name definition will no longer be needed/supported
221: digester.addBeanPropertySetter(
222: "portlet-app/custom-window-state/window-state",
223: "customName");
224: digester.addBeanPropertySetter(
225: "portlet-app/custom-window-state/name",
226: "customName");
227: digester.addSetNext("portlet-app/custom-window-state",
228: "addCustomWindowState");
229:
230: digester.addObjectCreate(
231: "portlet-app/portlet/security-role-ref",
232: SecurityRoleRefImpl.class);
233: digester.addBeanPropertySetter(
234: "portlet-app/portlet/security-role-ref/role-name",
235: "roleName");
236: digester.addBeanPropertySetter(
237: "portlet-app/portlet/security-role-ref/role-link",
238: "roleLink");
239: digester.addSetNext(
240: "portlet-app/portlet/security-role-ref",
241: "addSecurityRoleRef");
242:
243: digester
244: .addObjectCreate(
245: "portlet-app/portlet/security-role-ref/description",
246: SecurityRoleRefDescriptionImpl.class);
247: digester
248: .addSetProperties(
249: "portlet-app/portlet/security-role-ref/description",
250: "xml:lang", "language");
251: digester
252: .addBeanPropertySetter(
253: "portlet-app/portlet/security-role-ref/description",
254: "description");
255: digester
256: .addSetNext(
257: "portlet-app/portlet/security-role-ref/description",
258: "addDescription");
259:
260: PortletApplicationDefinitionImpl pd = (PortletApplicationDefinitionImpl) digester
261: .parse(portletXmlReader);
262:
263: if (pd.getApplicationIdentifier() == null) {
264: pd.setApplicationIdentifier(appName);
265: }
266:
267: Iterator portletDefs = pd.getPortletDefinitions()
268: .iterator();
269: while (portletDefs.hasNext()) {
270: Object obj = portletDefs.next();
271: PortletDefinitionComposite portletDef = (PortletDefinitionComposite) obj;
272: if (portletDef.getPortletIdentifier() == null) {
273: portletDef.setPortletIdentifier(portletDef
274: .getName());
275: }
276:
277: ((Support) obj).postLoad(classLoader);
278: }
279:
280: return pd;
281:
282: } catch (Throwable t) {
283: String msg = "Could not unmarshal portlet.xml. "
284: + t.toString();
285: throw new PortletApplicationException(msg, t);
286: }
287: }
288:
289: /**
290: * Validate a PortletApplicationDefinition tree AFTER its
291: * WebApplicationDefinition has been loaded. Currently, only the security
292: * role references of the portlet definitions are validated:
293: * <ul>
294: * <li>A security role reference should reference a security role through a
295: * roleLink. A warning message is logged if a direct reference is used.
296: * <li>For a security role reference a security role must be defined in the
297: * web application. An error message is logged and a
298: * PortletApplicationException is thrown if not.
299: * </ul>
300: *
301: * @param app
302: * The PortletApplicationDefinition to validate
303: * @throws PortletApplicationException
304: */
305: public void validate(MutablePortletApplication app)
306: throws PortletApplicationException {
307: SecurityRoleSet roles = app.getWebApplicationDefinition()
308: .getSecurityRoles();
309: Collection portlets = app.getPortletDefinitions();
310: Iterator portletIterator = portlets.iterator();
311: while (portletIterator.hasNext()) {
312: PortletDefinition portlet = (PortletDefinition) portletIterator
313: .next();
314: SecurityRoleRefSet securityRoleRefs = portlet
315: .getInitSecurityRoleRefSet();
316: Iterator roleRefsIterator = securityRoleRefs.iterator();
317: while (roleRefsIterator.hasNext()) {
318: SecurityRoleRef roleRef = (SecurityRoleRef) roleRefsIterator
319: .next();
320: String roleName = roleRef.getRoleLink();
321: if (roleName == null || roleName.length() == 0) {
322: roleName = roleRef.getRoleName();
323: }
324: if (roles.get(roleName) == null) {
325: String errorMsg = "Undefined security role "
326: + roleName + " referenced from portlet "
327: + portlet.getName();
328: log.error(errorMsg);
329: throw new PortletApplicationException(errorMsg);
330: }
331: }
332: }
333: }
334: }
|