/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.portal.pluto.om; import java.io.File; import java.io.FileInputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Vector; import java.util.List; import java.util.Arrays; import java.util.zip.ZipFile; import java.util.zip.ZipEntry; import java.net.URL; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import org.apache.avalon.framework.activity.Disposable; import org.apache.avalon.framework.activity.Initializable; import org.apache.avalon.framework.context.Context; import org.apache.avalon.framework.context.ContextException; import org.apache.avalon.framework.context.Contextualizable; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; import org.apache.avalon.framework.service.Serviceable; import org.apache.cocoon.components.source.SourceUtil; import org.apache.cocoon.portal.PortalService; import org.apache.cocoon.servlet.CocoonServlet; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceResolver; import org.apache.excalibur.xml.EntityResolver; import org.apache.pluto.om.common.ObjectID; import org.apache.pluto.om.entity.PortletApplicationEntityList; import org.apache.pluto.om.entity.PortletApplicationEntityListCtrl; import org.apache.pluto.om.portlet.PortletApplicationDefinitionList; import org.apache.pluto.om.portlet.PortletDefinition; import org.exolab.castor.mapping.Mapping; import org.exolab.castor.xml.Unmarshaller; import org.xml.sax.InputSource; /** * * * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a> * * @version CVS $Id$ */ public class PortletDefinitionRegistryImpl extends AbstractLogEnabled implements PortletDefinitionRegistry, Contextualizable, Initializable, Serviceable, Disposable { private static final String WEB_XML = "WEB-INF/web.xml"; private static final String PORTLET_XML = "WEB-INF/portlet.xml"; /** The mapping */ public static final String PORTLET_MAPPING = "resource://org/apache/cocoon/portal/pluto/om/portletdefinitionmapping.xml"; /** The mapping */ public static final String WEBXML_MAPPING = "resource://org/apache/cocoon/portal/pluto/om/servletdefinitionmapping.xml"; /** The context */ protected Context context; /** The service manager */ protected ServiceManager manager; /** The portlet application entity list */ protected PortletApplicationEntityListImpl portletApplicationEntities = new PortletApplicationEntityListImpl(this); // Helper lists and hashtables to access the data as fast as possible // List containing all portlet applications available in the system protected PortletApplicationDefinitionListImpl registry = new PortletApplicationDefinitionListImpl(); /** All portlet definitions, hashed by ObjectId */ protected Map portletsKeyObjectId = new HashMap(); /** Our context name */ protected String contextName; /** The entity resolver */ protected EntityResolver resolver; /** The portal service. */ protected PortalService service; /** * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) */ public void contextualize(Context context) throws ContextException { this.context = context; } /** * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager) */ public void service(ServiceManager manager) throws ServiceException { this.manager = manager; this.resolver = (EntityResolver) this.manager.lookup(EntityResolver.ROLE); this.service = (PortalService) this.manager.lookup(PortalService.ROLE); } /** * @see org.apache.avalon.framework.activity.Disposable#dispose() */ public void dispose() { if ( this.manager != null ) { this.manager.release(this.resolver); this.resolver = null; this.manager.release(this.service); this.service = null; this.manager = null; } this.context = null; } /** * @see org.apache.avalon.framework.activity.Initializable#initialize() */ public void initialize() throws Exception { if ( this.getLogger().isDebugEnabled() ) { this.getLogger().debug("Initializing PortletDefinitionRegistry"); } ServletConfig servletConfig = (ServletConfig) this.context.get(CocoonServlet.CONTEXT_SERVLET_CONFIG); ServletContext servletContext = servletConfig.getServletContext(); SourceResolver resolver = null; try { resolver = (SourceResolver)this.manager.lookup(SourceResolver.ROLE); Mapping mappingPortletXml = new Mapping(); Mapping mappingWebXml = new Mapping(); Source source = null; try { source = resolver.resolveURI(PORTLET_MAPPING); mappingPortletXml.loadMapping(SourceUtil.getInputSource(source)); } finally { resolver.release(source); } try { source = resolver.resolveURI(WEBXML_MAPPING); mappingWebXml.loadMapping(SourceUtil.getInputSource(source)); } finally { resolver.release(source); } String baseWMDir = servletContext.getRealPath(""); if (baseWMDir != null) { // BEGIN PATCH for IBM WebSphere if (baseWMDir.endsWith(File.separator)) { baseWMDir = baseWMDir.substring(0, baseWMDir.length() - 1); } // END PATCH for IBM WebSphere int lastIndex = baseWMDir.lastIndexOf(File.separatorChar); this.contextName = baseWMDir.substring(lastIndex + 1); baseWMDir = baseWMDir.substring(0, lastIndex + 1); if (this.getLogger().isDebugEnabled()) { this.getLogger().debug("servletContext.getRealPath('') =" + servletContext.getRealPath("")); this.getLogger().debug("baseWMDir = " + baseWMDir); } this.load(baseWMDir, mappingPortletXml, mappingWebXml); } else { if (this.getLogger().isWarnEnabled()) { this.getLogger().warn("Only local portlets are supported when deployed as a war"); this.contextName = "local"; loadLocal(mappingPortletXml, mappingWebXml); } } } catch (Exception e) { this.getLogger().error("Error during initialization of registry.", e); } finally { this.manager.release(resolver); } ((PortletApplicationEntityListCtrl)this.portletApplicationEntities).add("cocoon"); } /** * @see org.apache.cocoon.portal.pluto.om.PortletDefinitionRegistry#getPortletApplicationDefinitionList() */ public PortletApplicationDefinitionList getPortletApplicationDefinitionList() { return registry; } /** * @see org.apache.cocoon.portal.pluto.om.PortletDefinitionRegistry#getPortletDefinition(org.apache.pluto.om.common.ObjectID) */ public PortletDefinition getPortletDefinition(ObjectID id) { return (PortletDefinition)portletsKeyObjectId.get(id); } protected void load(String baseWMDir, Mapping portletXMLMapping, Mapping webXMLMapping) throws Exception { File f = new File(baseWMDir); String[] entries = f.list(); List entryList = Arrays.asList(entries); for (int i=0; i<entries.length; i++) { File entry = new File(baseWMDir+entries[i]); if ( this.getLogger().isDebugEnabled() ) { this.getLogger().debug("Searching file: " + entry); } if (entry.isDirectory()) { loadWebApp(baseWMDir, entries[i], portletXMLMapping, webXMLMapping); } else if (entry.isFile()) { String name = entry.getName(); int index = name.lastIndexOf(".war"); if (index > 0 && name.endsWith(".war")) { String webModule = name.substring(0, index); if (!entryList.contains(webModule)) { loadWar(entry, webModule, portletXMLMapping, webXMLMapping); } } } } } private void loadLocal(Mapping portletXMLMapping, Mapping webXMLMapping) throws Exception { ServletConfig config = (ServletConfig)this.context.get(CocoonServlet.CONTEXT_SERVLET_CONFIG); if (config == null) { if (this.getLogger().isDebugEnabled()) { this.getLogger().debug("Unable to locate servlet config"); } return; } ServletContext servletContext = config.getServletContext(); URL url = servletContext.getResource("/" + PORTLET_XML); if (url != null) { InputSource portletSource = new InputSource(url.openStream()); portletSource.setSystemId(url.toExternalForm()); url = servletContext.getResource("/" + WEB_XML); InputSource webSource = null; if (url != null) { webSource = new InputSource(url.openStream()); webSource.setSystemId(url.toExternalForm()); } else { webSource = new InputSource(); webSource.setSystemId("no web.xml!"); } load(portletSource, webSource, this.contextName, portletXMLMapping, webXMLMapping); } } private void loadWar(File warFile, String webModule, Mapping portletXMLMapping, Mapping webXMLMapping) throws Exception { if (this.getLogger().isDebugEnabled()) { this.getLogger().debug("Searching war " + warFile.getName()); } InputSource portletSource; InputSource webSource; try { ZipFile war = new ZipFile(warFile); ZipEntry entry = war.getEntry(PORTLET_XML); if (entry != null) { portletSource = new InputSource(war.getInputStream(entry)); portletSource.setSystemId("/" + PORTLET_XML); entry = war.getEntry(WEB_XML); if (entry != null) { webSource = new InputSource(war.getInputStream(entry)); webSource.setSystemId("/" + WEB_XML); } else { webSource = new InputSource(); webSource.setSystemId("no web.xml!"); } load(portletSource, webSource, webModule, portletXMLMapping, webXMLMapping); } } catch (Exception e) { if (this.getLogger().isDebugEnabled()) { this.getLogger().debug("Unable to inspect war " + warFile.getName() +". " + e. getMessage()); } } } private void loadWebApp(String baseDir, String webModule, Mapping portletXMLMapping, Mapping webXMLMapping) throws Exception { String directory = baseDir + webModule + File.separatorChar + "WEB-INF" + File.separatorChar; if (this.getLogger().isDebugEnabled()) { this.getLogger().debug("Searching in directory: " + directory); } File portletXml = new File(directory + "portlet.xml"); File webXml = new File(directory + "web.xml"); // check for the porlet.xml. If there is no portlet.xml this is not a // portlet application web module if (portletXml.exists()) { // && (webXml.exists())) { if (this.getLogger().isDebugEnabled()) { this.getLogger().debug("Loading the following Portlet Applications XML files..." + portletXml + ", " + webXml); } InputSource portletSource = new InputSource(new FileInputStream(portletXml)); portletSource.setSystemId(portletXml.toURL().toExternalForm()); InputSource webSource = null; if (webXml.exists()) { webSource = new InputSource(new FileInputStream(webXml)); webSource.setSystemId(webXml.toURL().toExternalForm()); } load(portletSource, webSource, webModule, portletXMLMapping, webXMLMapping); } } private void load(InputSource portletXml, InputSource webXml, String webModule, Mapping portletXMLMapping, Mapping webXMLMapping) throws Exception { if (this.getLogger().isDebugEnabled()) { this.getLogger().debug("Loading the following Portlet Applications XML files..." + portletXml.getSystemId() + ", " + webXml.getSystemId()); } Unmarshaller unmarshaller = new Unmarshaller(portletXMLMapping); unmarshaller.setIgnoreExtraElements(true); unmarshaller.setEntityResolver(this.resolver); unmarshaller.setValidation(false); PortletApplicationDefinitionImpl portletApp = (PortletApplicationDefinitionImpl) unmarshaller.unmarshal(portletXml); WebApplicationDefinitionImpl webApp = null; if (webXml.getByteStream() != null) { unmarshaller = new Unmarshaller(webXMLMapping); unmarshaller.setIgnoreExtraElements(true); unmarshaller.setEntityResolver(this.resolver); unmarshaller.setValidation(false); webApp = (WebApplicationDefinitionImpl) unmarshaller.unmarshal(webXml); Vector structure = new Vector(); structure.add(portletApp); structure.add("/" + webModule); webApp.postLoad(structure); // refill structure with necessary information webApp.preBuild(structure); webApp.postBuild(structure); } else { this.getLogger().info("no web.xml..."); Vector structure = new Vector(); structure.add("/" + webModule); structure.add(null); structure.add(null); portletApp.postLoad(structure); portletApp.preBuild(structure); portletApp.postBuild(structure); this.getLogger().debug("portlet.xml loaded"); } this.registry.add(portletApp); this.getLogger().debug("Portlet added to registry"); // fill portletsKeyObjectId final Iterator portlets = portletApp.getPortletDefinitionList().iterator(); while (portlets.hasNext()) { final PortletDefinition portlet = (PortletDefinition) portlets.next(); portletsKeyObjectId.put(portlet.getId(), portlet); if (this.contextName.equals(webModule)) { ((PortletDefinitionImpl) portlet).setLocalPortlet(true); } ((PortletDefinitionImpl) portlet).setPortletClassLoader(Thread.currentThread() .getContextClassLoader()); } } /** * @see org.apache.cocoon.portal.pluto.om.PortletDefinitionRegistry#getPortletApplicationEntityList() */ public PortletApplicationEntityList getPortletApplicationEntityList() { return this.portletApplicationEntities; } /** * @see org.apache.cocoon.portal.pluto.om.PortletDefinitionRegistry#getPortalService() */ public PortalService getPortalService() { return this.service; } }