[exo-jcr-commits] exo-jcr SVN: r207 - in kernel/trunk/container/src: main/java/org/exoplatform/container and 5 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Mon Oct 5 06:19:24 EDT 2009


Author: nfilotto
Date: 2009-10-05 06:19:24 -0400 (Mon, 05 Oct 2009)
New Revision: 207

Added:
   kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainerClassLoader.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainerContext.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/UnifiedClassLoader.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/WebAppInitContext.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/definition/
   kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerConfig.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerDefinition.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerDefinitionPlugin.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/web/
   kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractFilter.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractHttpServlet.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractHttpSessionListener.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/web/PortalContainerConfigOwner.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/web/PortalContainerCreator.java
   kernel/trunk/container/src/test/java/org/exoplatform/container/TestPortalContainerInitTaskContextComparator.java
   kernel/trunk/container/src/test/java/org/exoplatform/container/TestUnifiedClassLoader.java
   kernel/trunk/container/src/test/java/org/exoplatform/container/TestWebAppInitContextComparator.java
Modified:
   kernel/trunk/container/src/main/java/conf/configuration.xml
   kernel/trunk/container/src/main/java/org/exoplatform/container/ExoContainerContext.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainer.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/RootContainer.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/configuration/ConfigurationManagerImpl.java
   kernel/trunk/container/src/main/java/org/exoplatform/container/util/ContainerUtil.java
Log:
EXOJCR-166: Support separated ear delivery

Modified: kernel/trunk/container/src/main/java/conf/configuration.xml
===================================================================
--- kernel/trunk/container/src/main/java/conf/configuration.xml	2009-10-04 19:39:27 UTC (rev 206)
+++ kernel/trunk/container/src/main/java/conf/configuration.xml	2009-10-05 10:19:24 UTC (rev 207)
@@ -43,4 +43,8 @@
          </properties-param>
       </init-params>
    </component>
+
+	<component>
+		<type>org.exoplatform.container.definition.PortalContainerConfig</type>
+	</component>	  
 </configuration>

Modified: kernel/trunk/container/src/main/java/org/exoplatform/container/ExoContainerContext.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/ExoContainerContext.java	2009-10-04 19:39:27 UTC (rev 206)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/ExoContainerContext.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -55,6 +55,45 @@
       return container;
    }
 
+   /**
+    * @return if the embedded container is a {@link PortalContainer}, it will return the name the
+    * portal container otherwise it will return <code>null</code>
+    */
+   public String getPortalContainerName()
+   {
+      if (container instanceof PortalContainer)
+      {
+         return ((PortalContainer)container).getName();
+      }
+      return null;
+   }
+
+   /**
+    * @return if the embedded container is a {@link PortalContainer}, it will return the name 
+    * of the rest context name related to the portal container otherwise it will return the default name
+    */
+   public String getRestContextName()
+   {
+      if (container instanceof PortalContainer)
+      {
+         return ((PortalContainer)container).getRestContextName();
+      }
+      return PortalContainer.DEFAULT_REST_CONTEXT_NAME;
+   }
+
+   /**
+    * @return if the embedded container is a {@link PortalContainer}, it will return the name 
+    * of the realm name related to the portal container otherwise it will return the default name
+    */
+   public String getRealmName()
+   {
+      if (container instanceof PortalContainer)
+      {
+         return ((PortalContainer)container).getRealmName();
+      }
+      return PortalContainer.DEFAULT_REALM_NAME;
+   }
+
    public String getName()
    {
       return name;

Modified: kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainer.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainer.java	2009-10-04 19:39:27 UTC (rev 206)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainer.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -18,6 +18,8 @@
  */
 package org.exoplatform.container;
 
+import org.exoplatform.container.RootContainer.PortalContainerInitTask;
+import org.exoplatform.container.definition.PortalContainerConfig;
 import org.exoplatform.container.jmx.MX4JComponentAdapterFactory;
 import org.exoplatform.container.xml.PortalContainerInfo;
 import org.exoplatform.management.annotations.Managed;
@@ -25,12 +27,17 @@
 import org.exoplatform.management.jmx.annotations.NameTemplate;
 import org.exoplatform.management.jmx.annotations.NamingContext;
 import org.exoplatform.management.jmx.annotations.Property;
-import org.picocontainer.ComponentAdapter;
-import org.picocontainer.PicoContainer;
-import org.picocontainer.PicoException;
-import org.picocontainer.defaults.DuplicateComponentKeyRegistrationException;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
 
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 
 import javax.servlet.ServletContext;
 
@@ -45,21 +52,94 @@
 {
 
    /**
+    * Logger
+    */
+   private static final Log log = ExoLogger.getLogger(PortalContainer.class);
+
+   /**
     * The default name of the portal container
     */
-   private static final String DEFAULT_PORTAL_CONTAINER_NAME = "portal";
+   public static final String DEFAULT_PORTAL_CONTAINER_NAME;
 
-   private static ThreadLocal currentContainer_ = new ThreadLocal();
+   /**
+    * The default name of a the {@link ServletContext} of the rest web application
+    */
+   public static final String DEFAULT_REST_CONTEXT_NAME;
 
-   private boolean started_ = false;
+   /**
+    * The default name of a the realm
+    */
+   public static final String DEFAULT_REALM_NAME;
 
+   /**
+    * The configuration of the portal containers
+    */
+   private static final PortalContainerConfig CONFIG;
+   static
+   {
+      ExoContainer top = ExoContainerContext.getTopContainer();
+      CONFIG = top instanceof RootContainer ? ((RootContainer)top).getPortalContainerConfig() : null;
+      if (CONFIG == null)
+      {
+         DEFAULT_PORTAL_CONTAINER_NAME = PortalContainerConfig.DEFAULT_PORTAL_CONTAINER_NAME;
+         DEFAULT_REST_CONTEXT_NAME = PortalContainerConfig.DEFAULT_REST_CONTEXT_NAME;
+         DEFAULT_REALM_NAME = PortalContainerConfig.DEFAULT_REALM_NAME;
+      }
+      else
+      {
+         DEFAULT_PORTAL_CONTAINER_NAME = CONFIG.getDefaultPortalContainer();
+         DEFAULT_REST_CONTEXT_NAME = CONFIG.getDefaultRestContext();
+         DEFAULT_REALM_NAME = CONFIG.getDefaultRealmName();
+      }
+   }
+
+   private static ThreadLocal<PortalContainer> currentContainer_ = new ThreadLocal<PortalContainer>();
+
+   private volatile boolean started_;
+
    private PortalContainerInfo pinfo_;
 
    private SessionManager smanager_;
 
+   /**
+    * The name of the portal container
+    */
    private final String name;
 
-   public PortalContainer(PicoContainer parent, ServletContext portalContext)
+   /**
+    * The comparator used to sort the web applications by priorities 
+    */
+   private final Comparator<WebAppInitContext> webAppComparator;
+
+   /**
+    * The full {@link ServletContext} of the portal container after merging all the 
+    * {@link ServletContext} that have been registered
+    */
+   private final ServletContext portalMergedContext;
+
+   /**
+    * The full {@link ClassLoader} of the portal container after merging all the {@link ClassLoader}
+    * of the {@link ServletContext} that have been registered
+    */
+   private final ClassLoader portalMergedClassLoader;
+
+   /**
+    * The {@link Set} of all the web application context that share configuration
+    */
+   private volatile Set<WebAppInitContext> webAppContexts;
+
+   /**
+    * To allow overriding we need to have a custom {@link ClassLoader} by web applications by portal
+    * containers
+    */
+   private volatile Map<String, ClassLoader> webAppClassLoaders;
+
+   /**
+    * The {@link ServletContext} of the current portal container
+    */
+   final ServletContext portalContext;
+
+   public PortalContainer(RootContainer parent, ServletContext portalContext)
    {
       super(new MX4JComponentAdapterFactory(), parent);
       registerComponentInstance(ServletContext.class, portalContext);
@@ -67,8 +147,131 @@
       pinfo_ = new PortalContainerInfo(portalContext);
       registerComponentInstance(PortalContainerInfo.class, pinfo_);
       this.name = portalContext.getServletContextName();
+      final List<String> dependencies = parent.getPortalContainerConfig().getDependencies(name);
+      if (dependencies == null || dependencies.isEmpty())
+      {
+         // No order is required
+         this.webAppComparator = null;
+      }
+      else
+      {
+         this.webAppComparator = new WebAppInitContextComparator(dependencies);
+      }
+      this.webAppContexts = Collections.singleton(new WebAppInitContext(portalContext));
+      this.portalContext = portalContext;
+      this.portalMergedContext = new PortalContainerContext(this);
+      this.portalMergedClassLoader = new PortalContainerClassLoader(this);
+      this.webAppClassLoaders = Collections.unmodifiableMap(Collections.singletonMap(name, portalMergedClassLoader));
    }
 
+   /**
+    * @return a {@link Set} ordered by priority of all the {@link WebAppInitContext} that represents 
+    * the full portal context
+    */
+   Set<WebAppInitContext> getWebAppInitContexts()
+   {
+      return webAppContexts;
+   }
+
+   /**
+    * This gives the merged {@link ClassLoader} between the {@link PortalContainerClassLoader} and the
+    * {@link ClassLoader} of the web application.
+    * 
+    * @param context the {@link ServletContext} of the web application
+    * @return the merged {@link ClassLoader} between the {@link PortalContainerClassLoader} and
+    * the {@link ClassLoader} of the web application that allows us to override resources contained
+    * into the {@link ClassLoader} of the web application 
+    */
+   public ClassLoader getWebAppClassLoader(ServletContext context)
+   {
+      final String contextName = context.getServletContextName();
+      ClassLoader cl = webAppClassLoaders.get(contextName);
+      if (cl == null)
+      {
+         synchronized (this)
+         {
+            cl = webAppClassLoaders.get(contextName);
+            if (cl == null)
+            {
+               cl =
+                  new UnifiedClassLoader(new ClassLoader[]{Thread.currentThread().getContextClassLoader(),
+                     portalMergedClassLoader});
+               Map<String, ClassLoader> cls = new HashMap<String, ClassLoader>(webAppClassLoaders);
+               cls.put(contextName, cl);
+               this.webAppClassLoaders = Collections.unmodifiableMap(cls);
+            }
+         }
+      }
+      return cl;
+   }
+
+   /**
+    * @return the full {@link ClassLoader} of the portal container after merging all the 
+    * {@link ClassLoader} of all {@link ServletContext} that have been registered
+    */
+   public ClassLoader getPortalClassLoader()
+   {
+      return portalMergedClassLoader;
+   }
+
+   /**
+    * @return the full {@link ServletContext} of the portal container after merging all the 
+    * {@link ServletContext} that have been registered
+    */
+   public ServletContext getPortalContext()
+   {
+      return portalMergedContext;
+   }
+
+   /**
+    * Register a new servlet context that contains configuration files and potentially resource files
+    * We assume that this method is called within the initialization context of the related web application
+    * @param context the {@link ServletContext} of the web application to register
+    */
+   public synchronized void registerContext(ServletContext context)
+   {
+      final WebAppInitContext webappCtx = new WebAppInitContext(context);
+      if (!webAppContexts.contains(webappCtx))
+      {
+         final Set<WebAppInitContext> contexts;
+         if (webAppComparator == null)
+         {
+            contexts = new HashSet<WebAppInitContext>(webAppContexts);
+         }
+         else
+         {
+            contexts = new TreeSet<WebAppInitContext>(webAppComparator);
+            contexts.addAll(webAppContexts);
+         }
+         contexts.add(webappCtx);
+         this.webAppContexts = Collections.unmodifiableSet(contexts);
+      }
+   }
+
+   /**
+    * Unregister a servlet context that contains configuration files and potentially resource files
+    * @param context the {@link ServletContext} of the web application to unregister
+    */
+   public synchronized void unregisterContext(ServletContext context)
+   {
+      final WebAppInitContext webappCtx = new WebAppInitContext(context);
+      if (webAppContexts.contains(webappCtx))
+      {
+         final Set<WebAppInitContext> contexts;
+         if (webAppComparator == null)
+         {
+            contexts = new HashSet<WebAppInitContext>(webAppContexts);
+         }
+         else
+         {
+            contexts = new TreeSet<WebAppInitContext>(webAppComparator);
+            contexts.addAll(webAppContexts);
+         }
+         contexts.remove(webappCtx);
+         this.webAppContexts = Collections.unmodifiableSet(contexts);
+      }
+   }
+
    @Managed
    @ManagedDescription("The portal container name")
    public String getName()
@@ -110,6 +313,10 @@
       return pinfo_;
    }
 
+   /**
+    * @return the current instance of {@link PortalContainer} that has been stored into the related
+    * {@link ThreadLocal}. If no value has been set the default portal container will be returned
+    */
    public static PortalContainer getInstance()
    {
       PortalContainer container = (PortalContainer)currentContainer_.get();
@@ -121,50 +328,230 @@
       return container;
    }
 
-   @Managed
-   public boolean isStarted()
+   /**
+    * @return the current instance of {@link PortalContainer} that has been stored into the related
+    * {@link ThreadLocal}. If no value has been set, it will return <code>null</code>
+    */
+   public static PortalContainer getInstanceIfPresent()
    {
-      return started_;
+      return currentContainer_.get();
    }
 
-   public void start()
+   /**
+    * @see the method isPortalContainerName of {@link PortalContainerConfig}
+    */
+   public static boolean isPortalContainerName(String name)
    {
-      super.start();
-      started_ = true;
+      if (CONFIG == null)
+      {
+         return DEFAULT_PORTAL_CONTAINER_NAME.equals(name);
+      }
+      else
+      {
+         return CONFIG.isPortalContainerName(name);
+      }
    }
 
-   public void stop()
+   /**
+    * Add an init-task to all the portal container instances related to the given ServletContext
+    * 
+    * @param context the context from which we extract the context name
+    * @param task the task to execute 
+    */
+   public static void addInitTask(ServletContext context, PortalContainerInitTask task)
    {
-      super.stop();
-      started_ = false;
+      addInitTask(context, task, null);
    }
 
-   synchronized public ComponentAdapter getComponentAdapterOfType(Class componentType)
+   /**
+    * Add an init-task to all the portal container instances related to the given ServletContext if the
+    * given portal container name is <code>null</code> other it will execute the task only of this
+    * portal container if the {@link ServletContext} is on of its dependencies
+    * 
+    * @param context the context from which we extract the context name
+    * @param task the task to execute
+    * @param portalContainerName the name of the portal container for which we want to execute the task
+    */
+   public static void addInitTask(ServletContext context, PortalContainerInitTask task, String portalContainerName)
    {
-      return super.getComponentAdapterOfType(componentType);
+      if (context == null || CONFIG == null)
+      {
+         return;
+      }
+      String contextName = context.getServletContextName();
+      List<String> portalContainerNames = CONFIG.getPortalContainerNames(contextName);
+      RootContainer root = RootContainer.getInstance();
+      // We assume that we have at list one portal container otherwise there is a bug in PortalContainerConfig
+      for (String name : portalContainerNames)
+      {
+         if (portalContainerName == null || portalContainerName.equals(name))
+         {
+            root.addInitTask(context, task, name);
+         }
+      }
    }
 
-   synchronized public List getComponentAdaptersOfType(Class componentType)
+   /**
+    * Gives the first portal container instance related to the given ServletContext
+    * 
+    * @param context the context from which we extract the context name
+    */
+   public static PortalContainer getInstance(ServletContext context)
    {
-      return super.getComponentAdaptersOfType(componentType);
+      if (context == null || CONFIG == null)
+      {
+         return null;
+      }
+      List<String> portalContainerNames = CONFIG.getPortalContainerNames(context.getServletContextName());
+      RootContainer root = RootContainer.getInstance();
+      return root.getPortalContainer(portalContainerNames.get(0));
    }
 
-   synchronized public ComponentAdapter unregisterComponent(Object componentKey)
+   /**
+    * We first try to get the ExoContainer that has been stored in the ThreadLocal
+    * if the value is of type PortalContainer, we return it otherwise we get the
+    * portal container corresponding the given servlet context
+    * 
+    * @param context the context from which we extract the portal container name
+    */
+   public static PortalContainer getCurrentInstance(ServletContext context)
    {
-      return super.unregisterComponent(componentKey);
+      final ExoContainer container = ExoContainerContext.getCurrentContainer();
+      if (container instanceof PortalContainer)
+      {
+         if (log.isDebugEnabled())
+            log.debug("A portal container has been set in the ThreadLocal of ExoContainerContext");
+         return (PortalContainer)container;
+      }
+      else
+      {
+         PortalContainer pContainer = PortalContainer.getInstanceIfPresent();
+         if (pContainer == null)
+         {
+            if (log.isDebugEnabled())
+               log.debug("No portal container has been set in the ThreadLoal of PortalContainer");
+            pContainer = PortalContainer.getInstance(context);
+         }
+         return pContainer;
+      }
    }
 
-   synchronized public ComponentAdapter registerComponent(ComponentAdapter componentAdapter)
-      throws DuplicateComponentKeyRegistrationException
+   /**
+    * Returns the name of the current portal container that has been stored in the ThreadLocal. If no
+    * value can be found the value of PortalContainer.DEFAULT_PORTAL_CONTAINER_NAME will be used
+    */
+   public static String getCurrentPortalContainerName()
    {
-      return super.registerComponent(componentAdapter);
+      final PortalContainer container = getInstanceIfPresent();
+      if (container == null)
+      {
+         return DEFAULT_PORTAL_CONTAINER_NAME;
+      }
+      else
+      {
+         return container.getName();
+      }
    }
 
-   synchronized public List getComponentInstancesOfType(Class componentType) throws PicoException
+   /**
+    * Returns the name of the current rest context corresponding to the portal container
+    * that has been stored in the ThreadLocal. If no value can be found the value of 
+    * PortalContainer.DEFAULT_REST_CONTEXT_NAME will be used
+    */
+   public static String getCurrentRestContextName()
    {
-      return super.getComponentInstancesOfType(componentType);
+      final String containerName = getCurrentPortalContainerName();
+      return getRestContextName(containerName);
    }
 
+   /**
+    * Returns the name of the rest context corresponding to the given portal container name
+    * @param portalContainerName the name of the portal container for which we want the
+    * name of the rest {@link ServletContext}
+    */
+   public static String getRestContextName(String portalContainerName)
+   {
+      if (CONFIG == null)
+      {
+         return DEFAULT_REST_CONTEXT_NAME;
+      }
+      return CONFIG.getRestContextName(portalContainerName);
+   }
+
+   /**
+    * Returns the name of the rest context corresponding to the current portal container 
+    */
+   public String getRestContextName()
+   {
+      return getRestContextName(getName());
+   }
+
+   /**
+    * Returns the name of the current realm corresponding to the portal container
+    * that has been stored in the ThreadLocal. If no value can be found the value of 
+    * PortalContainer.DEFAULT_REALM_NAME will be used
+    */
+   public static String getCurrentRealmName()
+   {
+      final String containerName = getCurrentPortalContainerName();
+      return getRealmName(containerName);
+   }
+
+   /**
+    * Returns the name of the realm corresponding to the given portal container name
+    * @param portalContainerName the name of the portal container for which we want the
+    * name of the realm
+    */
+   public static String getRealmName(String portalContainerName)
+   {
+      if (CONFIG == null)
+      {
+         return DEFAULT_REALM_NAME;
+      }
+      return CONFIG.getRealmName(portalContainerName);
+   }
+
+   /**
+    * Returns the name of the realm corresponding to the current portal container 
+    */
+   public String getRealmName()
+   {
+      return getRealmName(getName());
+   }
+
+   /**
+    * Indicates if the given servlet context is a dependency of the given portal container
+    * @param container the portal container
+    * @param context the {@link ServletContext}
+    * @return <code>true</code> if the dependencies matches, <code>false</code> otherwise;
+    */
+   public static boolean isScopeValid(PortalContainer container, ServletContext context)
+   {
+      if (CONFIG == null)
+      {
+         return true;
+      }
+      return CONFIG.isScopeValid(container.getName(), context.getServletContextName());
+   }
+
+   @Managed
+   public boolean isStarted()
+   {
+      return started_;
+   }
+
+   public void start()
+   {
+      super.start();
+      started_ = true;
+   }
+
+   public void stop()
+   {
+      super.stop();
+      started_ = false;
+   }
+
    public static void setInstance(PortalContainer instance)
    {
       currentContainer_.set(instance);
@@ -176,4 +563,47 @@
       PortalContainer pcontainer = (PortalContainer)currentContainer_.get();
       return pcontainer.getComponentInstanceOfType(key);
    }
+
+   /**
+    * This class is used to compare the {@link WebAppInitContext}
+    */
+   static class WebAppInitContextComparator implements Comparator<WebAppInitContext>
+   {
+
+      private final List<String> dependencies;
+
+      WebAppInitContextComparator(List<String> dependencies)
+      {
+         this.dependencies = dependencies;
+      }
+
+      /**
+       * This will sort all the {@link WebAppInitContext} such that we will first have
+       * all the web applications defined in the list of dependencies of the 
+       * related portal container (see {@link PortalContainerConfig} for more details
+       *  about the dependencies) ordered in the same order as the dependencies, then
+       *  we will have all the web applications undefined ordered by context name
+       */
+      public int compare(WebAppInitContext ctx1, WebAppInitContext ctx2)
+      {
+         int idx1 = dependencies.indexOf(ctx1.getServletContextName());
+         int idx2 = dependencies.indexOf(ctx2.getServletContextName());
+         if (idx1 == -1 && idx2 != -1)
+         {
+            return 1;
+         }
+         else if (idx1 != -1 && idx2 == -1)
+         {
+            return -1;
+         }
+         else if (idx1 == -1 && idx2 == -1)
+         {
+            return ctx1.getServletContextName().compareTo(ctx2.getServletContextName());
+         }
+         else
+         {
+            return idx1 - idx2;
+         }
+      }
+   }
 }

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainerClassLoader.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainerClassLoader.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainerClassLoader.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.container;
+
+import java.util.Set;
+
+/**
+ * This class defined the {@link ClassLoader} of a portal container
+ * 
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ *          nicolas.filotto at exoplatform.com
+ * 15 sept. 2009  
+ */
+class PortalContainerClassLoader extends UnifiedClassLoader
+{
+
+   /**
+    * The related portal container
+    */
+   private final PortalContainer container;
+
+   PortalContainerClassLoader(PortalContainer container)
+   {
+      super(getClassLoaders(container));
+      this.container = container;
+   }
+
+   /**
+    * Retrieves the list of all the {@link ClassLoader} that are associated to the given
+    * portal container
+    */
+   private static ClassLoader[] getClassLoaders(PortalContainer container)
+   {
+      final Set<WebAppInitContext> contexts = container.getWebAppInitContexts();
+      final ClassLoader[] cls = new ClassLoader[contexts.size()];
+      int i = 0;
+      for (WebAppInitContext ctx : contexts)
+      {
+         cls[i++] = ctx.getWebappClassLoader();
+      }
+      return cls;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   protected ClassLoader[] getClassLoaders()
+   {
+      return getClassLoaders(container);
+   }
+}

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainerContext.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainerContext.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/PortalContainerContext.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.container;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+/**
+ * This class is used to merge all the {@link ServletContext} related to a given portal container.
+ * It will used the {@link WebAppInitContext} that have been defined in the related portal container.
+ * It will always consider that the {@link WebAppInitContext}
+ * with the highest priority has always right, in other words for example in the method
+ * getInitParameter, it will try to get the init parameter in the {@link WebAppInitContext} 
+ * of the highest priority, if it cans not find it, it will try the {@link WebAppInitContext}
+ *  with the second highest priority and so on. The priority of the {@link WebAppInitContext} is
+ *  the order given by the method PortalContainer.getWebAppInitContexts(), 
+ * the last {@link WebAppInitContext} is the one with the highest priority.
+ * 
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ *          nicolas.filotto at exoplatform.com
+ * 14 sept. 2009  
+ */
+class PortalContainerContext implements ServletContext
+{
+
+   /**
+    * The related portal container
+    */
+   private final PortalContainer container;
+
+   PortalContainerContext(PortalContainer container)
+   {
+      this.container = container;
+   }
+
+   private WebAppInitContext[] getWebAppInitContexts()
+   {
+      final Set<WebAppInitContext> contexts = container.getWebAppInitContexts();
+      final WebAppInitContext[] aContexts = new WebAppInitContext[contexts.size()];
+      return (WebAppInitContext[])contexts.toArray(aContexts);
+   }
+
+   private ServletContext getPortalContext()
+   {
+      return container.portalContext;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public Object getAttribute(String name)
+   {
+      return getPortalContext().getAttribute(name);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @SuppressWarnings("unchecked")
+   public Enumeration getAttributeNames()
+   {
+      return getPortalContext().getAttributeNames();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public ServletContext getContext(String uripath)
+   {
+      return getPortalContext().getContext(uripath);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public String getInitParameter(String name)
+   {
+      final WebAppInitContext[] contexts = getWebAppInitContexts();
+      for (int i = contexts.length - 1; i >= 0; i--)
+      {
+         final ServletContext context = contexts[i].getServletContext();
+         String param = context.getInitParameter(name);
+         if (param != null)
+         {
+            return param;
+         }
+      }
+      return null;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @SuppressWarnings("unchecked")
+   public Enumeration<String> getInitParameterNames()
+   {
+      final Set<WebAppInitContext> contexts = container.getWebAppInitContexts();
+      Set<String> names = null;
+      for (WebAppInitContext context : contexts)
+      {
+         Enumeration<String> eNames = context.getServletContext().getAttributeNames();
+         if (eNames != null)
+         {
+            if (names == null)
+            {
+               names = new HashSet<String>();
+            }
+            names.addAll(Collections.list(eNames));
+         }
+      }
+      if (names == null)
+      {
+         return null;
+      }
+      return Collections.enumeration(names);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public int getMajorVersion()
+   {
+      return getPortalContext().getMajorVersion();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public String getMimeType(String file)
+   {
+      final WebAppInitContext[] contexts = getWebAppInitContexts();
+      for (int i = contexts.length - 1; i >= 0; i--)
+      {
+         final ServletContext context = contexts[i].getServletContext();
+         String mimeType = context.getMimeType(file);
+         if (mimeType != null)
+         {
+            return mimeType;
+         }
+      }
+      return null;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public int getMinorVersion()
+   {
+      return getPortalContext().getMinorVersion();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public RequestDispatcher getNamedDispatcher(String name)
+   {
+      return getPortalContext().getNamedDispatcher(name);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public String getRealPath(String path)
+   {
+      final WebAppInitContext[] contexts = getWebAppInitContexts();
+      for (int i = contexts.length - 1; i >= 0; i--)
+      {
+         final ServletContext context = contexts[i].getServletContext();
+         final InputStream is = context.getResourceAsStream(path);
+         if (is != null)
+         {
+            // The resource exists within this servlet context
+            return context.getRealPath(path);
+         }
+      }
+      return null;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public RequestDispatcher getRequestDispatcher(String path)
+   {
+      final WebAppInitContext[] contexts = getWebAppInitContexts();
+      for (int i = contexts.length - 1; i >= 0; i--)
+      {
+         final ServletContext context = contexts[i].getServletContext();
+         final InputStream is = context.getResourceAsStream(path);
+         if (is != null)
+         {
+            // The resource exists within this servlet context
+            return context.getRequestDispatcher(path);
+         }
+      }
+      return null;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public URL getResource(String path) throws MalformedURLException
+   {
+      final WebAppInitContext[] contexts = getWebAppInitContexts();
+      for (int i = contexts.length - 1; i >= 0; i--)
+      {
+         final ServletContext context = contexts[i].getServletContext();
+         final URL url = context.getResource(path);
+         if (url != null)
+         {
+            return url;
+         }
+      }
+      return null;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public InputStream getResourceAsStream(String path)
+   {
+      final WebAppInitContext[] contexts = getWebAppInitContexts();
+      for (int i = contexts.length - 1; i >= 0; i--)
+      {
+         final ServletContext context = contexts[i].getServletContext();
+         final InputStream is = context.getResourceAsStream(path);
+         if (is != null)
+         {
+            return is;
+         }
+      }
+      return null;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @SuppressWarnings("unchecked")
+   public Set<String> getResourcePaths(String path)
+   {
+      final Set<WebAppInitContext> contexts = container.getWebAppInitContexts();
+      Set<String> paths = null;
+      for (WebAppInitContext context : contexts)
+      {
+         Set<String> sPaths = context.getServletContext().getResourcePaths(path);
+         if (sPaths != null)
+         {
+            if (paths == null)
+            {
+               paths = new LinkedHashSet<String>();
+            }
+            paths.addAll(sPaths);
+         }
+      }
+      return paths;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public String getServerInfo()
+   {
+      return getPortalContext().getServerInfo();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @SuppressWarnings("deprecation")
+   public Servlet getServlet(String name) throws ServletException
+   {
+      return getPortalContext().getServlet(name);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public String getServletContextName()
+   {
+      return getPortalContext().getServletContextName();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @SuppressWarnings({"deprecation", "unchecked"})
+   public Enumeration getServletNames()
+   {
+      return getPortalContext().getServletNames();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @SuppressWarnings({"deprecation", "unchecked"})
+   public Enumeration getServlets()
+   {
+      return getPortalContext().getServlets();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void log(String message)
+   {
+      getPortalContext().log(message);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @SuppressWarnings("deprecation")
+   public void log(Exception exception, String message)
+   {
+      getPortalContext().log(exception, message);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void log(String message, Throwable throwable)
+   {
+      getPortalContext().log(message, throwable);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void removeAttribute(String name)
+   {
+      getPortalContext().removeAttribute(name);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void setAttribute(String name, Object object)
+   {
+      getPortalContext().setAttribute(name, object);
+   }
+}

Modified: kernel/trunk/container/src/main/java/org/exoplatform/container/RootContainer.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/RootContainer.java	2009-10-04 19:39:27 UTC (rev 206)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/RootContainer.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -21,6 +21,8 @@
 import org.exoplatform.container.configuration.ConfigurationManager;
 import org.exoplatform.container.configuration.ConfigurationManagerImpl;
 import org.exoplatform.container.configuration.MockConfigurationManagerImpl;
+import org.exoplatform.container.definition.PortalContainerConfig;
+import org.exoplatform.container.definition.PortalContainerDefinition;
 import org.exoplatform.container.jmx.ManagementContextImpl;
 import org.exoplatform.container.monitor.jvm.J2EEServerInfo;
 import org.exoplatform.container.monitor.jvm.OperatingSystemInfo;
@@ -36,7 +38,15 @@
 import java.io.File;
 import java.lang.management.ManagementFactory;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.PriorityBlockingQueue;
 
 import javax.management.MBeanServer;
 import javax.servlet.ServletContext;
@@ -66,12 +76,25 @@
 
    private OperatingSystemInfo osenv_;
 
+   private PortalContainerConfig config_;
+
    private static final Log log = ExoLogger.getLogger(RootContainer.class);
 
    private static volatile boolean booting = false;
 
    private final J2EEServerInfo serverenv_ = new J2EEServerInfo();
 
+   /**
+    * The list of all the tasks to execute while initializing the corresponding portal containers
+    */
+   private final ConcurrentMap<String, ConcurrentMap<String, Queue<PortalContainerInitTaskContext>>> initTasks =
+      new ConcurrentHashMap<String, ConcurrentMap<String, Queue<PortalContainerInitTaskContext>>>();
+
+   /**
+    * The list of the web application contexts corresponding to all the portal containers
+    */
+   private final Queue<WebAppInitContext> portalContexts = new ConcurrentLinkedQueue<WebAppInitContext>();
+
    public RootContainer()
    {
       super(new ManagementContextImpl(findMBeanServer(), new HashMap<String, String>()));
@@ -88,6 +111,28 @@
       return osenv_;
    }
 
+   /**
+    * @return the {@link PortalContainerConfig} corresponding to the {@link RootContainer}
+    */
+   PortalContainerConfig getPortalContainerConfig()
+   {
+      if (config_ == null)
+      {
+         config_ = (PortalContainerConfig)this.getComponentInstanceOfType(PortalContainerConfig.class);
+      }
+      return config_;
+   }
+
+   /**
+    * Indicates if the current instance is aware of the {@link PortalContainerConfig}
+    * @return <code>true</code> if we are using the old way to configure the portal containers,
+    * <code>false</code> otherwise
+    */
+   public boolean isPortalContainerConfigAware()
+   {
+      return getPortalContainerConfig().hasDefinition();
+   }
+
    public J2EEServerInfo getServerEnvironment()
    {
       return serverenv_;
@@ -125,14 +170,96 @@
       return pcontainer;
    }
 
-   synchronized public PortalContainer createPortalContainer(ServletContext context)
+   /**
+    * Register a new portal container. It will try to detect if {@link PortalContainerDefinition} has
+    *  been defined, if so it will create the portal container later otherwise we assume that we 
+    * expect the old behavior, thus the portal container will be initialized synchronously 
+    * @param context the context of the portal container
+    */
+   public void registerPortalContainer(ServletContext context)
    {
+      PortalContainerConfig config = getPortalContainerConfig();
+      // Ensure that the portal container has been registered
+      config.registerPortalContainerName(context.getServletContextName());
+      if (config.hasDefinition())
+      {
+         // The new behavior has been detected thus, the creation will be done at the end asynchronously
+         portalContexts.add(new WebAppInitContext(context));
+         // We assume that a ServletContext of a portal container owns configuration files
+         final PortalContainerPreInitTask task = new PortalContainerPreInitTask()
+         {
+
+            public void execute(ServletContext context, PortalContainer portalContainer)
+            {
+               portalContainer.registerContext(context);
+            }
+         };
+         PortalContainer.addInitTask(context, task);
+      }
+      else
+      {
+         // The old behavior has been detected thus, the creation will be done synchronously
+         createPortalContainer(context);
+      }
+   }
+
+   /**
+    * Creates all the portal containers that have been registered thanks to the method 
+    * <code>registerPortalContainer</code>
+    */
+   public synchronized void createPortalContainers()
+   {
+      // Keep the old ClassLoader
+      final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+      WebAppInitContext context;
+      boolean hasChanged = false;
       try
       {
+         while ((context = portalContexts.poll()) != null)
+         {
+            // Set the context classloader of the related web application
+            Thread.currentThread().setContextClassLoader(context.getWebappClassLoader());
+            hasChanged = true;
+            createPortalContainer(context.getServletContext());
+         }
+      }
+      finally
+      {
+         if (hasChanged)
+         {
+            // Re-set the old classloader
+            Thread.currentThread().setContextClassLoader(currentClassLoader);
+         }
+      }
+      PortalContainerConfig config = getPortalContainerConfig();
+      for (String portalContainerName : initTasks.keySet())
+      {
+         // Unregister name of portal container that doesn't exist
+         log.warn("The portal container '" + portalContainerName + "' doesn't not exist or"
+            + " it has not yet been registered, please check your PortalContainerDefinitions and "
+            + "the loading order.");
+         config.unregisterPortalContainerName(portalContainerName);
+      }
+      // remove all the unneeded tasks
+      initTasks.clear();
+   }
+
+   public synchronized void createPortalContainer(ServletContext context)
+   {
+      // Keep the old ClassLoader
+      final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+      boolean hasChanged = false;
+      final String portalContainerName = context.getServletContextName();
+      try
+      {
+         log.info("Trying to create the portal container '" + portalContainerName + "'");
          PortalContainer pcontainer = new PortalContainer(this, context);
          PortalContainer.setInstance(pcontainer);
-         ExoContainerContext.setCurrentContainer(pcontainer);
-         ConfigurationManagerImpl cService = new ConfigurationManagerImpl(context);
+         executeInitTasks(pcontainer, PortalContainerPreInitTask.TYPE);
+         // Set the full classloader of the portal container
+         Thread.currentThread().setContextClassLoader(pcontainer.getPortalClassLoader());
+         hasChanged = true;
+         ConfigurationManagerImpl cService = new ConfigurationManagerImpl(pcontainer.getPortalContext());
 
          // add configs from services
          try
@@ -141,9 +268,7 @@
          }
          catch (Exception ex)
          {
-            System.err.println("ERROR: cannot add configuration conf/portal/configuration.xml. ServletContext: "
-               + context);
-            ex.printStackTrace();
+            log.error("Cannot add configuration conf/portal/configuration.xml. ServletContext: " + context, ex);
          }
 
          // Add configuration that depends on the environment
@@ -163,27 +288,29 @@
          }
          catch (Exception ex)
          {
-            System.err.println("ERROR: cannot add configuration " + uri + ". ServletContext: " + context);
-            ex.printStackTrace();
+            log.error("Cannot add configuration " + uri + ". ServletContext: " + context, ex);
          }
 
          // add configs from web apps
-         try
+         Set<WebAppInitContext> contexts = pcontainer.getWebAppInitContexts();
+         for (WebAppInitContext webappctx : contexts)
          {
-            cService.addConfiguration("war:/conf/configuration.xml");
+            ServletContext ctx = webappctx.getServletContext();
+            try
+            {
+               cService.addConfiguration(ctx, "war:/conf/configuration.xml");
+            }
+            catch (Exception ex)
+            {
+               log.error("Cannot add configuration war:/conf/configuration.xml. ServletContext: " + ctx, ex);
+            }
          }
-         catch (Exception ex)
-         {
-            System.err.println("ERROR: cannot add configuration war:/conf/configuration.xml. ServletContext: "
-               + context);
-            ex.printStackTrace();
-         }
 
          // add config from application server,
          // $AH_HOME/exo-conf/portal/configuration.xml
          String overrideConfig =
-            singleton_.getServerEnvironment().getExoConfigurationDirectory() + "/portal/"
-               + pcontainer.getPortalContainerInfo().getContainerName() + "/configuration.xml";
+            singleton_.getServerEnvironment().getExoConfigurationDirectory() + "/portal/" + portalContainerName
+               + "/configuration.xml";
          try
          {
             File file = new File(overrideConfig);
@@ -192,30 +319,43 @@
          }
          catch (Exception ex)
          {
-            System.err.println("ERROR: cannot add configuration " + overrideConfig + ". ServletContext: " + context);
-            ex.printStackTrace();
+            log.error("Cannot add configuration " + overrideConfig + ". ServletContext: " + context, ex);
          }
 
          cService.processRemoveConfiguration();
          ComponentAdapter adapter = pcontainer.registerComponentInstance(ConfigurationManager.class, cService);
          pcontainer.initContainer();
-         registerComponentInstance(context.getServletContextName(), pcontainer);
-         PortalContainer.setInstance(pcontainer);
-         ExoContainerContext.setCurrentContainer(pcontainer);
+         registerComponentInstance(portalContainerName, pcontainer);
          pcontainer.start();
 
          // Register the portal as an mbean
          managementContext.register(pcontainer);
 
          //
-         return pcontainer;
+         executeInitTasks(pcontainer, PortalContainerPostInitTask.TYPE);
+         executeInitTasks(pcontainer, PortalContainerPostCreateTask.TYPE);
+         log.info("The portal container '" + portalContainerName + "' has been created successfully");
       }
       catch (Exception ex)
       {
-         System.err.println("ERROR: cannot create portal container. ServletContext: " + context);
-         ex.printStackTrace();
+         log.error("Cannot create the portal container '" + portalContainerName + "' . ServletContext: " + context, ex);
       }
-      return null;
+      finally
+      {
+         if (hasChanged)
+         {
+            // Re-set the old classloader
+            Thread.currentThread().setContextClassLoader(currentClassLoader);
+         }
+         try
+         {
+            PortalContainer.setInstance(null);
+         }
+         catch (Exception e)
+         {
+            log.warn("An error occured while cleaning the ThreadLocal", e);
+         }
+      }
    }
 
    synchronized public void removePortalContainer(ServletContext servletContext)
@@ -316,6 +456,147 @@
       singleton_ = rcontainer;
    }
 
+   /**
+    * Calls the other method <code>addInitTask</code> with <code>ServletContext.getServletContextName()</code>
+    * as portal container name
+    * 
+    * @param context the servlet context from which the task comes from
+    * @param task the task to add
+    */
+   public void addInitTask(ServletContext context, PortalContainerInitTask task)
+   {
+      addInitTask(context, task, context.getServletContextName());
+   }
+
+   /**
+    * First check if the related portal container has already been initialized. If so
+    * it will call the method onAlreadyExists on the given task otherwise the task will
+    * be added to the task list to execute during the related portal container initialization
+    * 
+    * @param context the servlet context from which the task comes from
+    * @param task the task to add
+    * @param portalContainer the name of the portal container on which the task must be executed
+    */
+   public void addInitTask(ServletContext context, PortalContainerInitTask task, String portalContainer)
+   {
+      final PortalContainer container = getPortalContainer(portalContainer);
+      if (!task.alreadyExists(container))
+      {
+         if (log.isDebugEnabled())
+            log.debug("The portal container '" + portalContainer
+               + "' has not yet been initialized, thus the task can be added");
+         ConcurrentMap<String, Queue<PortalContainerInitTaskContext>> queues = initTasks.get(portalContainer);
+         if (queues == null)
+         {
+            queues = new ConcurrentHashMap<String, Queue<PortalContainerInitTaskContext>>();
+            final ConcurrentMap<String, Queue<PortalContainerInitTaskContext>> q =
+               initTasks.putIfAbsent(portalContainer, queues);
+            if (q != null)
+            {
+               queues = q;
+            }
+         }
+         final String type = task.getType();
+         Queue<PortalContainerInitTaskContext> queue = queues.get(type);
+         if (queue == null)
+         {
+            final List<String> dependencies = getPortalContainerConfig().getDependencies(portalContainer);
+            if (dependencies == null || dependencies.isEmpty())
+            {
+               // No order is required
+               queue = new ConcurrentLinkedQueue<PortalContainerInitTaskContext>();
+            }
+            else
+            {
+               queue =
+                  new PriorityBlockingQueue<PortalContainerInitTaskContext>(10,
+                     new PortalContainerInitTaskContextComparator(dependencies));
+            }
+            final Queue<PortalContainerInitTaskContext> q = queues.putIfAbsent(type, queue);
+            if (q != null)
+            {
+               queue = q;
+            }
+         }
+         queue.add(new PortalContainerInitTaskContext(context, task));
+      }
+      else
+      {
+         if (log.isDebugEnabled())
+            log.debug("The portal container '" + portalContainer
+               + "' has already been initialized, thus we call onAlreadyExists");
+         PortalContainer oldPortalContainer = PortalContainer.getInstanceIfPresent();
+         try
+         {
+            PortalContainer.setInstance(container);
+            task.onAlreadyExists(context, container);
+         }
+         finally
+         {
+            PortalContainer.setInstance(oldPortalContainer);
+         }
+      }
+   }
+
+   /**
+    * Executes all the tasks of the given type related to the given portal container
+    * @param portalContainer the portal container on which we want to execute the tasks
+    * @param type the type of the task to execute
+    */
+   private void executeInitTasks(PortalContainer portalContainer, String type)
+   {
+      final String portalContainerName = portalContainer.getName();
+      final ConcurrentMap<String, Queue<PortalContainerInitTaskContext>> queues = initTasks.get(portalContainerName);
+      if (queues == null)
+      {
+         return;
+      }
+      final Queue<PortalContainerInitTaskContext> queue = queues.get(type);
+      if (queue == null)
+      {
+         return;
+      }
+      if (log.isDebugEnabled())
+         log.debug("Start launching the " + type + " tasks of the portal container '" + portalContainer + "'");
+      // Keep the old ClassLoader
+      final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+      PortalContainerInitTaskContext context;
+      boolean hasChanged = false;
+      try
+      {
+         while ((context = queue.poll()) != null)
+         {
+            if (context.getServletContextName().equals(portalContainer.getName()))
+            {
+               context.getTask().execute(portalContainer.getPortalContext(), portalContainer);
+            }
+            else
+            {
+               // The current servlet context is not the context of the portal
+               // Set the context classloader of the related web application
+               Thread.currentThread().setContextClassLoader(context.getWebappClassLoader());
+               hasChanged = true;
+               context.getTask().execute(context.getServletContext(), portalContainer);
+            }
+         }
+      }
+      finally
+      {
+         if (hasChanged)
+         {
+            // Re-set the old classloader 
+            Thread.currentThread().setContextClassLoader(currentClassLoader);
+         }
+      }
+      queues.remove(type);
+      if (queues.isEmpty())
+      {
+         initTasks.remove(portalContainerName);
+      }
+      if (log.isDebugEnabled())
+         log.debug("End launching the " + type + " tasks of the portal container '" + portalContainer + "'");
+   }
+
    static class ShutdownThread extends Thread
    {
       RootContainer container_;
@@ -336,4 +617,222 @@
       super.stop();
       ExoContainerContext.setTopContainer(null);
    }
+
+   /**
+    * This interface is used to define a task that needs to be launched at a given state during the 
+    * initialization of a portal container
+    */
+   public static interface PortalContainerInitTask
+   {
+
+      /**
+       * This method allows the implementation to define what the state "already exists"
+       * means for a portal container
+       * 
+       * @param portalContainer the value of the current portal container
+       * @return <code>true</code> if the portal container exists according to the task
+       * requirements, <code>false</code> otherwise
+       */
+      public boolean alreadyExists(PortalContainer portalContainer);
+
+      /**
+       * This method is called if the related portal container has already been registered
+       * 
+       * @param context the servlet context of the web application
+       * @param portalContainer the value of the current portal container
+       */
+      public void onAlreadyExists(ServletContext context, PortalContainer portalContainer);
+
+      /**
+       * Executes the task
+       * 
+       * @param context the servlet context of the web application
+       * @param container The portal container on which we would like to execute the task
+       */
+      public void execute(ServletContext context, PortalContainer portalContainer);
+
+      /**
+       * @return the type of the task
+       */
+      public String getType();
+   }
+
+   /**
+    * This class is used to define a task that needs to be launched after the initialization of a
+    * portal container
+    */
+   public static abstract class PortalContainerPostInitTask implements PortalContainerInitTask
+   {
+
+      /**
+       * The name of the type of task
+       */
+      public static final String TYPE = "post-init";
+
+      /**
+       * {@inheritDoc}
+       */
+      public final boolean alreadyExists(PortalContainer portalContainer)
+      {
+         return portalContainer != null && portalContainer.isStarted();
+      }
+
+      /**
+       * {@inheritDoc}
+       */
+      public final void onAlreadyExists(ServletContext context, PortalContainer portalContainer)
+      {
+         execute(context, portalContainer);
+      }
+
+      /**
+       * {@inheritDoc}
+       */
+      public final String getType()
+      {
+         return TYPE;
+      }
+   }
+
+   /**
+    * This class is used to define a task that needs to be launched before the initialization of a
+    * portal container
+    */
+   public static abstract class PortalContainerPreInitTask implements PortalContainerInitTask
+   {
+
+      /**
+       * The name of the type of task
+       */
+      public static final String TYPE = "pre-init";
+
+      /**
+       * {@inheritDoc}
+       */
+      public final boolean alreadyExists(PortalContainer portalContainer)
+      {
+         return portalContainer != null;
+      }
+
+      /**
+       * {@inheritDoc}
+       */
+      public final void onAlreadyExists(ServletContext context, PortalContainer portalContainer)
+      {
+         throw new IllegalStateException("No pre init tasks can be added to the portal container '"
+            + portalContainer.getName() + "', because it has already been " + "initialized. Check the webapp '"
+            + context.getServletContextName() + "'");
+      }
+
+      /**
+       * {@inheritDoc}
+       */
+      public final String getType()
+      {
+         return TYPE;
+      }
+   }
+
+   /**
+    * This class is used to define a task that needs to be launched after creating a portal container
+    * Those type of tasks must be launched after all the "post-init" tasks. 
+    */
+   public static abstract class PortalContainerPostCreateTask implements PortalContainerInitTask
+   {
+
+      /**
+       * The name of the type of task
+       */
+      public static final String TYPE = "post-create";
+
+      /**
+       * {@inheritDoc}
+       */
+      public final boolean alreadyExists(PortalContainer portalContainer)
+      {
+         return portalContainer != null && portalContainer.isStarted();
+      }
+
+      /**
+       * {@inheritDoc}
+       */
+      public final void onAlreadyExists(ServletContext context, PortalContainer portalContainer)
+      {
+         execute(context, portalContainer);
+      }
+
+      /**
+       * {@inheritDoc}
+       */
+      public final String getType()
+      {
+         return TYPE;
+      }
+   }
+
+   /**
+    * This class is used to defined the context of the embedded {@link PortalContainerInitTask}
+    */
+   static class PortalContainerInitTaskContext extends WebAppInitContext
+   {
+
+      /**
+       * The task to execute
+       */
+      private final PortalContainerInitTask task;
+
+      PortalContainerInitTaskContext(ServletContext context, PortalContainerInitTask task)
+      {
+         super(context);
+         this.task = task;
+      }
+
+      public PortalContainerInitTask getTask()
+      {
+         return task;
+      }
+   }
+
+   /**
+    * This class is used to compare the {@link PortalContainerInitTaskContext}
+    */
+   static class PortalContainerInitTaskContextComparator implements Comparator<PortalContainerInitTaskContext>
+   {
+
+      private final List<String> dependencies;
+
+      PortalContainerInitTaskContextComparator(List<String> dependencies)
+      {
+         this.dependencies = dependencies;
+      }
+
+      /**
+       * This will sort all the {@link PortalContainerInitTaskContext} such that we will first have
+       * all the web applications defined in the list of dependencies of the 
+       * related portal container (see {@link PortalContainerConfig} for more details
+       *  about the dependencies) ordered in the same order as the dependencies, then
+       *  we will have all the web applications undefined ordered by context name
+       */
+      public int compare(PortalContainerInitTaskContext ctx1, PortalContainerInitTaskContext ctx2)
+      {
+         int idx1 = dependencies.indexOf(ctx1.getServletContextName());
+         int idx2 = dependencies.indexOf(ctx2.getServletContextName());
+         if (idx1 == -1 && idx2 != -1)
+         {
+            return 1;
+         }
+         else if (idx1 != -1 && idx2 == -1)
+         {
+            return -1;
+         }
+         else if (idx1 == -1 && idx2 == -1)
+         {
+            return ctx1.getServletContextName().compareTo(ctx2.getServletContextName());
+         }
+         else
+         {
+            return idx1 - idx2;
+         }
+      }
+   }
 }

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/UnifiedClassLoader.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/UnifiedClassLoader.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/UnifiedClassLoader.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.container;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * This class is used to merge different {@link ClassLoader} to create one single one.
+ * This ClassLoader is used only for the resources the class will be loaded from the 
+ * ContextClassLoader. For each resources, it will always consider that the {@link ClassLoader}
+ * with the highest priority has always right, in other words for example in the method
+ * getResource, it will try to get the resource in the {@link ClassLoader} of the highest
+ * priority, if it cans not find it, it will try the {@link ClassLoader} with the second highest
+ * priority and so on. The priority of the {@link ClassLoader} is the order given in the 
+ * constructor, the last {@link ClassLoader} is the one with the highest priority.
+ * 
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ *          nicolas.filotto at exoplatform.com
+ * 18 sept. 2009  
+ */
+class UnifiedClassLoader extends ClassLoader
+{
+
+   /**
+    * The list of all the {@link ClassLoader} to merge together
+    */
+   private final ClassLoader[] cls;
+
+   /**
+    * @param cls the list of all the {@link ClassLoader} to merge ordered by priority. The last 
+    * {@link ClassLoader} has highest priority. 
+    */
+   UnifiedClassLoader(ClassLoader... cls)
+   {
+      super(Thread.currentThread().getContextClassLoader());
+      if (cls == null || cls.length == 0)
+      {
+         throw new IllegalArgumentException("The array of ClassLoader cannot be empty");
+      }
+      this.cls = cls;
+   }
+
+   /**
+    * Allows to override the list of {@link ClassLoader} if it is a dynamic list
+    * @return the list of the {@link ClassLoader} to merge
+    */
+   protected ClassLoader[] getClassLoaders()
+   {
+      return cls;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public URL getResource(String name)
+   {
+      final ClassLoader[] cls = getClassLoaders();
+      for (int i = cls.length - 1; i >= 0; i--)
+      {
+         final ClassLoader cl = cls[i];
+         URL url = cl.getResource(name);
+         if (url != null)
+         {
+            return url;
+         }
+      }
+      return null;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Enumeration<URL> getResources(String name) throws IOException
+   {
+      final ClassLoader[] cls = getClassLoaders();
+      final Set<URL> urls = new LinkedHashSet<URL>();
+      for (int i = 0, length = cls.length; i < length; i++)
+      {
+         Enumeration<URL> eUrls = cls[i].getResources(name);
+         if (eUrls != null && eUrls.hasMoreElements())
+         {
+            // Prevent duplicates
+            urls.addAll(Collections.list(eUrls));
+         }
+      }
+      return Collections.enumeration(urls);
+   }
+}

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/WebAppInitContext.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/WebAppInitContext.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/WebAppInitContext.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.container;
+
+import javax.servlet.ServletContext;
+
+/**
+ * This class is used to define the initialization context of a web application
+ * 
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ *          nicolas.filotto at exoplatform.com
+ * 11 sept. 2009  
+ */
+public class WebAppInitContext
+{
+
+   /**
+    * The servlet context of the web application
+    */
+   private final ServletContext servletContext;
+
+   /**
+    * The class loader of the web application;
+    */
+   private final ClassLoader webappClassLoader;
+
+   public WebAppInitContext(ServletContext servletContext)
+   {
+      this.servletContext = servletContext;
+      this.webappClassLoader = Thread.currentThread().getContextClassLoader();
+   }
+
+   public ServletContext getServletContext()
+   {
+      return servletContext;
+   }
+
+   public String getServletContextName()
+   {
+      return servletContext.getServletContextName();
+   }
+
+   public ClassLoader getWebappClassLoader()
+   {
+      return webappClassLoader;
+   }
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (o instanceof WebAppInitContext)
+      {
+         return getServletContextName().equals(((WebAppInitContext)o).getServletContextName());
+      }
+      return false;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      return getServletContextName().hashCode();
+   }
+}

Modified: kernel/trunk/container/src/main/java/org/exoplatform/container/configuration/ConfigurationManagerImpl.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/configuration/ConfigurationManagerImpl.java	2009-10-04 19:39:27 UTC (rev 206)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/configuration/ConfigurationManagerImpl.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -18,8 +18,14 @@
  */
 package org.exoplatform.container.configuration;
 
+import org.exoplatform.container.ExoContainer;
+import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.container.RootContainer;
 import org.exoplatform.container.xml.Component;
 import org.exoplatform.container.xml.Configuration;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
 
 import java.io.File;
 import java.io.IOException;
@@ -47,6 +53,10 @@
 
    final static public boolean LOG_DEBUG = System.getProperty(LOG_DEBUG_PROPERTY) != null;
 
+   private static final String EXO_CONTAINER_PROP_NAME = "container.name.suffix";
+
+   private static final Log log = ExoLogger.getLogger(ConfigurationManagerImpl.class);
+
    protected Configuration configurations_;
 
    private ServletContext scontext_;
@@ -88,6 +98,13 @@
       return configurations_;
    }
 
+   public void addConfiguration(ServletContext context, String url) throws Exception
+   {
+      if (url == null)
+         return;
+      addConfiguration(context, getURL(context, url));
+   }
+
    public void addConfiguration(String url) throws Exception
    {
       if (url == null)
@@ -107,9 +124,13 @@
 
    public void addConfiguration(URL url) throws Exception
    {
+      addConfiguration(scontext_, url);
+   }
 
+   private void addConfiguration(ServletContext context, URL url) throws Exception
+   {
       if (LOG_DEBUG)
-         System.out.println("Add configuration " + url);
+         log.info("Add configuration " + url);
       if (url == null)
          return;
       try
@@ -154,20 +175,18 @@
                   conf = unmarshaller.unmarshall(urlObject);
                   configurations_.mergeConfiguration(conf);
                   if (LOG_DEBUG)
-                     System.out.println("\timport " + urlObject);
+                     log.info("\timport " + urlObject);
                }
                else
                {
-                  System.err.println("WARNING: Couldn't process the URL for " + uri + " configuration file ignored ");
+                  log.warn("Couldn't process the URL for " + uri + " configuration file ignored ");
                }
             }
          }
       }
       catch (Exception ex)
       {
-         // System .err.println("Error: " + ex.getMessage());
-         System.err.println("ERROR: cannot process the configuration " + url);
-         ex.printStackTrace();
+         log.error("Cannot process the configuration " + url, ex);
       }
       finally
       {
@@ -247,6 +266,11 @@
 
    public URL getURL(String url) throws Exception
    {
+      return getURL(scontext_, url);
+   }
+
+   private URL getURL(ServletContext context, String url) throws Exception
+   {
       if (url.startsWith("jar:"))
       {
          String path = removePrefix("jar:/", url);
@@ -262,9 +286,9 @@
       else if (url.startsWith("war:"))
       {
          String path = removePrefix("war:", url);
-         if (scontext_ != null)
+         if (context != null)
          {
-            return scontext_.getResource(WAR_CONF_LOCATION + path);
+            return context.getResource(WAR_CONF_LOCATION + path);
          }
          if (scontextClassLoader_ != null)
          {
@@ -324,7 +348,21 @@
             {
                String value = null;
                String key = input.substring(start + 2, i);
-               value = System.getProperty(key);
+               if (key.equals(EXO_CONTAINER_PROP_NAME))
+               {
+                  // The requested key is the name of current container
+                  ExoContainer container = ExoContainerContext.getCurrentContainerIfPresent();
+                  if (container instanceof PortalContainer)
+                  {
+                     // The current container is a portal container
+                     RootContainer rootContainer = (RootContainer)ExoContainerContext.getTopContainer();
+                     value = rootContainer.isPortalContainerConfigAware() ? "_" + container.getContext().getName() : "";
+                  }
+               }
+               else
+               {
+                  value = System.getProperty(key);
+               }
                if (value != null)
                {
                   properties = true;

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerConfig.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerConfig.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerConfig.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.container.definition;
+
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.container.RootContainer;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.ValueParam;
+import org.picocontainer.Startable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+/**
+ * This class is used to define the configuration related to the portal containers themselves. 
+ * It is mainly dedicated to the {@link RootContainer} to allows to understand how to manage and 
+ * deploy all the portal containers
+ * 
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ *          nicolas.filotto at exoplatform.com
+ * 26 aožt 2009  
+ */
+public class PortalContainerConfig implements Startable
+{
+
+   /**
+    * The default name of a portal container
+    */
+   public static final String DEFAULT_PORTAL_CONTAINER_NAME = "portal";
+
+   /**
+    * The default name of a the {@link ServletContext} of the rest web application
+    */
+   public static final String DEFAULT_REST_CONTEXT_NAME = "rest";
+
+   /**
+    * The default realm name
+    */
+   public static final String DEFAULT_REALM_NAME = "exo-domain";
+
+   /**
+    * The name of the default portal container
+    */
+   private String defaultPortalContainerName;
+
+   /**
+    * The name of the default rest {@link ServletContext}
+    */
+   private String defaultRestContextName;
+
+   /**
+    * The name of the default realm
+    */
+   private String defaultRealmName;
+
+   /**
+    * Indicates if the component has already been initialized
+    */
+   private volatile boolean initialized;
+
+   /**
+    * The list of all the portal containers
+    */
+   private List<String> portalContainerNames;
+
+   /**
+    * The list of all the web application scopes
+    */
+   private Map<String, List<String>> scopes;
+
+   /**
+    * The list of all the {@link PortalContainerDefinition} that have been registered
+    */
+   private Map<String, PortalContainerDefinition> definitions =
+      Collections.unmodifiableMap(new HashMap<String, PortalContainerDefinition>());
+
+   public PortalContainerConfig()
+   {
+      this(null);
+   }
+
+   public PortalContainerConfig(InitParams params)
+   {
+      if (params == null)
+      {
+         return;
+      }
+      final ValueParam vDpc = params.getValueParam("default.portal.container");
+      if (vDpc != null && vDpc.getValue().trim().length() > 0)
+      {
+         this.defaultPortalContainerName = vDpc.getValue().trim();
+      }
+      final ValueParam vRc = params.getValueParam("default.rest.context");
+      if (vRc != null && vRc.getValue().trim().length() > 0)
+      {
+         this.defaultRestContextName = vRc.getValue().trim();
+      }
+      final ValueParam vRn = params.getValueParam("default.realm.name");
+      if (vRn != null && vRn.getValue().trim().length() > 0)
+      {
+         this.defaultRealmName = vRn.getValue().trim();
+      }
+   }
+
+   /**
+    * @return the default name of the portal container
+    */
+   public String getDefaultPortalContainer()
+   {
+      return defaultPortalContainerName;
+   }
+
+   /**
+    * @return the default name of the rest {@link ServletContext}
+    */
+   public String getDefaultRestContext()
+   {
+      return defaultRestContextName;
+   }
+
+   /**
+    * @return the default name of the realm
+    */
+   public String getDefaultRealmName()
+   {
+      return defaultRealmName;
+   }
+
+   /**
+    * Indicates if at least one portal container definition has been defined. If no portal definition
+    * has been defined, we assume that we want the old behavior
+    * @return <code>true</code> if at least one definition has been set, <code>false</code> otherwise
+    */
+   public boolean hasDefinition()
+   {
+      return !definitions.isEmpty();
+   }
+
+   /**
+    * Registers a name of a portal container if it has not yet been registered
+    * @param name the name of the portal container to register
+    */
+   public synchronized void registerPortalContainerName(String name)
+   {
+      if (!portalContainerNames.contains(name))
+      {
+         final List<String> lPortalContainerNames = new ArrayList<String>(portalContainerNames.size() + 1);
+         lPortalContainerNames.add(name);
+         lPortalContainerNames.addAll(portalContainerNames);
+         this.portalContainerNames = Collections.unmodifiableList(lPortalContainerNames);
+      }
+   }
+
+   /**
+    * Unregisters a name of a portal container if it has not yet been unregistered
+    * @param name the name of the portal container to register
+    */
+   public synchronized void unregisterPortalContainerName(String name)
+   {
+      if (portalContainerNames.contains(name))
+      {
+         final List<String> lPortalContainerNames = new ArrayList<String>(portalContainerNames);
+         lPortalContainerNames.remove(name);
+         this.portalContainerNames = Collections.unmodifiableList(lPortalContainerNames);
+      }
+   }
+
+   /**
+    * Indicates if the given name is the name of a registered portal container
+    * @param name the name to check
+    * @return <code>true</code> if the name is a name of a portal container, <code>false</code>
+    *        otherwise.
+    */
+   public boolean isPortalContainerName(String name)
+   {
+      return name == null ? false : portalContainerNames.contains(name);
+   }
+
+   /**
+    * Gives the list of all the portal container names for which the web application is available
+    * @param contextName the context name of the web application
+    * @return the list of all the portal container names for which the web application is available
+    */
+   public List<String> getPortalContainerNames(String contextName)
+   {
+      if (contextName == null)
+      {
+         throw new IllegalArgumentException("The context name cannot be null");
+      }
+      final List<String> result = scopes.get(contextName);
+      if (result == null || result.isEmpty())
+      {
+         // we assume the old behavior is expected         
+         final String portalContainerName =
+            portalContainerNames.contains(contextName) ? contextName : defaultPortalContainerName;
+         return Collections.singletonList(portalContainerName);
+      }
+      return result;
+   }
+
+   /**
+    * Gives all the dependencies related to the given portal container
+    * @param portalContainerName the name of the portal container for which we want the dependencies
+    * @return a list of sorted context names
+    */
+   public List<String> getDependencies(String portalContainerName)
+   {
+      final PortalContainerDefinition definition = definitions.get(portalContainerName);
+      return definition == null ? null : definition.getDependencies();
+   }
+
+   /**
+    * Gives the name of the rest {@link ServletContext} related to the given portal container
+    * @param portalContainerName the name of the portal container for which we want the rest context name
+    * @return the name of the related rest context name. It tries to get it from the {@link PortalContainerDefinition}
+    * if it has not been set it will return <code>defaultRestContextName</code> 
+    */
+   public String getRestContextName(String portalContainerName)
+   {
+      final PortalContainerDefinition definition = definitions.get(portalContainerName);
+      if (definition == null)
+      {
+         return defaultRestContextName;
+      }
+      else
+      {
+         String contextName = definition.getRestContextName();
+         return contextName == null ? defaultRestContextName : contextName;
+      }
+   }
+
+   /**
+    * Gives the name of the realm related to the given portal container
+    * @param portalContainerName the name of the portal container for which we want the realm name
+    * @return the name of the related realm name. It tries to get it from the {@link PortalContainerDefinition}
+    * if it has not been set it will return <code>defaultRealmName</code> 
+    */
+   public String getRealmName(String portalContainerName)
+   {
+      final PortalContainerDefinition definition = definitions.get(portalContainerName);
+      if (definition == null)
+      {
+         return defaultRealmName;
+      }
+      else
+      {
+         String realmName = definition.getRealmName();
+         return realmName == null ? defaultRealmName : realmName;
+      }
+   }
+
+   /**
+    * Indicates if the given servlet context is a dependency of the given portal container
+    * @param portalContainerName the name of the portal container
+    * @param contextName the name of the {@link ServletContext}
+    * @return <code>true</code> if the dependencies matches, <code>false</code> otherwise;
+    */
+   public boolean isScopeValid(String portalContainerName, String contextName)
+   {
+      final List<String> result = scopes.get(contextName);
+      if (result == null || result.isEmpty())
+      {
+         // we assume the old behavior is expected
+         return true;
+      }
+      else
+      {
+         return result.contains(portalContainerName);
+      }
+   }
+
+   /**
+    * Allow to define a set of {@link PortalContainerDefinition}
+    * @param plugin the plugin that contains all the {@link PortalContainerDefinition} to define
+    */
+   public void registerPlugin(PortalContainerDefinitionPlugin plugin)
+   {
+      final List<PortalContainerDefinition> lDefs = plugin.getPortalContainerDefinitions();
+      if (lDefs != null && !lDefs.isEmpty())
+      {
+         synchronized (this)
+         {
+            if (initialized)
+            {
+               throw new IllegalStateException("The PortalContainerConfig has already been initialized");
+            }
+            final Map<String, PortalContainerDefinition> tempDefinitions =
+               new HashMap<String, PortalContainerDefinition>(definitions);
+            for (PortalContainerDefinition def : lDefs)
+            {
+               String name = def.getName();
+               if (name == null || (name = name.trim()).length() == 0)
+               {
+                  continue;
+               }
+               else
+               {
+                  // Ensure that the name doesn't contain any useless characters 
+                  def.setName(name);
+               }
+               tempDefinitions.put(name, def);
+            }
+            this.definitions = Collections.unmodifiableMap(tempDefinitions);
+         }
+      }
+   }
+
+   /**
+    * Construct the scopes of all the web applications from the given {@link PortalContainerDefinition}
+    * @param definition the definition of a {@link PortalContainer} that contains the dependencies with
+    * the web application
+    * @param scopes the map in which the scope must be defined
+    */
+   private void registerDependencies(PortalContainerDefinition definition, Map<String, List<String>> scopes)
+   {
+      final List<String> dependencies = definition.getDependencies();
+      if (definition == null || dependencies.isEmpty())
+      {
+         return;
+      }
+      for (String context : dependencies)
+      {
+         if (context == null || (context = context.trim()).length() == 0)
+         {
+            continue;
+         }
+         List<String> lPortalContainerNames = scopes.get(context);
+         if (lPortalContainerNames == null)
+         {
+            // There is no 
+            lPortalContainerNames = new ArrayList<String>();
+         }
+         else
+         {
+            // The existing collection is unmodifiable thus we need to create a new one
+            lPortalContainerNames = new ArrayList<String>(lPortalContainerNames);
+         }
+         lPortalContainerNames.add(definition.getName());
+         scopes.put(context, Collections.unmodifiableList(lPortalContainerNames));
+      }
+   }
+
+   /**
+    * Initialize the current component
+    * @param mDefinitions the list of all the portal container definition to treat
+    */
+   private void initialize(Map<String, PortalContainerDefinition> mDefinitions)
+   {
+      if (mDefinitions.isEmpty())
+      {
+         // No definitions have been found, the default values will be set
+         if (defaultPortalContainerName == null)
+         {
+            this.defaultPortalContainerName = DEFAULT_PORTAL_CONTAINER_NAME;
+         }
+      }
+      final List<String> lPortalContainerNames = new ArrayList<String>(mDefinitions.size() + 1);
+      // Add the default portal container name
+      if (defaultPortalContainerName != null)
+      {
+         lPortalContainerNames.add(defaultPortalContainerName);
+      }
+      final Map<String, List<String>> mScopes = new HashMap<String, List<String>>();
+      for (Map.Entry<String, PortalContainerDefinition> entry : mDefinitions.entrySet())
+      {
+         PortalContainerDefinition definition = entry.getValue();
+         String name = definition.getName();
+         if (!name.equals(defaultPortalContainerName))
+         {
+            if (defaultPortalContainerName == null)
+            {
+               this.defaultPortalContainerName = name;
+            }
+            lPortalContainerNames.add(name);
+         }
+         if (defaultRestContextName == null)
+         {
+            this.defaultRestContextName = definition.getRestContextName();
+         }
+         if (defaultRealmName == null)
+         {
+            this.defaultRealmName = definition.getRealmName();
+         }
+         registerDependencies(definition, mScopes);
+      }
+      this.portalContainerNames = Collections.unmodifiableList(lPortalContainerNames);
+      this.scopes = Collections.unmodifiableMap(mScopes);
+      if (defaultRestContextName == null)
+      {
+         this.defaultRestContextName = DEFAULT_REST_CONTEXT_NAME;
+      }
+      if (defaultRealmName == null)
+      {
+         this.defaultRealmName = DEFAULT_REALM_NAME;
+      }
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void start()
+   {
+      if (!initialized)
+      {
+         synchronized (this)
+         {
+            if (!initialized)
+            {
+               // Prevent to add new definitions after initializing the PortalContainerConfig
+               this.initialized = true;
+            }
+            else
+            {
+               // The PortalContainerConfig has already been initialized 
+               return;
+            }
+         }
+      }
+      else
+      {
+         // The PortalContainerConfig has already been initialized 
+         return;
+      }
+      initialize(definitions);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   public void stop()
+   {
+   }
+}

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerDefinition.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerDefinition.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerDefinition.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.container.definition;
+
+import org.exoplatform.container.PortalContainer;
+
+import java.util.List;
+
+import javax.servlet.ServletContext;
+
+/**
+ * This class is used to define a {@link PortalContainer} and its dependencies. The dependencies
+ * are in fact all the web applications that the {@link PortalContainer} needs to be properly 
+ * initialized. Be aware that the dependency order is used to define the initialization order. 
+ * 
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ *          nicolas.filotto at exoplatform.com
+ * 8 sept. 2009  
+ */
+public class PortalContainerDefinition
+{
+
+   /**
+    * The name of the related {@link PortalContainer}
+    */
+   private String name;
+
+   /**
+    * The realm name of the related {@link PortalContainer}
+    */
+   private String realmName;
+   
+   /**
+    * The name of the {@link ServletContext} of the rest web application
+    */
+   private String restContextName;
+   
+   /**
+    * The list of all the context names that are needed to initialized properly the
+    * {@link PortalContainer}. The order of all the dependencies will define the initialization order 
+    */
+   private List<String> dependencies;
+
+   public String getName()
+   {
+      return name;
+   }
+
+   public void setName(String name)
+   {
+      this.name = name;
+   }
+
+   public List<String> getDependencies()
+   {
+      return dependencies;
+   }
+
+   public void setDependencies(List<String> dependencies)
+   {
+      this.dependencies = dependencies;
+   }
+
+   public String getRealmName()
+   {
+      return realmName;
+   }
+
+   public void setRealmName(String realmName)
+   {
+      this.realmName = realmName;
+   }
+
+   public String getRestContextName()
+   {
+      return restContextName;
+   }
+
+   public void setRestContextName(String restContextName)
+   {
+      this.restContextName = restContextName;
+   }
+}

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerDefinitionPlugin.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerDefinitionPlugin.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/definition/PortalContainerDefinitionPlugin.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.container.definition;
+
+import org.exoplatform.container.component.BaseComponentPlugin;
+import org.exoplatform.container.xml.InitParams;
+
+import java.util.List;
+
+/**
+ * This class allows you to dynamically define a new portal container with all its dependencies
+ *  
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ *          nicolas.filotto at exoplatform.com
+ * 8 sept. 2009  
+ */
+public class PortalContainerDefinitionPlugin extends BaseComponentPlugin
+{
+
+   /**
+    * The initial parameter of this plugin
+    */
+   private final InitParams params;
+
+   public PortalContainerDefinitionPlugin(InitParams params)
+   {
+      this.params = params;
+   }
+
+   /**
+    * @return all the {@link PortalContainerDefinition} related to this plugin
+    */
+   public List<PortalContainerDefinition> getPortalContainerDefinitions()
+   {
+      return params.getObjectParamValues(PortalContainerDefinition.class);
+   }
+}

Modified: kernel/trunk/container/src/main/java/org/exoplatform/container/util/ContainerUtil.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/util/ContainerUtil.java	2009-10-04 19:39:27 UTC (rev 206)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/util/ContainerUtil.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -74,7 +74,9 @@
          // deploy them to a temp dir and include both jars, the one in sar and tmp
          // dir,
          // in the class path. It cause the configuration run twice
-         int index = key.lastIndexOf("exo-");
+         int index1 = key.lastIndexOf("exo-");
+         int index2 = key.lastIndexOf("exo.");
+         int index = index1 < index2 ? index2 : index1; 
          if (index >= 0)
             key = key.substring(index);
          map.put(key, url);

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractFilter.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractFilter.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractFilter.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.container.web;
+
+import org.exoplatform.container.ExoContainer;
+import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.container.RootContainer;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+/**
+ * This class is the root class of all the Filters that require an ExoContainer 
+ * 
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ *          nicolas.filotto at exoplatform.com
+ * 21 aožt 2009  
+ */
+public abstract class AbstractFilter implements Filter
+{
+
+   /**
+    * The filter configuration
+    */
+   protected FilterConfig config;
+
+   /**
+    * The Servlet context name
+    */
+   protected String servletContextName;
+
+   /**
+    * Indicates if we need a portal environment.
+    */
+   private volatile Boolean requirePortalEnvironment;
+
+   /**
+    * {@inheritDoc}
+    */
+   public final void init(FilterConfig config) throws ServletException
+   {
+      this.config = config;
+      this.servletContextName = config.getServletContext().getServletContextName();
+      afterInit(config);
+   }
+
+   /**
+    * Allows sub-classes to initialize 
+    * @param config the current filter configuration
+    */
+   protected void afterInit(FilterConfig config) throws ServletException
+   {
+   }
+
+   /**
+    * @return Gives the {@link ExoContainer} that fits best with the current context
+    */
+   protected final ExoContainer getContainer()
+   {
+      ExoContainer container = ExoContainerContext.getCurrentContainer();
+      if (container instanceof RootContainer)
+      {
+         // The top container is a RootContainer, thus we assume that we are in a portal mode
+         container = PortalContainer.getCurrentInstance(config.getServletContext());
+         if (container == null)
+         {
+            container = ExoContainerContext.getTopContainer();
+         }
+      }
+      // The container is a PortalContainer or a StandaloneContainer
+      return container;
+   }
+
+   /**
+    * Indicates if it requires that a full portal environment must be set
+    * @return <code>true</code> if it requires the portal environment <code>false</code> otherwise.
+    */
+   protected boolean requirePortalEnvironment()
+   {
+      if (requirePortalEnvironment == null)
+      {
+         synchronized (this)
+         {
+            if (requirePortalEnvironment == null)
+            {
+               this.requirePortalEnvironment = PortalContainer.isPortalContainerName(servletContextName);
+            }
+         }
+      }
+      return requirePortalEnvironment.booleanValue();
+   }
+
+   /**
+    * @return the current {@link ServletContext}
+    */
+   protected ServletContext getServletContext()
+   {
+      if (requirePortalEnvironment())
+      {
+         ExoContainer container = getContainer();
+         if (container instanceof PortalContainer)
+         {
+            return ((PortalContainer)container).getPortalContext();
+         }
+      }
+      return config.getServletContext();
+   }
+}

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractHttpServlet.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractHttpServlet.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractHttpServlet.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see&lt;http://www.gnu.org/licenses/&gt;.
+ */
+package org.exoplatform.container.web;
+
+import org.exoplatform.container.ExoContainer;
+import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.container.RootContainer;
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto 
+ *          nicolas.filotto at exoplatform.com
+ * 29 sept. 2009  
+ */
+public abstract class AbstractHttpServlet extends HttpServlet
+{
+
+   /**
+    * Serial Version ID.
+    */
+   private static final long serialVersionUID = -3302886470677004895L;
+
+   /**
+    * The filter configuration
+    */
+   protected ServletConfig config;
+
+   /**
+    * The Servlet context name
+    */
+   protected String servletContextName;
+
+   /**
+    * Indicates if we need a portal environment.
+    */
+   private volatile Boolean requirePortalEnvironment;
+
+   /**
+    * {@inheritDoc}
+    */
+   public final void init(ServletConfig config) throws ServletException
+   {
+      super.init(config);
+      this.config = config;
+      this.servletContextName = config.getServletContext().getServletContextName();
+      afterInit(config);
+   }
+
+   /**
+    * Allows sub-classes to initialize 
+    * @param config the current servlet configuration
+    */
+   protected void afterInit(ServletConfig config) throws ServletException
+   {
+   }
+
+   /**
+    * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+    */
+   public final void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
+   {
+      final ExoContainer oldContainer = ExoContainerContext.getCurrentContainer();
+      // Keep the old ClassLoader
+      final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+      ExoContainer container = null;
+      boolean hasBeenSet = false;
+      try
+      {
+         container = getContainer();
+         if (!container.equals(oldContainer))
+         {
+            if (container instanceof PortalContainer)
+            {
+               PortalContainer.setInstance((PortalContainer)container);
+            }
+            ExoContainerContext.setCurrentContainer(container);
+            hasBeenSet = true;
+         }
+         if (requirePortalEnvironment() && container instanceof PortalContainer)
+         {
+            if (PortalContainer.getInstanceIfPresent() == null)
+            {
+               // The portal container has not been set
+               PortalContainer.setInstance((PortalContainer)container);
+               hasBeenSet = true;
+            }
+            // Set the full classloader of the portal container
+            Thread.currentThread().setContextClassLoader(((PortalContainer)container).getPortalClassLoader());
+         }
+         onService(container, req, res);
+      }
+      finally
+      {
+         if (hasBeenSet)
+         {
+            if (container instanceof PortalContainer)
+            {
+               // Remove the current Portal Container and the current ExoContainer
+               PortalContainer.setInstance(null);
+            }
+            // Re-set the old container
+            ExoContainerContext.setCurrentContainer(oldContainer);
+         }
+         if (requirePortalEnvironment())
+         {
+            // Re-set the old classloader
+            Thread.currentThread().setContextClassLoader(currentClassLoader);
+         }
+      }
+   }
+
+   /**
+    * Indicates if it requires that a full portal environment must be set
+    * @return <code>true</code> if it requires the portal environment <code>false</code> otherwise.
+    */
+   protected boolean requirePortalEnvironment()
+   {
+      if (requirePortalEnvironment == null)
+      {
+         synchronized (this)
+         {
+            if (requirePortalEnvironment == null)
+            {
+               this.requirePortalEnvironment = PortalContainer.isPortalContainerName(servletContextName);
+            }
+         }
+      }
+      return requirePortalEnvironment.booleanValue();
+   }
+
+   /**
+    * Allow the sub classes to execute a task when the method <code>service</code> is called 
+    * @param container the eXo container
+    * @param req the {@link HttpServletRequest}
+    * @param res the {@link HttpServletResponse}
+    */
+   protected void onService(ExoContainer container, HttpServletRequest req, HttpServletResponse res)
+      throws ServletException, IOException
+   {
+      // Dispatches to the right HTTP method
+      super.service(req, res);
+   }
+
+   /**
+    * @return Gives the {@link ExoContainer} that fits best with the current context
+    */
+   protected final ExoContainer getContainer()
+   {
+      ExoContainer container = ExoContainerContext.getCurrentContainer();
+      if (container instanceof RootContainer)
+      {
+         // The top container is a RootContainer, thus we assume that we are in a portal mode
+         container = PortalContainer.getCurrentInstance(config.getServletContext());
+         if (container == null)
+         {
+            container = ExoContainerContext.getTopContainer();
+         }
+      }
+      // The container is a PortalContainer or a StandaloneContainer
+      return container;
+   }
+
+   /**
+    * @return the current {@link ServletContext}
+    */
+   @Override
+   public ServletContext getServletContext()
+   {
+      if (requirePortalEnvironment())
+      {
+         ExoContainer container = getContainer();
+         if (container instanceof PortalContainer)
+         {
+            return ((PortalContainer)container).getPortalContext();
+         }
+      }
+      return super.getServletContext();
+   }
+}

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractHttpSessionListener.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractHttpSessionListener.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/web/AbstractHttpSessionListener.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see&lt;http://www.gnu.org/licenses/&gt;.
+ */
+package org.exoplatform.container.web;
+
+import org.exoplatform.container.ExoContainer;
+import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.container.RootContainer;
+
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto 
+ *          nicolas.filotto at exoplatform.com
+ * 29 sept. 2009  
+ */
+public abstract class AbstractHttpSessionListener implements HttpSessionListener
+{
+
+   /**
+    * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent)
+    */
+   public final void sessionCreated(HttpSessionEvent event)
+   {
+      final ExoContainer oldContainer = ExoContainerContext.getCurrentContainer();
+      // Keep the old ClassLoader
+      final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+      ExoContainer container = null;
+      boolean hasBeenSet = false;
+      try
+      {
+         container = getContainer(event);
+         if (!container.equals(oldContainer))
+         {
+            if (container instanceof PortalContainer)
+            {
+               PortalContainer.setInstance((PortalContainer)container);
+            }
+            ExoContainerContext.setCurrentContainer(container);
+            hasBeenSet = true;
+         }
+         if (requirePortalEnvironment() && container instanceof PortalContainer)
+         {
+            if (PortalContainer.getInstanceIfPresent() == null)
+            {
+               // The portal container has not been set
+               PortalContainer.setInstance((PortalContainer)container);
+               hasBeenSet = true;
+            }
+            // Set the full classloader of the portal container
+            Thread.currentThread().setContextClassLoader(((PortalContainer)container).getPortalClassLoader());
+         }
+         onSessionCreated(container, event);
+      }
+      finally
+      {
+         if (hasBeenSet)
+         {
+            if (container instanceof PortalContainer)
+            {
+               // Remove the current Portal Container and the current ExoContainer
+               PortalContainer.setInstance(null);
+            }
+            // Re-set the old container
+            ExoContainerContext.setCurrentContainer(oldContainer);
+         }
+         if (requirePortalEnvironment())
+         {
+            // Re-set the old classloader
+            Thread.currentThread().setContextClassLoader(currentClassLoader);
+         }
+      }
+   }
+
+   /**
+    * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
+    */
+   public final void sessionDestroyed(HttpSessionEvent event)
+   {
+      final ExoContainer oldContainer = ExoContainerContext.getCurrentContainer();
+      // Keep the old ClassLoader
+      final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+      ExoContainer container = null;
+      boolean hasBeenSet = false;
+      try
+      {
+         container = getContainer(event);
+         if (!container.equals(oldContainer))
+         {
+            if (container instanceof PortalContainer)
+            {
+               PortalContainer.setInstance((PortalContainer)container);
+            }
+            ExoContainerContext.setCurrentContainer(container);
+            hasBeenSet = true;
+         }
+         if (requirePortalEnvironment() && container instanceof PortalContainer)
+         {
+            if (PortalContainer.getInstanceIfPresent() == null)
+            {
+               // The portal container has not been set
+               PortalContainer.setInstance((PortalContainer)container);
+               hasBeenSet = true;
+            }
+            // Set the full classloader of the portal container
+            Thread.currentThread().setContextClassLoader(((PortalContainer)container).getPortalClassLoader());
+         }
+         onSessionDestroyed(container, event);
+      }
+      finally
+      {
+         if (hasBeenSet)
+         {
+            if (container instanceof PortalContainer)
+            {
+               // Remove the current Portal Container and the current ExoContainer
+               PortalContainer.setInstance(null);
+            }
+            // Re-set the old container
+            ExoContainerContext.setCurrentContainer(oldContainer);
+         }
+         if (requirePortalEnvironment())
+         {
+            // Re-set the old classloader
+            Thread.currentThread().setContextClassLoader(currentClassLoader);
+         }
+      }
+   }
+
+   /**
+    * Indicates if it requires that a full portal environment must be set
+    * @return <code>true</code> if it requires the portal environment <code>false</code> otherwise.
+    */
+   protected abstract boolean requirePortalEnvironment();
+
+   /**
+    * Allow sub-classes to execute an action when a session is created
+    * @param container the eXo container
+    * @param event the {@link HttpSessionEvent}
+    */
+   protected abstract void onSessionCreated(ExoContainer container, HttpSessionEvent event);
+
+   /**
+    * Allow sub-classes to execute an action when a session is destroyed
+    * @param container the eXo container
+    * @param event the {@link HttpSessionEvent}
+    */
+   protected abstract void onSessionDestroyed(ExoContainer container, HttpSessionEvent event);
+
+   /**
+    * @return Gives the {@link ExoContainer} that fits best with the current context
+    */
+   protected final ExoContainer getContainer(HttpSessionEvent event)
+   {
+      ExoContainer container = ExoContainerContext.getCurrentContainer();
+      if (container instanceof RootContainer)
+      {
+         // The top container is a RootContainer, thus we assume that we are in a portal mode
+         container = PortalContainer.getCurrentInstance(event.getSession().getServletContext());
+         if (container == null)
+         {
+            container = ExoContainerContext.getTopContainer();
+         }
+      }
+      // The container is a PortalContainer or a StandaloneContainer
+      return container;
+   }
+}

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/web/PortalContainerConfigOwner.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/web/PortalContainerConfigOwner.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/web/PortalContainerConfigOwner.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.container.web;
+
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.container.RootContainer.PortalContainerPostInitTask;
+import org.exoplatform.container.RootContainer.PortalContainerPreInitTask;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+/**
+ * This class is used to indicated that this servlet context provides resources and/or configuration
+ * files to the associated portal containers
+ * 
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ *          nicolas.filotto at exoplatform.com
+ * 14 sept. 2009  
+ */
+public class PortalContainerConfigOwner implements ServletContextListener
+{
+
+   public void contextInitialized(ServletContextEvent event)
+   {
+      final PortalContainerPreInitTask task = new PortalContainerPreInitTask()
+      {
+
+         public void execute(ServletContext context, PortalContainer portalContainer)
+         {
+            portalContainer.registerContext(context);
+         }
+      };
+      PortalContainer.addInitTask(event.getServletContext(), task);
+   }
+
+   public void contextDestroyed(ServletContextEvent event)
+   {
+      final PortalContainerPostInitTask task = new PortalContainerPostInitTask()
+      {
+
+         public void execute(ServletContext context, PortalContainer portalContainer)
+         {
+            portalContainer.unregisterContext(context);
+         }
+      };
+      PortalContainer.addInitTask(event.getServletContext(), task);
+   }
+}

Added: kernel/trunk/container/src/main/java/org/exoplatform/container/web/PortalContainerCreator.java
===================================================================
--- kernel/trunk/container/src/main/java/org/exoplatform/container/web/PortalContainerCreator.java	                        (rev 0)
+++ kernel/trunk/container/src/main/java/org/exoplatform/container/web/PortalContainerCreator.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see<http://www.gnu.org/licenses/>.
+ */
+package org.exoplatform.container.web;
+
+import org.exoplatform.container.RootContainer;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+/**
+ * This class is used to create and initialize all the portal containers that have been
+ * registered previously
+ * 
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto
+ *          nicolas.filotto at exoplatform.com
+ * 9 sept. 2009  
+ */
+public class PortalContainerCreator implements ServletContextListener
+{
+
+   /**
+    * {@inheritDoc}
+    */
+   public void contextDestroyed(ServletContextEvent event)
+   {
+   }
+
+   /**
+    * Initializes and creates all the portal container that have been registered previously
+    */
+   public void contextInitialized(ServletContextEvent event)
+   {
+      RootContainer rootContainer = RootContainer.getInstance();
+      rootContainer.createPortalContainers();
+   }
+}

Added: kernel/trunk/container/src/test/java/org/exoplatform/container/TestPortalContainerInitTaskContextComparator.java
===================================================================
--- kernel/trunk/container/src/test/java/org/exoplatform/container/TestPortalContainerInitTaskContextComparator.java	                        (rev 0)
+++ kernel/trunk/container/src/test/java/org/exoplatform/container/TestPortalContainerInitTaskContextComparator.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see&lt;http://www.gnu.org/licenses/&gt;.
+ */
+package org.exoplatform.container;
+
+import junit.framework.TestCase;
+
+import org.exoplatform.container.RootContainer.PortalContainerInitTaskContext;
+import org.exoplatform.container.RootContainer.PortalContainerInitTaskContextComparator;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Set;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto 
+ *          nicolas.filotto at exoplatform.com
+ * 24 sept. 2009  
+ */
+ at SuppressWarnings("unchecked")
+public class TestPortalContainerInitTaskContextComparator extends TestCase
+{
+ 
+   public void testCompare()
+   {
+      PortalContainerInitTaskContextComparator comparator = new PortalContainerInitTaskContextComparator(Arrays.asList("d", "c"));
+      PortalContainerInitTaskContext[] contexts =
+         {createPortalContainerInitTaskContext("b"), createPortalContainerInitTaskContext("d"), createPortalContainerInitTaskContext("a"),
+         createPortalContainerInitTaskContext("c")};
+      Arrays.sort(contexts, comparator);
+      assertEquals("d", contexts[0].getServletContextName());
+      assertEquals("c", contexts[1].getServletContextName());
+      assertEquals("a", contexts[2].getServletContextName());
+      assertEquals("b", contexts[3].getServletContextName());
+   }
+   
+
+   private PortalContainerInitTaskContext createPortalContainerInitTaskContext(String name)
+   {
+      return new PortalContainerInitTaskContext(new MockServletContext(name), null);
+   }
+      
+   private static class MockServletContext implements ServletContext
+   {
+
+      private final String name;
+
+      private MockServletContext(String name)
+      {
+         this.name = name;
+      }
+
+      public Object getAttribute(String name)
+      {
+
+         return null;
+      }
+
+      public Enumeration getAttributeNames()
+      {
+
+         return null;
+      }
+
+      public ServletContext getContext(String uripath)
+      {
+
+         return null;
+      }
+
+      public String getInitParameter(String name)
+      {
+
+         return null;
+      }
+
+      public Enumeration getInitParameterNames()
+      {
+
+         return null;
+      }
+
+      public int getMajorVersion()
+      {
+
+         return 0;
+      }
+
+      public String getMimeType(String file)
+      {
+
+         return null;
+      }
+
+      public int getMinorVersion()
+      {
+
+         return 0;
+      }
+
+      public RequestDispatcher getNamedDispatcher(String name)
+      {
+
+         return null;
+      }
+
+      public String getRealPath(String path)
+      {
+
+         return null;
+      }
+
+      public RequestDispatcher getRequestDispatcher(String path)
+      {
+
+         return null;
+      }
+
+      public URL getResource(String path) throws MalformedURLException
+      {
+
+         return null;
+      }
+
+      public InputStream getResourceAsStream(String path)
+      {
+
+         return null;
+      }
+
+      public Set getResourcePaths(String path)
+      {
+
+         return null;
+      }
+
+      public String getServerInfo()
+      {
+
+         return null;
+      }
+
+      public Servlet getServlet(String name) throws ServletException
+      {
+
+         return null;
+      }
+
+      public String getServletContextName()
+      {
+         return name;
+      }
+
+      public Enumeration getServletNames()
+      {
+
+         return null;
+      }
+
+      public Enumeration getServlets()
+      {
+
+         return null;
+      }
+
+      public void log(String msg)
+      {
+
+      }
+
+      public void log(Exception exception, String msg)
+      {
+
+      }
+
+      public void log(String message, Throwable throwable)
+      {
+
+      }
+
+      public void removeAttribute(String name)
+      {
+
+      }
+
+      public void setAttribute(String name, Object object)
+      {
+
+      }
+
+   }   
+}

Added: kernel/trunk/container/src/test/java/org/exoplatform/container/TestUnifiedClassLoader.java
===================================================================
--- kernel/trunk/container/src/test/java/org/exoplatform/container/TestUnifiedClassLoader.java	                        (rev 0)
+++ kernel/trunk/container/src/test/java/org/exoplatform/container/TestUnifiedClassLoader.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see&lt;http://www.gnu.org/licenses/&gt;.
+ */
+package org.exoplatform.container;
+
+import junit.framework.TestCase;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto 
+ *          nicolas.filotto at exoplatform.com
+ * 24 sept. 2009  
+ */
+public class TestUnifiedClassLoader extends TestCase
+{
+
+   public void testConstructor()
+   {
+      try
+      {
+         new UnifiedClassLoader();
+         fail("An IllegalArgumentException is expected");
+      }
+      catch (IllegalArgumentException e)
+      {
+      }
+      try
+      {
+         new UnifiedClassLoader(new ClassLoader[0]);
+         fail("An IllegalArgumentException is expected");
+      }
+      catch (IllegalArgumentException e)
+      {
+      }      
+   }
+   
+   public void testGetResource() throws Exception
+   {
+      UnifiedClassLoader mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(null, null), new MockClassLoader(null, null)});
+      assertNull(mcl.getResource(null));
+      URL result = new URL("file:///foo");
+      mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(null, null), new MockClassLoader(result, null)});
+      assertEquals(result, mcl.getResource(null));      
+      mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(result, null), new MockClassLoader(null, null)});
+      assertEquals(result, mcl.getResource(null));      
+      mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(new URL("file:///foo2"), null), new MockClassLoader(result, null)});
+      assertEquals(result, mcl.getResource(null));      
+   }
+   
+   public void testGetResources() throws Exception
+   {
+      UnifiedClassLoader mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(null, Collections.enumeration(new ArrayList<URL>())), new MockClassLoader(null, Collections.enumeration(new ArrayList<URL>()))});
+      Enumeration<URL> eResult = mcl.getResources(null);
+      assertNotNull(eResult);
+      assertFalse(eResult.hasMoreElements());
+      mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(null, null), new MockClassLoader(null, null)});
+      eResult = mcl.getResources(null);
+      assertNotNull(eResult);
+      assertFalse(eResult.hasMoreElements());
+      URL result = new URL("file:///foo");
+      mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(null, Collections.enumeration(Arrays.asList(result))), new MockClassLoader(null, Collections.enumeration(new ArrayList<URL>()))});
+      eResult = mcl.getResources(null);
+      assertNotNull(eResult);
+      assertTrue(eResult.hasMoreElements());
+      assertEquals(result, eResult.nextElement());
+      assertFalse(eResult.hasMoreElements());
+      mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(null, Collections.enumeration(Arrays.asList(result))), new MockClassLoader(null, null)});
+      eResult = mcl.getResources(null);
+      assertNotNull(eResult);
+      assertTrue(eResult.hasMoreElements());
+      assertEquals(result, eResult.nextElement());
+      assertFalse(eResult.hasMoreElements());
+      mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(null, Collections.enumeration(new ArrayList<URL>())), new MockClassLoader(null, Collections.enumeration(Arrays.asList(result)))});
+      eResult = mcl.getResources(null);
+      assertNotNull(eResult);
+      assertTrue(eResult.hasMoreElements());
+      assertEquals(result, eResult.nextElement());
+      assertFalse(eResult.hasMoreElements());
+      mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(null, null), new MockClassLoader(null, Collections.enumeration(Arrays.asList(result)))});
+      eResult = mcl.getResources(null);
+      assertNotNull(eResult);
+      assertTrue(eResult.hasMoreElements());
+      assertEquals(result, eResult.nextElement());
+      assertFalse(eResult.hasMoreElements());
+      URL result1 = new URL("file:///foo");      
+      mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(null, Collections.enumeration(Arrays.asList(result))), new MockClassLoader(null, Collections.enumeration(Arrays.asList(result1)))});
+      eResult = mcl.getResources(null);
+      assertNotNull(eResult);
+      assertTrue(eResult.hasMoreElements());
+      assertEquals(result, eResult.nextElement());
+      assertFalse(eResult.hasMoreElements());
+      URL result2 = new URL("file:///foo2");
+      mcl = new UnifiedClassLoader(new ClassLoader[]{new MockClassLoader(null, Collections.enumeration(Arrays.asList(result))), new MockClassLoader(null, Collections.enumeration(Arrays.asList(result2)))});
+      eResult = mcl.getResources(null);
+      assertNotNull(eResult);
+      assertTrue(eResult.hasMoreElements());
+      assertEquals(result, eResult.nextElement());
+      assertTrue(eResult.hasMoreElements());
+      assertEquals(result2, eResult.nextElement());
+      assertFalse(eResult.hasMoreElements());
+   }
+
+   private static class MockClassLoader extends ClassLoader
+   {
+
+      private final URL getResourceResult;
+
+      private final Enumeration<URL> getResourcesResult;
+
+      private MockClassLoader(URL getResourceResult, Enumeration<URL> getResourcesResult)
+      {
+         this.getResourceResult = getResourceResult;
+         this.getResourcesResult = getResourcesResult;
+      }
+
+      public URL getResource(String name)
+      {
+         return getResourceResult;
+      }
+
+      public Enumeration<URL> getResources(String name)
+      {
+         return getResourcesResult;
+      }
+   }
+}

Added: kernel/trunk/container/src/test/java/org/exoplatform/container/TestWebAppInitContextComparator.java
===================================================================
--- kernel/trunk/container/src/test/java/org/exoplatform/container/TestWebAppInitContextComparator.java	                        (rev 0)
+++ kernel/trunk/container/src/test/java/org/exoplatform/container/TestWebAppInitContextComparator.java	2009-10-05 10:19:24 UTC (rev 207)
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2003-2009 eXo Platform SAS.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see&lt;http://www.gnu.org/licenses/&gt;.
+ */
+package org.exoplatform.container;
+
+import junit.framework.TestCase;
+
+import org.exoplatform.container.PortalContainer.WebAppInitContextComparator;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Set;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+/**
+ * Created by The eXo Platform SAS
+ * Author : Nicolas Filotto 
+ *          nicolas.filotto at exoplatform.com
+ * 24 sept. 2009  
+ */
+ at SuppressWarnings("unchecked")
+public class TestWebAppInitContextComparator extends TestCase
+{
+
+   public void testCompare()
+   {
+      WebAppInitContextComparator comparator = new WebAppInitContextComparator(Arrays.asList("d", "c"));
+      WebAppInitContext[] contexts =
+         {createWebAppInitContext("b"), createWebAppInitContext("d"), createWebAppInitContext("a"),
+            createWebAppInitContext("c")};
+      Arrays.sort(contexts, comparator);
+      assertEquals("d", contexts[0].getServletContextName());
+      assertEquals("c", contexts[1].getServletContextName());
+      assertEquals("a", contexts[2].getServletContextName());
+      assertEquals("b", contexts[3].getServletContextName());
+   }
+
+   private WebAppInitContext createWebAppInitContext(String name)
+   {
+      return new WebAppInitContext(new MockServletContext(name));
+   }
+   
+   private static class MockServletContext implements ServletContext
+   {
+
+      private final String name;
+
+      private MockServletContext(String name)
+      {
+         this.name = name;
+      }
+
+      public Object getAttribute(String name)
+      {
+
+         return null;
+      }
+
+      public Enumeration getAttributeNames()
+      {
+
+         return null;
+      }
+
+      public ServletContext getContext(String uripath)
+      {
+
+         return null;
+      }
+
+      public String getInitParameter(String name)
+      {
+
+         return null;
+      }
+
+      public Enumeration getInitParameterNames()
+      {
+
+         return null;
+      }
+
+      public int getMajorVersion()
+      {
+
+         return 0;
+      }
+
+      public String getMimeType(String file)
+      {
+
+         return null;
+      }
+
+      public int getMinorVersion()
+      {
+
+         return 0;
+      }
+
+      public RequestDispatcher getNamedDispatcher(String name)
+      {
+
+         return null;
+      }
+
+      public String getRealPath(String path)
+      {
+
+         return null;
+      }
+
+      public RequestDispatcher getRequestDispatcher(String path)
+      {
+
+         return null;
+      }
+
+      public URL getResource(String path) throws MalformedURLException
+      {
+
+         return null;
+      }
+
+      public InputStream getResourceAsStream(String path)
+      {
+
+         return null;
+      }
+
+      public Set getResourcePaths(String path)
+      {
+
+         return null;
+      }
+
+      public String getServerInfo()
+      {
+
+         return null;
+      }
+
+      public Servlet getServlet(String name) throws ServletException
+      {
+
+         return null;
+      }
+
+      public String getServletContextName()
+      {
+         return name;
+      }
+
+      public Enumeration getServletNames()
+      {
+
+         return null;
+      }
+
+      public Enumeration getServlets()
+      {
+
+         return null;
+      }
+
+      public void log(String msg)
+      {
+
+      }
+
+      public void log(Exception exception, String msg)
+      {
+
+      }
+
+      public void log(String message, Throwable throwable)
+      {
+
+      }
+
+      public void removeAttribute(String name)
+      {
+
+      }
+
+      public void setAttribute(String name, Object object)
+      {
+
+      }
+
+   }
+}



More information about the exo-jcr-commits mailing list