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.cocoon.portal.pluto.om;
018:
019: import java.io.File;
020: import java.io.FileInputStream;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.Map;
024: import java.util.Vector;
025: import java.util.List;
026: import java.util.Arrays;
027: import java.util.zip.ZipFile;
028: import java.util.zip.ZipEntry;
029: import java.net.URL;
030:
031: import javax.servlet.ServletConfig;
032: import javax.servlet.ServletContext;
033:
034: import org.apache.avalon.framework.activity.Disposable;
035: import org.apache.avalon.framework.activity.Initializable;
036: import org.apache.avalon.framework.context.Context;
037: import org.apache.avalon.framework.context.ContextException;
038: import org.apache.avalon.framework.context.Contextualizable;
039: import org.apache.avalon.framework.logger.AbstractLogEnabled;
040: import org.apache.avalon.framework.service.ServiceException;
041: import org.apache.avalon.framework.service.ServiceManager;
042: import org.apache.avalon.framework.service.Serviceable;
043: import org.apache.cocoon.components.source.SourceUtil;
044: import org.apache.cocoon.portal.PortalService;
045: import org.apache.cocoon.servlet.CocoonServlet;
046: import org.apache.excalibur.source.Source;
047: import org.apache.excalibur.source.SourceResolver;
048: import org.apache.excalibur.xml.EntityResolver;
049: import org.apache.pluto.om.common.ObjectID;
050: import org.apache.pluto.om.entity.PortletApplicationEntityList;
051: import org.apache.pluto.om.entity.PortletApplicationEntityListCtrl;
052: import org.apache.pluto.om.portlet.PortletApplicationDefinitionList;
053: import org.apache.pluto.om.portlet.PortletDefinition;
054: import org.exolab.castor.mapping.Mapping;
055: import org.exolab.castor.xml.Unmarshaller;
056: import org.xml.sax.InputSource;
057:
058: /**
059: *
060: *
061: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
062: *
063: * @version CVS $Id: PortletDefinitionRegistryImpl.java 433543 2006-08-22 06:22:54Z crossley $
064: */
065: public class PortletDefinitionRegistryImpl extends AbstractLogEnabled
066: implements PortletDefinitionRegistry, Contextualizable,
067: Initializable, Serviceable, Disposable {
068:
069: private static final String WEB_XML = "WEB-INF/web.xml";
070: private static final String PORTLET_XML = "WEB-INF/portlet.xml";
071:
072: /** The mapping */
073: public static final String PORTLET_MAPPING = "resource://org/apache/cocoon/portal/pluto/om/portletdefinitionmapping.xml";
074:
075: /** The mapping */
076: public static final String WEBXML_MAPPING = "resource://org/apache/cocoon/portal/pluto/om/servletdefinitionmapping.xml";
077:
078: /** The context */
079: protected Context context;
080:
081: /** The service manager */
082: protected ServiceManager manager;
083:
084: /** The portlet application entity list */
085: protected PortletApplicationEntityListImpl portletApplicationEntities = new PortletApplicationEntityListImpl(
086: this );
087:
088: // Helper lists and hashtables to access the data as fast as possible
089: // List containing all portlet applications available in the system
090: protected PortletApplicationDefinitionListImpl registry = new PortletApplicationDefinitionListImpl();
091: /** All portlet definitions, hashed by ObjectId */
092: protected Map portletsKeyObjectId = new HashMap();
093: /** Our context name */
094: protected String contextName;
095:
096: /** The entity resolver */
097: protected EntityResolver resolver;
098:
099: /** The portal service. */
100: protected PortalService service;
101:
102: /**
103: * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
104: */
105: public void contextualize(Context context) throws ContextException {
106: this .context = context;
107: }
108:
109: /**
110: * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
111: */
112: public void service(ServiceManager manager) throws ServiceException {
113: this .manager = manager;
114: this .resolver = (EntityResolver) this .manager
115: .lookup(EntityResolver.ROLE);
116: this .service = (PortalService) this .manager
117: .lookup(PortalService.ROLE);
118: }
119:
120: /**
121: * @see org.apache.avalon.framework.activity.Disposable#dispose()
122: */
123: public void dispose() {
124: if (this .manager != null) {
125: this .manager.release(this .resolver);
126: this .resolver = null;
127: this .manager.release(this .service);
128: this .service = null;
129: this .manager = null;
130: }
131: this .context = null;
132: }
133:
134: /**
135: * @see org.apache.avalon.framework.activity.Initializable#initialize()
136: */
137: public void initialize() throws Exception {
138: if (this .getLogger().isDebugEnabled()) {
139: this .getLogger().debug(
140: "Initializing PortletDefinitionRegistry");
141: }
142: ServletConfig servletConfig = (ServletConfig) this .context
143: .get(CocoonServlet.CONTEXT_SERVLET_CONFIG);
144:
145: ServletContext servletContext = servletConfig
146: .getServletContext();
147:
148: SourceResolver resolver = null;
149:
150: try {
151: resolver = (SourceResolver) this .manager
152: .lookup(SourceResolver.ROLE);
153: Mapping mappingPortletXml = new Mapping();
154: Mapping mappingWebXml = new Mapping();
155: Source source = null;
156: try {
157: source = resolver.resolveURI(PORTLET_MAPPING);
158:
159: mappingPortletXml.loadMapping(SourceUtil
160: .getInputSource(source));
161: } finally {
162: resolver.release(source);
163: }
164: try {
165: source = resolver.resolveURI(WEBXML_MAPPING);
166:
167: mappingWebXml.loadMapping(SourceUtil
168: .getInputSource(source));
169: } finally {
170: resolver.release(source);
171: }
172:
173: String baseWMDir = servletContext.getRealPath("");
174:
175: if (baseWMDir != null) {
176: // BEGIN PATCH for IBM WebSphere
177: if (baseWMDir.endsWith(File.separator)) {
178: baseWMDir = baseWMDir.substring(0, baseWMDir
179: .length() - 1);
180: }
181: // END PATCH for IBM WebSphere
182: int lastIndex = baseWMDir
183: .lastIndexOf(File.separatorChar);
184: this .contextName = baseWMDir.substring(lastIndex + 1);
185: baseWMDir = baseWMDir.substring(0, lastIndex + 1);
186: if (this .getLogger().isDebugEnabled()) {
187: this .getLogger().debug(
188: "servletContext.getRealPath('') ="
189: + servletContext.getRealPath(""));
190: this .getLogger().debug("baseWMDir = " + baseWMDir);
191: }
192: this .load(baseWMDir, mappingPortletXml, mappingWebXml);
193: } else {
194: if (this .getLogger().isWarnEnabled()) {
195: this
196: .getLogger()
197: .warn(
198: "Only local portlets are supported when deployed as a war");
199: this .contextName = "local";
200: loadLocal(mappingPortletXml, mappingWebXml);
201: }
202: }
203:
204: } catch (Exception e) {
205: this .getLogger().error(
206: "Error during initialization of registry.", e);
207: } finally {
208: this .manager.release(resolver);
209: }
210:
211: ((PortletApplicationEntityListCtrl) this .portletApplicationEntities)
212: .add("cocoon");
213: }
214:
215: /**
216: * @see org.apache.cocoon.portal.pluto.om.PortletDefinitionRegistry#getPortletApplicationDefinitionList()
217: */
218: public PortletApplicationDefinitionList getPortletApplicationDefinitionList() {
219: return registry;
220: }
221:
222: /**
223: * @see org.apache.cocoon.portal.pluto.om.PortletDefinitionRegistry#getPortletDefinition(org.apache.pluto.om.common.ObjectID)
224: */
225: public PortletDefinition getPortletDefinition(ObjectID id) {
226: return (PortletDefinition) portletsKeyObjectId.get(id);
227: }
228:
229: protected void load(String baseWMDir, Mapping portletXMLMapping,
230: Mapping webXMLMapping) throws Exception {
231: File f = new File(baseWMDir);
232: String[] entries = f.list();
233: List entryList = Arrays.asList(entries);
234: for (int i = 0; i < entries.length; i++) {
235: File entry = new File(baseWMDir + entries[i]);
236: if (this .getLogger().isDebugEnabled()) {
237: this .getLogger().debug("Searching file: " + entry);
238: }
239: if (entry.isDirectory()) {
240: loadWebApp(baseWMDir, entries[i], portletXMLMapping,
241: webXMLMapping);
242: } else if (entry.isFile()) {
243: String name = entry.getName();
244: int index = name.lastIndexOf(".war");
245: if (index > 0 && name.endsWith(".war")) {
246: String webModule = name.substring(0, index);
247: if (!entryList.contains(webModule)) {
248: loadWar(entry, webModule, portletXMLMapping,
249: webXMLMapping);
250: }
251: }
252: }
253: }
254: }
255:
256: private void loadLocal(Mapping portletXMLMapping,
257: Mapping webXMLMapping) throws Exception {
258: ServletConfig config = (ServletConfig) this .context
259: .get(CocoonServlet.CONTEXT_SERVLET_CONFIG);
260: if (config == null) {
261: if (this .getLogger().isDebugEnabled()) {
262: this .getLogger().debug(
263: "Unable to locate servlet config");
264: }
265: return;
266: }
267: ServletContext servletContext = config.getServletContext();
268: URL url = servletContext.getResource("/" + PORTLET_XML);
269: if (url != null) {
270: InputSource portletSource = new InputSource(url
271: .openStream());
272: portletSource.setSystemId(url.toExternalForm());
273:
274: url = servletContext.getResource("/" + WEB_XML);
275: InputSource webSource = null;
276: if (url != null) {
277: webSource = new InputSource(url.openStream());
278: webSource.setSystemId(url.toExternalForm());
279: } else {
280: webSource = new InputSource();
281: webSource.setSystemId("no web.xml!");
282: }
283:
284: load(portletSource, webSource, this .contextName,
285: portletXMLMapping, webXMLMapping);
286: }
287: }
288:
289: private void loadWar(File warFile, String webModule,
290: Mapping portletXMLMapping, Mapping webXMLMapping)
291: throws Exception {
292: if (this .getLogger().isDebugEnabled()) {
293: this .getLogger()
294: .debug("Searching war " + warFile.getName());
295: }
296: InputSource portletSource;
297: InputSource webSource;
298: try {
299: ZipFile war = new ZipFile(warFile);
300: ZipEntry entry = war.getEntry(PORTLET_XML);
301: if (entry != null) {
302: portletSource = new InputSource(war
303: .getInputStream(entry));
304: portletSource.setSystemId("/" + PORTLET_XML);
305: entry = war.getEntry(WEB_XML);
306: if (entry != null) {
307: webSource = new InputSource(war
308: .getInputStream(entry));
309: webSource.setSystemId("/" + WEB_XML);
310: } else {
311: webSource = new InputSource();
312: webSource.setSystemId("no web.xml!");
313: }
314: load(portletSource, webSource, webModule,
315: portletXMLMapping, webXMLMapping);
316: }
317: } catch (Exception e) {
318: if (this .getLogger().isDebugEnabled()) {
319: this .getLogger().debug(
320: "Unable to inspect war " + warFile.getName()
321: + ". " + e.getMessage());
322: }
323: }
324: }
325:
326: private void loadWebApp(String baseDir, String webModule,
327: Mapping portletXMLMapping, Mapping webXMLMapping)
328: throws Exception {
329: String directory = baseDir + webModule + File.separatorChar
330: + "WEB-INF" + File.separatorChar;
331: if (this .getLogger().isDebugEnabled()) {
332: this .getLogger().debug(
333: "Searching in directory: " + directory);
334: }
335:
336: File portletXml = new File(directory + "portlet.xml");
337: File webXml = new File(directory + "web.xml");
338:
339: // check for the porlet.xml. If there is no portlet.xml this is not a
340: // portlet application web module
341: if (portletXml.exists()) { // && (webXml.exists())) {
342: if (this .getLogger().isDebugEnabled()) {
343: this .getLogger().debug(
344: "Loading the following Portlet Applications XML files..."
345: + portletXml + ", " + webXml);
346: }
347:
348: InputSource portletSource = new InputSource(
349: new FileInputStream(portletXml));
350: portletSource.setSystemId(portletXml.toURL()
351: .toExternalForm());
352: InputSource webSource = null;
353:
354: if (webXml.exists()) {
355: webSource = new InputSource(new FileInputStream(webXml));
356: webSource.setSystemId(webXml.toURL().toExternalForm());
357: }
358:
359: load(portletSource, webSource, webModule,
360: portletXMLMapping, webXMLMapping);
361: }
362: }
363:
364: private void load(InputSource portletXml, InputSource webXml,
365: String webModule, Mapping portletXMLMapping,
366: Mapping webXMLMapping) throws Exception {
367: if (this .getLogger().isDebugEnabled()) {
368: this .getLogger().debug(
369: "Loading the following Portlet Applications XML files..."
370: + portletXml.getSystemId() + ", "
371: + webXml.getSystemId());
372: }
373:
374: Unmarshaller unmarshaller = new Unmarshaller(portletXMLMapping);
375: unmarshaller.setIgnoreExtraElements(true);
376: unmarshaller.setEntityResolver(this .resolver);
377: unmarshaller.setValidation(false);
378: PortletApplicationDefinitionImpl portletApp = (PortletApplicationDefinitionImpl) unmarshaller
379: .unmarshal(portletXml);
380:
381: WebApplicationDefinitionImpl webApp = null;
382:
383: if (webXml.getByteStream() != null) {
384: unmarshaller = new Unmarshaller(webXMLMapping);
385: unmarshaller.setIgnoreExtraElements(true);
386: unmarshaller.setEntityResolver(this .resolver);
387: unmarshaller.setValidation(false);
388: webApp = (WebApplicationDefinitionImpl) unmarshaller
389: .unmarshal(webXml);
390:
391: Vector structure = new Vector();
392: structure.add(portletApp);
393: structure.add("/" + webModule);
394:
395: webApp.postLoad(structure);
396:
397: // refill structure with necessary information
398: webApp.preBuild(structure);
399:
400: webApp.postBuild(structure);
401: } else {
402: this .getLogger().info("no web.xml...");
403:
404: Vector structure = new Vector();
405: structure.add("/" + webModule);
406: structure.add(null);
407: structure.add(null);
408:
409: portletApp.postLoad(structure);
410:
411: portletApp.preBuild(structure);
412:
413: portletApp.postBuild(structure);
414:
415: this .getLogger().debug("portlet.xml loaded");
416: }
417:
418: this .registry.add(portletApp);
419:
420: this .getLogger().debug("Portlet added to registry");
421:
422: // fill portletsKeyObjectId
423: final Iterator portlets = portletApp.getPortletDefinitionList()
424: .iterator();
425: while (portlets.hasNext()) {
426: final PortletDefinition portlet = (PortletDefinition) portlets
427: .next();
428: portletsKeyObjectId.put(portlet.getId(), portlet);
429:
430: if (this .contextName.equals(webModule)) {
431: ((PortletDefinitionImpl) portlet).setLocalPortlet(true);
432: }
433: ((PortletDefinitionImpl) portlet)
434: .setPortletClassLoader(Thread.currentThread()
435: .getContextClassLoader());
436: }
437: }
438:
439: /**
440: * @see org.apache.cocoon.portal.pluto.om.PortletDefinitionRegistry#getPortletApplicationEntityList()
441: */
442: public PortletApplicationEntityList getPortletApplicationEntityList() {
443: return this .portletApplicationEntities;
444: }
445:
446: /**
447: * @see org.apache.cocoon.portal.pluto.om.PortletDefinitionRegistry#getPortalService()
448: */
449: public PortalService getPortalService() {
450: return this.service;
451: }
452:
453: }
|