blob: efaa098fffc2144a3f9bf34fed6c01f88fdd3944 [file] [log] [blame]
/*
* 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;
}
}