| /* |
| * 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.pluto.driver.container; |
| |
| import java.io.IOException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.servlet.ServletConfig; |
| import javax.servlet.ServletContext; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.apache.pluto.container.PortletContainerException; |
| import org.apache.pluto.container.PortletWindow; |
| import org.apache.pluto.container.RequestDispatcherService; |
| import org.apache.pluto.container.PortletAppDescriptorService; |
| import org.apache.pluto.container.driver.DriverPortletConfig; |
| import org.apache.pluto.container.driver.DriverPortletContext; |
| import org.apache.pluto.container.driver.PortletContextService; |
| import org.apache.pluto.container.driver.PortletRegistryEvent; |
| import org.apache.pluto.container.driver.PortletRegistryListener; |
| import org.apache.pluto.container.driver.PortletRegistryService; |
| import org.apache.pluto.container.om.portlet.PortletApplicationDefinition; |
| import org.apache.pluto.container.om.portlet.PortletDefinition; |
| import org.apache.pluto.container.util.ClasspathScanner; |
| |
| /** |
| * Manager used to cache the portlet configurations which have |
| * been previously parsed. |
| * |
| * @version 1.0 |
| * @since Sep 20, 2004 |
| */ |
| public class PortletContextManager implements PortletRegistryService, PortletContextService { |
| |
| /** |
| * Logger Instance |
| */ |
| private static final Logger LOG = LoggerFactory.getLogger(PortletContextManager.class); |
| |
| /** |
| * The PortletContext cache map: key is servlet context, and value is the |
| * associated portlet context. |
| */ |
| private Map<String,DriverPortletContext> portletContexts = new HashMap<String,DriverPortletContext>(); |
| |
| /** |
| * List of application id resolvers. * |
| */ |
| private static final List<ApplicationIdResolver> APP_ID_RESOLVERS = new ArrayList<ApplicationIdResolver>(); |
| |
| |
| // Private Member Variables ------------------------------------------------ |
| |
| /** |
| * The PortletContext cache map: key is servlet context, and value is the |
| * associated portlet context. |
| */ |
| private final Map<String,DriverPortletConfig> portletConfigs = new HashMap<String,DriverPortletConfig>(); |
| |
| |
| /** |
| * The registered listeners that should be notified upon |
| * registry events. |
| */ |
| private final List<PortletRegistryListener> registryListeners = new ArrayList<PortletRegistryListener>(); |
| |
| /** |
| * The classloader for the portal, key is portletWindow and value is the classloader. |
| */ |
| private final Map<String,ClassLoader> classLoaders = new HashMap<String,ClassLoader>(); |
| |
| private final RequestDispatcherService rdService; |
| private final PortletDescriptorRegistry portletRegistry; |
| |
| // Constructor ------------------------------------------------------------- |
| |
| public PortletContextManager(RequestDispatcherService rdService, PortletAppDescriptorService portletAppDescriptorService) { |
| this.rdService = rdService; |
| portletRegistry = new PortletDescriptorRegistry(portletAppDescriptorService); |
| } |
| |
| |
| // Public Methods ---------------------------------------------------------- |
| |
| /** |
| * Retrieves the PortletContext associated with the given ServletContext. |
| * If one does not exist, it is created. |
| * |
| * @param config the servlet config. |
| * @return the InternalPortletContext associated with the ServletContext. |
| * @throws PortletContainerException |
| */ |
| public String register(ServletConfig config) throws PortletContainerException { |
| ServletContext servletContext = config.getServletContext(); |
| String contextPath = getContextPath(servletContext); |
| if (!portletContexts.containsKey(contextPath)) { |
| |
| PortletApplicationDefinition portletApp = portletRegistry.getPortletAppDD(servletContext, contextPath, contextPath); |
| |
| DriverPortletContext portletContext = new DriverPortletContextImpl(servletContext, portletApp, rdService); |
| |
| portletContexts.put(contextPath, portletContext); |
| |
| fireRegistered(portletContext); |
| |
| if (LOG.isInfoEnabled()) { |
| LOG.info("Registered portlet application for context '" + contextPath + "'"); |
| |
| LOG.info("Registering "+portletApp.getPortlets().size()+" portlets for context /"+portletContext.getApplicationName()); |
| } |
| |
| classLoaders.put(portletApp.getName(), Thread.currentThread().getContextClassLoader()); |
| for (PortletDefinition portlet: portletApp.getPortlets()) { |
| String appName = portletContext.getApplicationName(); |
| if (appName == null) { |
| throw new PortletContainerException("Portlet application name should not be null."); |
| } |
| portletConfigs.put( |
| portletContext.getApplicationName() + "/" + portlet.getPortletName(), |
| new DriverPortletConfigImpl(portletContext, portlet) |
| ); |
| } |
| } else { |
| if (LOG.isInfoEnabled()) { |
| LOG.info("Portlet application for context '" + contextPath + "' already registered."); |
| } |
| } |
| return contextPath; |
| } |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletContextService#unregister(org.apache.pluto.container.driver.DriverPortletContext) |
| */ |
| public void unregister(DriverPortletContext context) { |
| portletContexts.remove(context.getApplicationName()); |
| classLoaders.remove(context.getApplicationName()); |
| Iterator<String> configs = portletConfigs.keySet().iterator(); |
| while (configs.hasNext()) { |
| String key = configs.next(); |
| if (key.startsWith(context.getApplicationName() + "/")) { |
| configs.remove(); |
| } |
| } |
| fireRemoved(context); |
| } |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletRegistryService#getRegisteredPortletApplicationNames() |
| */ |
| public Iterator<String> getRegisteredPortletApplicationNames() { |
| return new HashSet<String>(portletContexts.keySet()).iterator(); |
| } |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletContextService#getPortletContexts() |
| */ |
| public Iterator<DriverPortletContext> getPortletContexts() { |
| return new HashSet<DriverPortletContext>(portletContexts.values()).iterator(); |
| } |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletContextService#getPortletContext(java.lang.String) |
| */ |
| public DriverPortletContext getPortletContext(String applicationName) { |
| return portletContexts.get(applicationName); |
| } |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletContextService#getPortletContext(org.apache.pluto.container.PortletWindow) |
| */ |
| public DriverPortletContext getPortletContext(PortletWindow portletWindow) throws PortletContainerException { |
| return portletContexts.get(portletWindow.getPortletDefinition().getApplication().getName()); |
| } |
| |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletContextService#getPortletConfig(java.lang.String, java.lang.String) |
| */ |
| public DriverPortletConfig getPortletConfig(String applicationName, String portletName) throws PortletContainerException { |
| DriverPortletConfig ipc = portletConfigs.get(applicationName + "/" + portletName); |
| if (ipc != null) { |
| return ipc; |
| } |
| String msg = "Unable to locate portlet config [applicationName="+applicationName+"]/["+portletName+"]."; |
| LOG.warn(msg); |
| throw new PortletContainerException(msg); |
| } |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletRegistryService#getPortlet(java.lang.String, java.lang.String) |
| */ |
| public PortletDefinition getPortlet(String applicationName, String portletName) throws PortletContainerException { |
| DriverPortletConfig ipc = portletConfigs.get(applicationName + "/" + portletName); |
| if (ipc != null) { |
| return ipc.getPortletDefinition(); |
| } |
| String msg = "Unable to retrieve portlet: '"+applicationName+"/"+portletName+"'"; |
| LOG.warn(msg); |
| throw new PortletContainerException(msg); |
| } |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletRegistryService#getPortletApplication(java.lang.String) |
| */ |
| public PortletApplicationDefinition getPortletApplication(String applicationName) throws PortletContainerException { |
| DriverPortletContext ipc = portletContexts.get(applicationName); |
| if (ipc != null) { |
| return ipc.getPortletApplicationDefinition(); |
| } |
| String msg = "Unable to retrieve portlet application: '"+applicationName+"'"; |
| LOG.warn(msg); |
| throw new PortletContainerException(msg); |
| } |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletContextService#getClassLoader(java.lang.String) |
| */ |
| public ClassLoader getClassLoader(String applicationName){ |
| return classLoaders.get(applicationName); |
| } |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletRegistryService#addPortletRegistryListener(org.apache.pluto.container.driver.PortletRegistryListener) |
| */ |
| public void addPortletRegistryListener(PortletRegistryListener listener) { |
| registryListeners.add(listener); |
| } |
| |
| /** |
| * @see org.apache.pluto.container.driver.PortletRegistryService#removePortletRegistryListener(org.apache.pluto.container.driver.PortletRegistryListener) |
| */ |
| public void removePortletRegistryListener(PortletRegistryListener listener) { |
| registryListeners.remove(listener); |
| } |
| |
| private void fireRegistered(DriverPortletContext context) { |
| PortletRegistryEvent event = new PortletRegistryEvent(); |
| event.setPortletApplication(context.getPortletApplicationDefinition()); |
| |
| for (PortletRegistryListener l: registryListeners) { |
| l.portletApplicationRegistered(event); |
| } |
| LOG.info("Portlet Context '" + context.getApplicationName() + "' registered."); |
| } |
| |
| private void fireRemoved(DriverPortletContext context) { |
| PortletRegistryEvent event = new PortletRegistryEvent(); |
| event.setPortletApplication(context.getPortletApplicationDefinition()); |
| |
| for (PortletRegistryListener l: registryListeners) { |
| l.portletApplicationRemoved(event); |
| } |
| |
| LOG.info("Portlet Context '" + context.getApplicationName() + "' removed."); |
| } |
| |
| // |
| // Utility |
| |
| /** |
| * Retrieve the servlet context of the portlet web app. |
| * @param portalContext The servlet context of the portal web app. |
| * @param portletContextPath The context path of the portlet web app. |
| * The given path must be begin with "/" (see {@link ServletContext#getContext(String)}). |
| * @return The servlet context of the portlet web app. |
| * @throws PortletContainerException if the servlet context cannot be |
| * retrieved for the given context path |
| */ |
| public static ServletContext getPortletContext(ServletContext portalContext, |
| String portletContextPath) throws PortletContainerException { |
| if (Configuration.preventUnecessaryCrossContext()) { |
| String portalPath = getContextPath(portalContext); |
| if (portalPath.equals(portletContextPath)) { |
| return portalContext; |
| } |
| } |
| |
| //Hack to deal with inconsistence in root context handling between |
| //ServletContext.getContextPath and ServletContext.getContext |
| if ("".equals(portletContextPath)) { |
| portletContextPath = "/"; |
| } |
| ServletContext portletAppCtx = portalContext.getContext(portletContextPath); |
| if (portletAppCtx == null) { |
| final String msg = "Unable to obtain the servlet context for the " + |
| "portlet app context path [" + portletContextPath + "]. Make " + |
| "sure that the portlet app has been deployed and that cross " + |
| "context support is enabled for the portal app."; |
| throw new PortletContainerException(msg); |
| } |
| return portletAppCtx; |
| } |
| |
| /** |
| * Servlet 2.5 ServletContext.getContextPath() method. |
| */ |
| private static Method contextPathGetter; |
| |
| static { |
| try { |
| contextPathGetter = ServletContext.class.getMethod("getContextPath", (Class[])null); |
| } |
| catch (NoSuchMethodException e) { |
| LOG.warn("Servlet 2.4 or below detected. Unable to find getContextPath on ServletContext."); |
| } |
| } |
| |
| protected static String getContextPath(ServletContext context) { |
| String contextPath = null; |
| if (contextPathGetter != null) { |
| try { |
| contextPath = (String) contextPathGetter.invoke(context, (Object[])null); |
| } catch (Exception e) { |
| LOG.warn("Unable to directly retrieve context path from ServletContext. Computing. . . "); |
| } |
| } |
| |
| if (contextPath == null) { |
| contextPath = computeContextPath(context); |
| } |
| |
| return contextPath; |
| } |
| |
| |
| @SuppressWarnings("unchecked") |
| protected static String computeContextPath(ServletContext context) { |
| if (APP_ID_RESOLVERS.size() < 1) { |
| List<Class> classes = null; |
| try { |
| classes = ClasspathScanner.findConfiguredImplementations(ApplicationIdResolver.class); |
| } catch (IOException e) { |
| throw new RuntimeException("Unable to find any ApplicationIdResolvers"); |
| } |
| for (Class c : classes) { |
| try { |
| APP_ID_RESOLVERS.add((ApplicationIdResolver)c.newInstance()); |
| } catch (Exception e) { |
| LOG.warn("Unable to instantiate ApplicationIdResolver for class " + c.getName()); |
| } |
| } |
| if (LOG.isInfoEnabled()) { |
| LOG.info("Found " + APP_ID_RESOLVERS.size() + " application id resolvers."); |
| } |
| } |
| |
| String path = null; |
| int authority = Integer.MAX_VALUE; |
| |
| for (ApplicationIdResolver resolver : APP_ID_RESOLVERS) { |
| if (resolver.getAuthority() < authority || path == null) { |
| authority = resolver.getAuthority(); |
| String temp = resolver.resolveApplicationId(context); |
| if (temp != null) { |
| path = temp; |
| } |
| } |
| } |
| |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("Resolved application id '" + path + "' with authority " + authority); |
| } |
| return path; |
| } |
| |
| } |