Bug 405261 - [enterprise] Update versions of enterprise components
diff --git a/build.versions b/build.versions
index dd2e5a4..74b9114 100644
--- a/build.versions
+++ b/build.versions
@@ -19,22 +19,30 @@
 org.slf4j.jul=1.7.2.v20121108-1250
 
 # Enterprise Compile
-org.apache.openejb.core=4.0.0.beta-2_v201205260545-virgo-7
-org.apache.openejb.loader=4.0.0.beta-2_v201205041336
-org.apache.openejb.jee=4.0.0.beta-2_v201205041336
+org.apache.openejb.core=4.5.2.virgo-1
+org.apache.openejb.loader=4.5.2
+org.apache.openejb.jee=4.5.2
 javax.validation=1.0.0.GA_v201205091237
 javax.transaction=1.1.1.v201105210645
-org.glassfish.com.sun.faces=2.1.6.v201205171319-virgo-3
+org.glassfish.com.sun.faces=2.1.18.v201304210537-virgo-1
 org.ow2.jotm.jotm-core=2.1.9.v201204271116
 javax.ejb=3.1.1.v201204261316
 org.apache.tomcat.api=7.0.35.v201302120746
 javax.persistence=2.0.4.v201112161009
 javax.annotation=1.1.0.v201108011116
-org.apache.bval=0.3.0.v201205161050
+org.apache.bval=0.5.0
 org.apache.derby=10.8.2.2_v201211210650
 org.eclipse.persistence.core=2.4.1.v20121003-ad44345
 org.eclipse.persistence.jpa=2.4.1.v20121003-ad44345
-org.apache.openwebbeans.tomcat7=1.1.3.v201210311100
+javassist=3.17.1.GA
+org.apache.xbean.finder=3.12.0.v201304201405
+org.apache.openwebbeans.ee=1.1.7.v201304200545
+org.apache.openwebbeans.ee.common=1.1.7.v201304201405
+org.apache.openwebbeans.impl=1.1.7.v201304201405
+org.apache.openwebbeans.spi=1.1.7.v201304201405
+org.apache.openwebbeans.jsf=1.1.7.v201304201405
+org.apache.openwebbeans.tomcat7=1.1.7.v201304201405
+cdi.api=1.0.0.v201105160744
 
 # Test
 ch.qos.logback.classic=1.0.7.v20121108-1250
diff --git a/org.eclipse.virgo.web.enterprise.appdeployer/ivy.xml b/org.eclipse.virgo.web.enterprise.appdeployer/ivy.xml
index 7754f01..1af41e1 100644
--- a/org.eclipse.virgo.web.enterprise.appdeployer/ivy.xml
+++ b/org.eclipse.virgo.web.enterprise.appdeployer/ivy.xml
@@ -13,14 +13,21 @@
 	</publications>
 
 	<dependencies>
-        <dependency org="org.eclipse.virgo.mirrored" name="javax.ejb" rev="${javax.ejb}" conf="compile->runtime"/>
-        <dependency org="org.eclipse.virgo.mirrored" name="javax.servlet" rev="${javax.servlet}" conf="compile->runtime"/>
-        <dependency org="org.eclipse.virgo.mirrored" name="javax.validation" rev="${javax.validation}" conf="compile->runtime"/>
-        <dependency org="org.eclipse.virgo.mirrored" name="org.apache.catalina" rev="${org.apache.catalina}" conf="compile->runtime"/>
-        <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openejb.core" rev="${org.apache.openejb.core}" conf="compile->runtime"/>
-        <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openejb.loader" rev="${org.apache.openejb.loader}" conf="compile->runtime"/>
-        <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openejb.jee" rev="${org.apache.openejb.jee}" conf="compile->runtime"/>
-        <dependency org="org.eclipse.virgo.mirrored" name="org.eclipse.osgi" rev="${org.eclipse.osgi}" conf="compile->runtime"/>
+	  <dependency org="org.eclipse.virgo.mirrored" name="cdi.api" rev="${cdi.api}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="javax.ejb" rev="${javax.ejb}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="javax.servlet" rev="${javax.servlet}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="javax.validation" rev="${javax.validation}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.apache.catalina" rev="${org.apache.catalina}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openejb.core" rev="${org.apache.openejb.core}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openejb.loader" rev="${org.apache.openejb.loader}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openejb.jee" rev="${org.apache.openejb.jee}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openwebbeans.ee" rev="${org.apache.openwebbeans.ee}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openwebbeans.impl" rev="${org.apache.openwebbeans.impl}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openwebbeans.spi" rev="${org.apache.openwebbeans.spi}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openwebbeans.jsf" rev="${org.apache.openwebbeans.jsf}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openwebbeans.tomcat7" rev="${org.apache.openwebbeans.tomcat7}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.apache.xbean.finder" rev="${org.apache.xbean.finder}" conf="compile->runtime"/>
+    <dependency org="org.eclipse.virgo.mirrored" name="org.eclipse.osgi" rev="${org.eclipse.osgi}" conf="compile->runtime"/>
  		<dependency org="org.eclipse.virgo.mirrored" name="org.slf4j.api" rev="${org.slf4j.api}" conf="compile->runtime"/>
         
 		<dependency org="org.eclipse.virgo.medic" name="org.eclipse.virgo.medic" rev="${org.eclipse.virgo.medic}" conf="compile->runtime"/>
diff --git a/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeployerEjb.java b/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeployerEjb.java
index 1add160..5805ff7 100755
--- a/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeployerEjb.java
+++ b/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeployerEjb.java
@@ -65,7 +65,7 @@
 import org.apache.openejb.config.sys.Resource;

 import org.apache.openejb.config.sys.ServiceProvider;

 import org.apache.openejb.loader.SystemInstance;

-import org.apache.openejb.util.ContextUtil;

+import org.apache.openejb.util.Contexts;

 import org.eclipse.virgo.medic.eventlog.LogEvent;

 import org.eclipse.virgo.web.enterprise.openejb.deployer.log.OpenEjbDeployerLogEvents;

 import org.osgi.framework.Bundle;

@@ -117,10 +117,12 @@
 	

 	private Logger logger = LoggerFactory.getLogger(VirgoDeployerEjb.class);

 

-	public VirgoDeployerEjb(String webContextPath, ClassLoader servletClassLoader) {

+	public VirgoDeployerEjb(ServletContext context) {

 		// this custom deployment loader fixes deployment of archived web apps

 		// and sets the webcontextPath as moduleId

-		deploymentLoader = new VirgoDeploymentLoader(webContextPath);

+		webContextPath = context.getContextPath();

+		servletClassLoader = context.getClassLoader();

+		deploymentLoader = new VirgoDeploymentLoader(context);

 		dynamicDeployer = OpenEjbDeployerDSComponent.getDynamicDeployer();

 		if (dynamicDeployer != null) {

 			configurationFactory = new ConfigurationFactory(false, dynamicDeployer);

@@ -129,8 +131,6 @@
 		}

 		assembler = (Assembler) SystemInstance.get().getComponent(org.apache.openejb.spi.Assembler.class);

 

-		this.webContextPath = webContextPath;

-		this.servletClassLoader = servletClassLoader;

 		try {

 			resourceProviders = ServiceUtils

 					.getServiceProvidersByServiceType("Resource");

@@ -153,6 +153,8 @@
 		Properties p = new Properties();

 

 		AppModule appModule = null;

+		ClassLoader webAppClassLoader = null;

+		

 		try {

 			File file = new File(loc);

 			appModule = deploymentLoader.load(file);

@@ -165,7 +167,10 @@
 			// set resources

 			processResources(appModule, standardContext);

 

+//			ClassLoader old = Thread.currentThread().getContextClassLoader();

+//			Thread.currentThread().setContextClassLoader(Assembler.class.getClassLoader());

 			final AppInfo appInfo = configurationFactory.configureApplication(appModule);

+//			Thread.currentThread().setContextClassLoader(old);

 			if (p != null && p.containsKey(OPENEJB_DEPLOYER_FORCED_APP_ID_PROP)) {

 				appInfo.appId = p.getProperty(OPENEJB_DEPLOYER_FORCED_APP_ID_PROP);

 			}

@@ -200,6 +205,10 @@
 				throw (OpenEJBException) e;

 			}

 			throw new OpenEJBException("Error while deploying application with real path '" + loc + "' and web context path '" + this.webContextPath + "'.", e);

+		} finally {

+			if(webAppClassLoader != null) {

+				Thread.currentThread().setContextClassLoader(webAppClassLoader);

+			}

 		}

 

 	}

@@ -281,7 +290,7 @@
 			if(jndiName.contains("comp/BeanManager"))

 				continue;

 			this.logger.debug("Binding " + jndiName + " with value " + value);

-			ContextUtil.mkdirs(jndiContext, jndiName);

+			Contexts.createSubcontexts(jndiContext, jndiName);

 			try {

 				// Note: This will not rebind the DataSources also

 				jndiContext.bind(jndiName, value);

diff --git a/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeploymentLoader.java b/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeploymentLoader.java
index 82741e8..215054e 100755
--- a/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeploymentLoader.java
+++ b/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoDeploymentLoader.java
@@ -11,18 +11,56 @@
 
 package org.eclipse.virgo.web.enterprise.openejb.deployer;
 
+import static org.apache.openejb.util.URLs.toFile;
+
 import java.io.File;
 import java.io.IOException;
+import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.TreeMap;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
+import javax.servlet.ServletContext;
+
+import org.apache.openejb.ClassLoaderUtil;
 import org.apache.openejb.OpenEJBException;
 import org.apache.openejb.config.AppModule;
+import org.apache.openejb.config.ClientModule;
+import org.apache.openejb.config.ConnectorModule;
 import org.apache.openejb.config.DeploymentLoader;
+import org.apache.openejb.config.DeploymentModule;
+import org.apache.openejb.config.EjbModule;
+import org.apache.openejb.config.NewLoaderLogic;
+import org.apache.openejb.config.PersistenceModule;
+import org.apache.openejb.config.ReadDescriptors;
+import org.apache.openejb.config.ResourcesModule;
+import org.apache.openejb.config.TldScanner;
+import org.apache.openejb.config.UnknownModuleTypeException;
+import org.apache.openejb.config.UnsupportedModuleTypeException;
+import org.apache.openejb.config.WebModule;
+import org.apache.openejb.config.event.BeforeDeploymentEvent;
+import org.apache.openejb.core.EmptyResourcesClassLoader;
+import org.apache.openejb.jee.Application;
+import org.apache.openejb.jee.Beans;
+import org.apache.openejb.jee.FacesConfig;
+import org.apache.openejb.jee.JspConfig;
+import org.apache.openejb.jee.Taglib;
+import org.apache.openejb.jee.TldTaglib;
+import org.apache.openejb.jee.WebApp;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.util.URLs;
+import org.apache.xbean.finder.ResourceFinder;
 
 /**
  * 
@@ -33,62 +71,426 @@
 public class VirgoDeploymentLoader extends DeploymentLoader {
     
     private static final String VIRGO_ROOT_APPLICATION_RESERVED_MODULE_ID = "virgoRootApplicationReservedModuleID";
-    private final String webContextPath;
+    private ServletContext servletContext;
+    private static final String ddDir = "META-INF/";
     
-    public VirgoDeploymentLoader(String webContextPath) {
+    public VirgoDeploymentLoader(ServletContext context) {
         super();
-        this.webContextPath = webContextPath;
+        this.servletContext = context;
     }
 
     @Override
-    public AppModule load(File arg0) throws OpenEJBException {
-        //Sets the web context path as the moduleId, leaving the original logic unchanged
-        AppModule result = super.load(arg0);
-        result.setModuleId(createModuleIDFromWebContextPath());
-        return result;
+     public AppModule load(final File jarFile) throws OpenEJBException {
+         // verify we have a valid file
+         final String jarPath;
+         try {
+             jarPath = jarFile.getCanonicalPath();
+         } catch (IOException e) {
+             throw new OpenEJBException("Invalid application file path " + jarFile, e);
+         }
+
+         final URL baseUrl = getFileUrl(jarFile);
+
+         // create a class loader to use for detection of module type
+         // do not use this class loader for any other purposes... it is
+         // non-temp class loader and usage will mess up JPA
+         ClassLoader doNotUseClassLoader = null;// = ClassLoaderUtil.createClassLoader(jarPath, new URL[]{baseUrl}, OpenEJB.class.getClassLoader());
+
+         try {
+             // determine the module type
+             final Class<? extends DeploymentModule> moduleClass;
+
+             try {
+                 doNotUseClassLoader = ClassLoaderUtil.createClassLoader(jarPath, new URL[]{baseUrl}, getOpenEJBClassLoader());
+                 moduleClass = discoverModuleType(baseUrl, ClassLoaderUtil.createTempClassLoader(doNotUseClassLoader), true);
+             } catch (Exception e) {
+                 throw new UnknownModuleTypeException("Unable to determine module type for jar: " + baseUrl.toExternalForm(), e);
+             }
+
+             if (ResourcesModule.class.equals(moduleClass)) {
+                 final AppModule appModule = new AppModule(null, jarPath);
+                 final ResourcesModule module = new ResourcesModule();
+                 module.getAltDDs().put("resources.xml", baseUrl);
+                 ReadDescriptors.readResourcesXml(module);
+                 module.initAppModule(appModule);
+                 // here module is no more useful since everything is in the appmodule
+                 appModule.setModuleId(createModuleIDFromWebContextPath());
+                 return appModule;
+             }
+
+             //We always load AppModule, as it somewhat likes a wrapper module
+             if (AppModule.class.equals(moduleClass)) {
+             	AppModule appModule = createAppModule(jarFile, jarPath);
+             	appModule.setModuleId(createModuleIDFromWebContextPath());
+                 return appModule;
+             }
+
+             if (EjbModule.class.equals(moduleClass)) {
+                 final URL[] urls = new URL[]{baseUrl};
+
+                 SystemInstance.get().fireEvent(new BeforeDeploymentEvent(urls));             
+
+                 final AppModule appModule;
+                 //final Class<? extends DeploymentModule> o = EjbModule.class;
+                 final EjbModule ejbModule = createEjbModule(baseUrl, jarPath, getWebAppClassLoader());
+
+                 // wrap the EJB Module with an Application Module
+                 appModule = new AppModule(ejbModule);
+
+                 addPersistenceUnits(appModule, baseUrl);
+                 appModule.setModuleId(createModuleIDFromWebContextPath());
+                 return appModule;
+             }
+
+             if (WebModule.class.equals(moduleClass)) {
+                 final File file = toFile(baseUrl);
+
+                 // Standalone Web Module
+                 final WebModule webModule = createWebModule(file.getAbsolutePath(), file.getAbsolutePath(), getOpenEJBClassLoader(), getContextRoot(), getModuleName());
+                 // important to use the webapp classloader here otherwise each time we'll check something using loadclass it will fail (=== empty classloader)
+                 final AppModule appModule = new AppModule(webModule.getClassLoader(), file.getAbsolutePath(), new Application(), true);
+                 addWebModule(webModule, appModule);
+
+                 final Map<String, Object> otherDD = new HashMap<String, Object>();
+                 final List<URL> urls = webModule.getScannableUrls();
+                 final ResourceFinder finder = new ResourceFinder("", urls.toArray(new URL[urls.size()]));
+                 otherDD.putAll(getDescriptors(finder, false));
+
+                 // "persistence.xml" is done separately since we manage a list of url and not s single url
+                 try {
+                     final List<URL> persistenceXmls = finder.findAll(ddDir + "persistence.xml");
+                     if (persistenceXmls.size() >= 1) {
+                         final URL old = (URL) otherDD.get("persistence.xml");
+                         if (old != null && !persistenceXmls.contains(old)) {
+                             persistenceXmls.add(old);
+                         }
+                         otherDD.put("persistence.xml", persistenceXmls);
+                     }
+                 } catch (IOException e) {
+                     // ignored
+                 }
+
+                 addWebPersistenceDD("persistence.xml", otherDD, appModule);
+                 addWebPersistenceDD("persistence-fragment.xml", otherDD, appModule);
+                 addPersistenceUnits(appModule, baseUrl);
+                 appModule.setStandloneWebModule();
+                 appModule.setDelegateFirst(false);
+                 appModule.setModuleId(createModuleIDFromWebContextPath());
+                 return appModule;
+             }
+
+             if (PersistenceModule.class.equals(moduleClass)) {
+                 final String jarLocation = URLs.toFilePath(baseUrl);
+                // final ClassLoader classLoader = ClassLoaderUtil.createTempClassLoader(jarPath, new URL[]{baseUrl}, getOpenEJBClassLoader());
+
+                 // wrap the EJB Module with an Application Module
+                 final AppModule appModule = new AppModule(getWebAppClassLoader(), jarLocation);
+
+                 // Persistence Units
+                 addPersistenceUnits(appModule, baseUrl);
+                 appModule.setModuleId(createModuleIDFromWebContextPath());
+                 return appModule;
+             }
+
+             throw new UnsupportedModuleTypeException("Unsupported module type: " + moduleClass.getSimpleName());
+
+         } finally {
+             // if the application was unpacked appId used to create this class loader will be wrong
+             // We can safely destroy this class loader in either case, as it was not use by any modules
+             if (null != doNotUseClassLoader) {
+                 ClassLoaderUtil.destroyClassLoader(doNotUseClassLoader);
+             }
+         }
+     }
+     
+    private ClassLoader getWebAppClassLoader() {
+    	return Thread.currentThread().getContextClassLoader();
     }
-    
-    private String createModuleIDFromWebContextPath() {
-        if (this.webContextPath.equals("")) {
-          return VIRGO_ROOT_APPLICATION_RESERVED_MODULE_ID;
+       
+    @Override
+    public WebModule createWebModule(final String appId, final String warPath, final ClassLoader parentClassLoader, final String contextRoot, final String moduleName) throws OpenEJBException {
+   	 File warFile = new File(warPath);
+        ArrayList<URL> webUrls = new ArrayList<URL>();
+        
+        //we don't care about web.xml here but the rest
+        final Map<String, URL> descriptors;
+        try {
+            descriptors = getWebDescriptors(warFile);
+        } catch (IOException e) {
+            throw new OpenEJBException("Unable to collect descriptors in web module: " + contextRoot, e);
         }
-        // remove the slash at the beginning of each webContextPath
-        return this.webContextPath.substring(1);
-      }
+        
+        final WebApp webApp;
+        final URL webXmlUrl = descriptors.get("web.xml");
+        if (webXmlUrl != null) {
+            webApp = ReadDescriptors.readWebApp(webXmlUrl);
+        } else {
+            // no web.xml webapp - possible since Servlet 3.0
+            webApp = new WebApp();
+        }                
+        
+        webUrls.addAll(Arrays.asList(getWebappUrls(warFile)));
+
+        //Original logic kept from OpenEJB:
+        // in TomEE this is done in init hook since we don't manage tomee webapp classloader
+        // so here is not the best idea for tomee
+        // if we want to manage it in a generic way
+        // simply add a boolean shared between tomcat and openejb world
+        // to know if we should fire it or not
+        
+        URL[] webUrlsAsArray =  webUrls.toArray(new URL[]{});
+        
+        SystemInstance.get().fireEvent(new BeforeDeploymentEvent(webUrlsAsArray, parentClassLoader));
+
+
+        // create web module
+        webApp.setVersion("3.0"); //TODO:hardcoded
+        //TODO: we assume here it would be gemini classloader
+        final WebModule webModule = new WebModule(webApp, contextRoot, getWebAppClassLoader(), warFile.getAbsolutePath(), moduleName);
+        webModule.setUrls(webUrls);
+        webModule.getAltDDs().putAll(descriptors);
+        List<URL> filteredURLs = webUrls;
+        File exclusionList = SystemInstance.get().getConf(NewLoaderLogic.EXCLUSION_FILE);
+		try {
+			filteredURLs = filterWebappUrls(webUrlsAsArray, exclusionList.toURL());
+		} catch (MalformedURLException e) {
+			logger.warning("Unable to apply exclusion list " + exclusionList + " to web app urls. Scannable URLs may contain redundant entries", e);
+		}
+        webModule.setScannableUrls(filteredURLs); 
+       //If webModule object is loaded by ejbModule or persitenceModule, no need to load tag libraries, web service and JSF related staffs.
+        //Not needed
+       addTagLibraries(webModule);
+
+       // load faces configuration files
+       addFacesConfigs(webModule);
+
+        addBeansXmls(webModule);
+
+        return webModule;
+   }
     
     @Override
     protected String getContextRoot() {
-        return webContextPath;
+        return servletContext.getContextPath();
     }
+    
+    private String createModuleIDFromWebContextPath() {
+    	String webContextPath = this.servletContext.getContextPath();
+        if (webContextPath.equals("")) {
+          return VIRGO_ROOT_APPLICATION_RESERVED_MODULE_ID;
+        }
+        // remove the slash at the beginning of each webContextPath
+        return webContextPath.substring(1);
+    }
+    
+    private void addBeansXmls(final WebModule webModule) {
+        final List<URL> urls = webModule.getScannableUrls();
+      
+        final URLClassLoader loader = new URLClassLoader(urls.toArray(new URL[urls.size()]), new EmptyResourcesClassLoader());
 
-    @Override
-    protected Map<String, URL> getWebDescriptors(File warFile) throws IOException {
-        //Fixes a bug in OpenEjb that prevents recognising web modules when deploying packed web apps
-        Map<String, URL> descriptors = new TreeMap<String, URL>();
-        if (warFile.isFile()) {
-            URL jarURL = new URL("jar", "", -1, warFile.toURI().toURL() + "!/");
-            JarFile jarFile = null;
+        final ArrayList<URL> xmls;
+        try {
+            xmls = Collections.list(loader.getResources("META-INF/beans.xml"));
+            xmls.add((URL) webModule.getAltDDs().get("beans.xml"));
+        } catch (IOException e) {
+
+            return;
+        }
+
+        Beans complete = null;
+        for (final URL url : xmls) {
+            if (url == null) continue;
+            complete = mergeBeansXml(complete, url);
+        }
+
+        webModule.getAltDDs().put("beans.xml", complete);
+    }
+    
+    private Beans mergeBeansXml(final Beans current, final URL url) {
+        Beans returnValue = current;
+        try {
+            final Beans beans;
             try {
-                jarFile = new JarFile(warFile);
-                for (JarEntry entry : Collections.list(jarFile.entries())) {
-                    String entryName = entry.getName();
-                    if (!entry.isDirectory() && entryName.startsWith("WEB-INF/") && entryName.indexOf('/', "WEB-INF".length()) > 0) {
-                        descriptors.put(entryName, new URL(jarURL, entry.getName()));
+                beans = ReadDescriptors.readBeans(url.openStream());
+            } catch (IOException e) {
+                return returnValue;
+            }
+
+            if (current == null) {
+                returnValue = beans;
+            } else {
+                current.getAlternativeClasses().addAll(beans.getAlternativeClasses());
+                current.getAlternativeStereotypes().addAll(beans.getAlternativeStereotypes());
+                current.getDecorators().addAll(beans.getDecorators());
+                current.getInterceptors().addAll(beans.getInterceptors());
+            }
+            // check is done here since later we lost the data of the origin
+            ReadDescriptors.checkDuplicatedByBeansXml(beans, returnValue);
+        } catch (OpenEJBException e) {
+            logger.error("Unable to read beans.xml from :" + url.toExternalForm());
+        }
+        return returnValue;
+    }
+   
+    private void addWebPersistenceDD(final String name, final Map<String, Object> otherDD, final AppModule appModule) {
+        if (otherDD.containsKey(name)) {
+            List<URL> persistenceUrls = (List<URL>) appModule.getAltDDs().get(name);
+            if (persistenceUrls == null) {
+                persistenceUrls = new ArrayList<URL>();
+                appModule.getAltDDs().put(name, persistenceUrls);
+            }
+
+            if (otherDD.containsKey(name)) {
+                final Object otherUrl = otherDD.get(name);
+                if (otherUrl instanceof URL && !persistenceUrls.contains(otherUrl)) {
+                    persistenceUrls.add((URL) otherUrl);
+                } else if (otherUrl instanceof List) {
+                    final List<URL> otherList = (List<URL>) otherDD.get(name);
+                    for (final URL url : otherList) {
+                        if (!persistenceUrls.contains(url)) {
+                            persistenceUrls.add(url);
+                        }
                     }
                 }
-            } catch (IOException e) {
-                // most likely an invalid jar file
-            } finally {
-            	try {
-            		if (jarFile != null) {
-            			jarFile.close();
-            		}
-            	} catch (IOException e) {
-            		// do nothing
-            	}
             }
         }
-        descriptors.putAll(super.getWebDescriptors(warFile));
-        return descriptors;
     }
+    
+    public static Map<String, URL> getDescriptors(final URL moduleUrl) throws OpenEJBException {
+
+        final ResourceFinder finder = new ResourceFinder(moduleUrl);
+        return getDescriptors(finder);
+    }
+
+    private static Map<String, URL> getDescriptors(final ResourceFinder finder) throws OpenEJBException {
+        return getDescriptors(finder, true);
+    }
+
+    private static Map<String, URL> getDescriptors(final ResourceFinder finder, final boolean log) throws OpenEJBException {
+        try {
+
+            return altDDSources(mapDescriptors(finder), log);
+
+        } catch (IOException e) {
+            throw new OpenEJBException("Unable to determine descriptors in jar.", e);
+        }
+    }
+    
+
+    /**
+     * Finds all faces configuration files and stores them in the WebModule
+     *
+     * @param webModule WebModule
+     * @throws OpenEJBException
+     */
+    private void addFacesConfigs(final WebModule webModule) throws OpenEJBException {
+        //*************************IMPORTANT*******************************************
+        // TODO : kmalhi :: Add support to scrape META-INF/faces-config.xml in jar files
+        // look at section 10.4.2 of the JSF v1.2 spec, bullet 1 for details
+        final Set<URL> facesConfigLocations = new HashSet<URL>();
+
+        // web.xml contains faces config locations in the context parameter javax.faces.CONFIG_FILES
+        final File warFile = new File(webModule.getJarLocation());
+        final WebApp webApp = webModule.getWebApp();
+        if (webApp != null) {
+            final String foundContextParam = webApp.contextParamsAsMap().get("javax.faces.CONFIG_FILES");
+            if (foundContextParam != null) {
+                // the value is a comma separated list of config files
+                final String commaDelimitedListOfFiles = foundContextParam.trim();
+                final String[] configFiles = commaDelimitedListOfFiles.split(",");
+                // trim any extra spaces in each file
+                final String[] trimmedConfigFiles = new String[configFiles.length];
+                for (int i = 0; i < configFiles.length; i++) {
+                    trimmedConfigFiles[i] = configFiles[i].trim();
+                }
+                // convert each file to a URL and add it to facesConfigLocations
+                for (final String location : trimmedConfigFiles) {
+                    if (!location.startsWith("/"))
+                        logger.error("A faces configuration file should be context relative when specified in web.xml. Please fix the value of context parameter javax.faces.CONFIG_FILES for the file " + location);
+                    try {
+                        final File file = new File(warFile, location).getCanonicalFile().getAbsoluteFile();
+                        final URL url = file.toURI().toURL();
+                        facesConfigLocations.add(url);
+
+                    } catch (IOException e) {
+                        logger.error("Faces configuration file location bad: " + location, e);
+                    }
+                }
+            } else {
+                logger.debug("faces config file is null");
+            }
+        }
+
+        // Search for WEB-INF/faces-config.xml
+        final File webInf = new File(warFile, "WEB-INF");
+        if (webInf.isDirectory()) {
+            File facesConfigFile = new File(webInf, "faces-config.xml");
+            if (facesConfigFile.exists()) {
+                try {
+                    facesConfigFile = facesConfigFile.getCanonicalFile().getAbsoluteFile();
+                    final URL url = facesConfigFile.toURI().toURL();
+                    facesConfigLocations.add(url);
+                } catch (IOException e) {
+                    // TODO: kmalhi:: Remove the printStackTrace after testing
+                    e.printStackTrace();
+                }
+            }
+        }
+        // load the faces configuration files
+        // TODO:kmalhi:: Its good to have separate FacesConfig objects for multiple configuration files, but what if there is a conflict where the same
+        // managebean is declared in two different files, which one wins? -- check the jsf spec, Hopefully JSF should be able to check for this and
+        // flag an error and not allow the application to be deployed.
+        for (final URL location : facesConfigLocations) {
+            final FacesConfig facesConfig = ReadDescriptors.readFacesConfig(location);
+            webModule.getFacesConfigs().add(facesConfig);
+            if ("file".equals(location.getProtocol())) {
+                webModule.getWatchedResources().add(URLs.toFilePath(location));
+            }
+        }
+    }
+    
+    private void addTagLibraries(final WebModule webModule) throws OpenEJBException {
+        final Set<URL> tldLocations = new HashSet<URL>();
+
+        // web.xml contains tag lib locations in nested jsp config elements
+        final File warFile = new File(webModule.getJarLocation());
+        final WebApp webApp = webModule.getWebApp();
+        if (webApp != null) {
+            for (final JspConfig jspConfig : webApp.getJspConfig()) {
+                for (final Taglib taglib : jspConfig.getTaglib()) {
+                    String location = taglib.getTaglibLocation();
+                    if (!location.startsWith("/")) {
+                        // this reproduces a tomcat bug
+                        location = "/WEB-INF/" + location;
+                    }
+                    try {
+                        final File file = new File(warFile, location).getCanonicalFile().getAbsoluteFile();
+                        tldLocations.addAll(TldScanner.scanForTagLibs(file));
+                    } catch (IOException e) {
+                        logger.warning("JSP tag library location bad: " + location, e);
+                    }
+                }
+            }
+        }
+
+        // WEB-INF/**/*.tld except in WEB-INF/classes and WEB-INF/lib
+        Set<URL> urls = TldScanner.scanWarForTagLibs(warFile);
+        tldLocations.addAll(urls);
+
+        // Search all libs
+        final ClassLoader parentClassLoader = webModule.getClassLoader().getParent();
+        urls = TldScanner.scan(parentClassLoader);
+        tldLocations.addAll(urls);
+
+        // load the tld files
+        for (final URL location : tldLocations) {
+            final TldTaglib taglib = ReadDescriptors.readTldTaglib(location);
+            webModule.getTaglibs().add(taglib);
+            if ("file".equals(location.getProtocol())) {
+                webModule.getWatchedResources().add(URLs.toFilePath(location));
+            }
+        }
+    }
+    
+
 }
diff --git a/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoUndeployerEjb.java b/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoUndeployerEjb.java
index 8a9f492..df1bc35 100755
--- a/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoUndeployerEjb.java
+++ b/org.eclipse.virgo.web.enterprise.appdeployer/src/main/java/org/eclipse/virgo/web/enterprise/openejb/deployer/VirgoUndeployerEjb.java
@@ -54,10 +54,10 @@
 		ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class);

 		Context context = containerSystem.getJNDIContext();

 		if (appForUndeploy != null) {

-			Set<ResourceInfo> resources = appForUndeploy.resourceInfos;

-			for (ResourceInfo resource : resources) {

+			Set<String> resources = appForUndeploy.resourceIds;

+			for (String resourceId : resources) {

 				try {

-					context.unbind(resource.id);

+					context.unbind(resourceId);

 				} catch (NamingException e) {

 					// do nothing

 				}

diff --git a/org.eclipse.virgo.web.enterprise.appdeployer/template.mf b/org.eclipse.virgo.web.enterprise.appdeployer/template.mf
index 6b54d1c..974bced 100644
--- a/org.eclipse.virgo.web.enterprise.appdeployer/template.mf
+++ b/org.eclipse.virgo.web.enterprise.appdeployer/template.mf
@@ -6,14 +6,17 @@
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Service-Component: OSGI-INF/virgo.web.enterprise.appdeployer.deployer.xml
 Import-Template: javax.ejb;version="0",
+ javax.enterprise.inject.spi;version="0",
+ javax.naming;version="0",
  javax.servlet;version="0",
  javax.validation;version="0",
  org.apache.catalina.*;version="${org.apache.catalina:[=.=.=, +1)}",
  org.apache.naming.*;version="${org.apache.catalina:[=.=.=, +1)}",
  org.apache.openejb.*;version="0",
+ org.apache.webbeans.*;version="0",
+ org.apache.xbean.finder;version="0",
  org.osgi.framework;version="0",
  org.eclipse.virgo.medic.*;version="${org.eclipse.virgo.medic:[=.=.=, +1)}",
- org.slf4j;version="0",
- javax.naming;version="0"
+ org.slf4j;version="0" 
 Excluded-Exports:
  *.internal.*
diff --git a/org.eclipse.virgo.web.enterprise.applistener/src/main/java/org/eclipse/virgo/web/enterprise/applistener/internal/OpenEjbApplicationListener.java b/org.eclipse.virgo.web.enterprise.applistener/src/main/java/org/eclipse/virgo/web/enterprise/applistener/internal/OpenEjbApplicationListener.java
index d845694..4f0958d 100755
--- a/org.eclipse.virgo.web.enterprise.applistener/src/main/java/org/eclipse/virgo/web/enterprise/applistener/internal/OpenEjbApplicationListener.java
+++ b/org.eclipse.virgo.web.enterprise.applistener/src/main/java/org/eclipse/virgo/web/enterprise/applistener/internal/OpenEjbApplicationListener.java
@@ -33,8 +33,7 @@
     

     public void deploy(StandardContext standardContext) throws Exception {

         ServletContext context = standardContext.getServletContext();

-        String contextPath = context.getContextPath();

-        VirgoDeployerEjb deployer = new VirgoDeployerEjb(contextPath, context.getClassLoader());

+        VirgoDeployerEjb deployer = new VirgoDeployerEjb(context);

         try {

             String realPath = context.getRealPath("");

             synchronized (monitor) {

@@ -46,7 +45,7 @@
             }

         } catch (Exception e) {

             if (logger.isErrorEnabled()) {

-                logger.error("Failed to initialise enterprise container for application with context path '" + contextPath + "'", e);

+                logger.error("Failed to initialise enterprise container for application with context path '" + context.getContextPath() + "'", e);

             }

             throw e;

         }

@@ -55,8 +54,7 @@
     // no need to synchronize the undeploy operation as it is stateless

     public void undeploy(StandardContext standardContext) throws Exception {

         ServletContext context = standardContext.getServletContext();

-        String contextPath = context.getContextPath();

-        VirgoDeployerEjb deployer = new VirgoDeployerEjb(contextPath, context.getClassLoader());

+        VirgoDeployerEjb deployer = new VirgoDeployerEjb(context);

         try {

             String realPath = context.getRealPath("");

             if (realPath != null) {

@@ -66,7 +64,7 @@
             }

         } catch (Exception e) {

             if (logger.isErrorEnabled()) {

-                logger.error("Failed to destroy enterprise container for application with context path '" + contextPath + "'", e);

+                logger.error("Failed to destroy enterprise container for application with context path '" + context.getContextPath() + "'", e);

             }

             throw e;

         }

diff --git a/org.eclipse.virgo.web.enterprise.jsf.support/.classpath b/org.eclipse.virgo.web.enterprise.jsf.support/.classpath
index 8359b66..54060fb 100755
--- a/org.eclipse.virgo.web.enterprise.jsf.support/.classpath
+++ b/org.eclipse.virgo.web.enterprise.jsf.support/.classpath
@@ -1,16 +1,18 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="src/main/resources"/>
-	<classpathentry kind="src" path="src/test/java"/>
-	<classpathentry kind="src" path="src/main/java"/>
-	<classpathentry kind="src" path="src/test/resources"/>
-	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/javax.annotation/1.1.0.v201108011116/javax.annotation-1.1.0.v201108011116.jar"/>
-	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/javax.ejb/3.1.1.v201204261316/javax.ejb-3.1.1.v201204261316.jar"/>
-	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.catalina/7.0.35.v201302131125/org.apache.catalina-7.0.35.v201302131125.jar" sourcepath="/IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.catalina/7.0.35.v201302131125/org.apache.catalina.source-7.0.35.v201302131125.jar"/>
-	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.glassfish.com.sun.faces/2.1.6.v201205171319-virgo-1/org.glassfish.com.sun.faces-2.1.6.v201205171319-virgo-1.jar"/>
-	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/javax.persistence/2.0.4.v201112161009/javax.persistence-2.0.4.v201112161009.jar"/>
-	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.slf4j.api/1.7.2.v20121108-1250/org.slf4j.api-1.7.2.v20121108-1250.jar" sourcepath="/IVY_CACHE/org.eclipse.virgo.mirrored/org.slf4j.api/1.7.2.v20121108-1250/org.slf4j.api.source-1.7.2.v20121108-1250.jar"/>
-	<classpathentry kind="output" path="bin"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>

+<classpath>

+	<classpathentry kind="src" path="src/main/resources"/>

+	<classpathentry kind="src" path="src/test/java"/>

+	<classpathentry kind="src" path="src/main/java"/>

+	<classpathentry kind="src" path="src/test/resources"/>

+	<classpathentry kind="var" path="IVY_CACHE/javax.annotation/javax.annotation/1.1.0.v201105051105/javax.annotation-1.1.0.v201105051105.jar"/>

+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>

+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/javax.ejb/3.1.1.v201204261316/javax.ejb-3.1.1.v201204261316.jar"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.catalina/7.0.35.v201302131125/org.apache.catalina-7.0.35.v201302131125.jar" sourcepath="/IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.catalina/7.0.35.v201302131125/org.apache.catalina.source-7.0.35.v201302131125.jar"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.glassfish.com.sun.faces/2.1.6.v201205171319-virgo-1/org.glassfish.com.sun.faces-2.1.6.v201205171319-virgo-1.jar"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/javax.persistence/2.0.4.v201112161009/javax.persistence-2.0.4.v201112161009.jar"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.slf4j.api/1.7.2.v20121108-1250/org.slf4j.api-1.7.2.v20121108-1250.jar" sourcepath="/IVY_CACHE/org.eclipse.virgo.mirrored/org.slf4j.api/1.7.2.v20121108-1250/org.slf4j.api.source-1.7.2.v20121108-1250.jar"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/org.apache.openwebbeans.impl/1.1.7.v201304201405/org.apache.openwebbeans.impl-1.1.7.v201304201405.jar"/>

+	<classpathentry kind="var" path="IVY_CACHE/org.eclipse.virgo.mirrored/cdi.api/1.0.0.v201105160744/cdi.api-1.0.0.v201105160744.jar"/>

+	<classpathentry kind="output" path="bin"/>

+</classpath>

diff --git a/org.eclipse.virgo.web.enterprise.jsf.support/ivy.xml b/org.eclipse.virgo.web.enterprise.jsf.support/ivy.xml
index 21d5491..2bcf0b8 100644
--- a/org.eclipse.virgo.web.enterprise.jsf.support/ivy.xml
+++ b/org.eclipse.virgo.web.enterprise.jsf.support/ivy.xml
@@ -13,11 +13,13 @@
 	</publications>
 
 	<dependencies>
+	  <dependency org="org.eclipse.virgo.mirrored" name="cdi.api" rev="${cdi.api}" conf="compile->runtime"/>
         <dependency org="org.eclipse.virgo.mirrored" name="javax.servlet" rev="${javax.servlet}" conf="compile->runtime"/>
         <dependency org="org.eclipse.virgo.mirrored" name="org.glassfish.com.sun.faces" rev="${org.glassfish.com.sun.faces}" conf="compile->runtime"/>
         <dependency org="org.eclipse.virgo.mirrored" name="javax.ejb" rev="${javax.ejb}" conf="compile->runtime"/>
         <dependency org="org.eclipse.virgo.mirrored" name="javax.persistence" rev="${javax.persistence}" conf="compile->runtime"/>
         <dependency org="org.eclipse.virgo.mirrored" name="javax.annotation" rev="${javax.annotation}" conf="compile->runtime"/>
+        <dependency org="org.eclipse.virgo.mirrored" name="org.apache.openwebbeans.impl" rev="${org.apache.openwebbeans.impl}" conf="compile->runtime"/>
         <dependency org="org.eclipse.virgo.mirrored" name="org.apache.catalina" rev="${org.apache.catalina}" conf="compile->runtime"/>
 		<dependency org="org.eclipse.virgo.mirrored" name="org.slf4j.api" rev="${org.slf4j.api}" conf="compile->runtime"/>
 
diff --git a/org.eclipse.virgo.web.enterprise.jsf.support/src/main/java/org/eclipse/virgo/web/enterprise/jsf/support/VirgoJsfInjectionProvider.java b/org.eclipse.virgo.web.enterprise.jsf.support/src/main/java/org/eclipse/virgo/web/enterprise/jsf/support/VirgoJsfInjectionProvider.java
index 21076a8..9d02202 100755
--- a/org.eclipse.virgo.web.enterprise.jsf.support/src/main/java/org/eclipse/virgo/web/enterprise/jsf/support/VirgoJsfInjectionProvider.java
+++ b/org.eclipse.virgo.web.enterprise.jsf.support/src/main/java/org/eclipse/virgo/web/enterprise/jsf/support/VirgoJsfInjectionProvider.java
@@ -31,6 +31,8 @@
 import com.sun.faces.spi.InjectionProvider;

 import com.sun.faces.spi.InjectionProviderException;

 

+import org.apache.webbeans.config.WebBeansContext;

+import org.apache.webbeans.inject.OWBInjector;

 import org.slf4j.Logger;

 import org.slf4j.LoggerFactory;

 

@@ -55,13 +57,14 @@
 	public void inject(Object managedBean) throws InjectionProviderException {

 	    // try injecting everything with OWB's injector instance

 	    try {

-            ClassLoader tccl = Thread.currentThread().getContextClassLoader();

-            if (tccl != null) {

-                Class<?> injector = tccl.loadClass("org.apache.webbeans.inject.OWBInjector");

-                Object injectorInstance = injector.newInstance();

-                Method method = injector.getDeclaredMethod("inject", new Class<?>[] { Object.class });

-                injectorInstance = method.invoke(injectorInstance, new Object[] { managedBean });

-            }

+	    	OWBInjector.inject(WebBeansContext.currentInstance().getBeanManagerImpl(), managedBean, null);

+//            ClassLoader tccl = Thread.currentThread().getContextClassLoader();

+//            if (tccl != null) {

+//                Class<?> injector = tccl.loadClass("org.apache.webbeans.inject.OWBInjector");

+//                Object injectorInstance = injector.newInstance();

+//                Method method = injector.getDeclaredMethod("inject", new Class<?>[] { Object.class });

+//                injectorInstance = method.invoke(injectorInstance, new Object[] { managedBean });

+//            }

         } catch (Exception e) {

             if (logger.isErrorEnabled()) {

                 logger.error("Failed to invoke OWBInjector for managedBean '"+ managedBean.toString() +"', will fallback to manual processing", e);

diff --git a/org.eclipse.virgo.web.enterprise.jsf.support/template.mf b/org.eclipse.virgo.web.enterprise.jsf.support/template.mf
index b3c2964..a377f49 100644
--- a/org.eclipse.virgo.web.enterprise.jsf.support/template.mf
+++ b/org.eclipse.virgo.web.enterprise.jsf.support/template.mf
@@ -11,6 +11,10 @@
  com.sun.faces.spi;version="0",
  org.apache.naming;version="${org.apache.catalina:[=.=.=, +1)}",
  javax.naming;version="0",
- org.slf4j.*;version="0"
+ org.slf4j.*;version="0",
+ org.apache.webbeans.*;version="0",
+ javax.enterprise.context.spi;version="0",
+ javax.enterprise.inject.spi;version="0",
+ org.apache.webbeans.container;version="0"
 Excluded-Exports:
  *.internal.*
diff --git a/org.eclipse.virgo.web.enterprise.openejb.fragment.webbeans/src/main/resources/META-INF/MANIFEST.MF b/org.eclipse.virgo.web.enterprise.openejb.fragment.webbeans/src/main/resources/META-INF/MANIFEST.MF
index dbf563b..47bc2fa 100755
--- a/org.eclipse.virgo.web.enterprise.openejb.fragment.webbeans/src/main/resources/META-INF/MANIFEST.MF
+++ b/org.eclipse.virgo.web.enterprise.openejb.fragment.webbeans/src/main/resources/META-INF/MANIFEST.MF
@@ -3,8 +3,12 @@
 Bundle-Version: 3.6.0.enterprise

 Bundle-Name: OpenEjb integration with OpenWebBeans

 Bundle-ManifestVersion: 2

-Import-Package: org.apache.webbeans.web.tomcat,org.apache.webbeans.jsf

- .plugin,org.apache.webbeans.jsf.scopes,org.apache.webbeans.jsf

+Import-Package: org.apache.webbeans.ee.beans,

+ org.apache.webbeans.ee.common.beans,

+ org.apache.webbeans.jsf,

+ org.apache.webbeans.jsf.plugin,

+ org.apache.webbeans.web.tomcat,

+ org.slf4j.spi

 Bundle-SymbolicName: org.eclipse.virgo.web.enterprise.openejb.fragment.webbeans

 Bundle-RequiredExecutionEnvironment: JavaSE-1.6

 

diff --git a/org.eclipse.virgo.web.enterprise.openejb.fragment.webbeans/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/org.eclipse.virgo.web.enterprise.openejb.fragment.webbeans/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
deleted file mode 100755
index 5c64241..0000000
--- a/org.eclipse.virgo.web.enterprise.openejb.fragment.webbeans/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
+++ /dev/null
@@ -1,18 +0,0 @@
-#Licensed to the Apache Software Foundation (ASF) under one
-#or more contributor license agreements.  See the NOTICE file
-#distributed with this work for additional information
-#regarding copyright ownership.  The ASF licenses this file
-#to you under the Apache License, Version 2.0 (the
-#"License"); you may not use this file except in compliance
-#with the License.  You may obtain a copy of the License at
-#
-#  http://www.apache.org/licenses/LICENSE-2.0
-#
-#Unless required by applicable law or agreed to in writing,
-#software distributed under the License is distributed on an
-#"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#KIND, either express or implied.  See the License for the
-#specific language governing permissions and limitations
-#under the License.
-
-org.apache.webbeans.jsf.scopes.Jsf2ScopesExtension
\ No newline at end of file
diff --git a/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/VirgoEEBundleComparable.java b/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/VirgoEEBundleComparable.java
new file mode 100755
index 0000000..493dba0
--- /dev/null
+++ b/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/VirgoEEBundleComparable.java
@@ -0,0 +1,42 @@
+package org.eclipse.virgo.web.enterprise.services.accessor;

+

+import java.util.ArrayList;

+import java.util.Collections;

+import java.util.Comparator;

+import java.util.List;

+import java.util.Set;

+

+import org.osgi.framework.Bundle;

+

+public class VirgoEEBundleComparable implements Comparator<Bundle> {

+	List<String> orderedImplBundles;

+	

+	public VirgoEEBundleComparable() {

+		orderedImplBundles = new ArrayList<String>(WebAppBundleTrackerCustomizer.getBundles(System.getProperty(WebAppBundleTrackerCustomizer.IMPL_BUNDLES)).keySet());

+	}

+

+	@Override

+	public int compare(Bundle b1, Bundle b2) {

+		if(b1 == b2) {

+			return 0;

+		}

+		

+		String name1 = b1.getSymbolicName();

+		String name2 = b2.getSymbolicName();

+		

+		Integer index1 = orderedImplBundles.indexOf(name1);

+		Integer index2 = orderedImplBundles.indexOf(name2);

+		

+		if(index1 == -1 && index2 == -1) {

+			return name1.compareTo(name2);

+		} else if(index1 == -1) {

+			return 1;

+		} else if(index2 == -1) {

+			return -1;

+		} else { //normal int comparison

+			return index1.compareTo(index2);

+		}

+

+	}

+

+}

diff --git a/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/WebAppBundleClassLoaderDelegateHook.java b/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/WebAppBundleClassLoaderDelegateHook.java
index 72be765..053514b 100755
--- a/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/WebAppBundleClassLoaderDelegateHook.java
+++ b/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/WebAppBundleClassLoaderDelegateHook.java
@@ -14,11 +14,13 @@
 import java.io.FileNotFoundException;

 import java.io.IOException;

 import java.net.URL;

+import java.util.Collections;

 import java.util.Enumeration;

 import java.util.HashSet;

 import java.util.List;

 import java.util.Map;

 import java.util.Set;

+import java.util.TreeMap;

 import java.util.concurrent.ConcurrentHashMap;

 import java.util.concurrent.CopyOnWriteArraySet;

 import java.util.concurrent.atomic.AtomicInteger;

@@ -28,6 +30,7 @@
 import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegateHook;

 import org.eclipse.osgi.framework.internal.core.BundleHost;

 import org.osgi.framework.Bundle;

+import org.osgi.framework.FrameworkUtil;

 import org.osgi.framework.wiring.BundleCapability;

 import org.osgi.framework.wiring.BundleRevision;

 import org.osgi.framework.wiring.BundleWire;

@@ -37,6 +40,8 @@
 

 class WebAppBundleClassLoaderDelegateHook implements ClassLoaderDelegateHook {

 

+    private static final String GEMINI_WEB_TOMCAT_SYMBOLIC_NAME = "org.eclipse.gemini.web.tomcat";

+

     private static final Logger LOGGER = LoggerFactory.getLogger(WebAppBundleClassLoaderDelegateHook.class);

 

     private static final int MAX_API_SEARCH_DEPTH = 1;

@@ -51,14 +56,47 @@
 

     private final Set<Bundle> implBundles = new CopyOnWriteArraySet<Bundle>();

 

-    private final Map<Bundle, ClassLoader> implBundlesClassloaders = new ConcurrentHashMap<Bundle, ClassLoader>();

+    private final Map<Bundle, ClassLoader> implBundlesClassloaders = Collections.synchronizedMap(new TreeMap<Bundle, ClassLoader>(new VirgoEEBundleComparable()));

 

     private final Map<Bundle, Set<String>> webAppBundles = new ConcurrentHashMap<Bundle, Set<String>>();

     

     private final Set<Bundle> postFindApiBundles = new CopyOnWriteArraySet<Bundle>();

+    private Set<String> negativeCacheClassPrefixes = new HashSet<String>();

+	

+    WebAppBundleClassLoaderDelegateHook() {

+    	negativeCacheClassPrefixes.add("openwebbeans/Messages");

+    	negativeCacheClassPrefixes.add("com.sun.faces.LogStrings");

+    	negativeCacheClassPrefixes.add("javax.faces.LogStrings");

+    	negativeCacheClassPrefixes.add("org.apache.catalina.loader.LocalStrings");

+    	negativeCacheClassPrefixes.add("org.apache.tomcat.util.file.LocalStrings");

+    	negativeCacheClassPrefixes.add("org.apache.tomcat.util.scan.LocalStrings");

+    	negativeCacheClassPrefixes.add("org.apache.tomcat.util.http.mapper.LocalStrings");

+    	negativeCacheClassPrefixes.add("org.apache.tomcat.util.net.res.LocalStrings");

+    	negativeCacheClassPrefixes.add("org.apache.tomcat.util.threads.res.LocalStrings");

+    	negativeCacheClassPrefixes.add("ValidationMessages");

+    	negativeCacheClassPrefixes.add("org.apache.bval.jsr303.ValidationMessages");

+    	negativeCacheClassPrefixes.add("com.sun.xml.internal.messaging.saaj.soap.LocalStrings");

+    	negativeCacheClassPrefixes.add("org.apache.openejb.package-info");

+    	negativeCacheClassPrefixes.add("org.apache.openejb.monitoring.package-info");

+    	negativeCacheClassPrefixes.add("org.apache.geronimo.openejb.cdi.GeronimoWebBeansPlugin");

+    	negativeCacheClassPrefixes.add("org.apache.openejb.server.rest.RsRegistry");

+    	negativeCacheClassPrefixes.add("javax.faces.application.ConfigurableNavigationHandlerBeanInfo");

+    	negativeCacheClassPrefixes.add("javax.faces.application.NavigationHandlerBeanInfo");

+    	negativeCacheClassPrefixes.add("org.apache.webbeans.jsf.ConversationAwareViewHandlerBeanInfo");

+    	negativeCacheClassPrefixes.add("javax.faces.application.ViewHandlerWrapperBeanInfo");

+    	negativeCacheClassPrefixes.add("javax.faces.application.ViewHandlerBeanInfo");

+    	negativeCacheClassPrefixes.add("javax.faces.component.UIViewRootBeanInfo");

+    	negativeCacheClassPrefixes.add("javax.faces.component.UIComponentBaseBeanInfo");

+    	negativeCacheClassPrefixes.add("javax.faces.component.UIComponentBeanInfo");  

+    	negativeCacheClassPrefixes.add("javax.management.MBean");    

+    	// keep javax.management.MBean out of the list:

+    }

 

     @Override

     public Class<?> postFindClass(String name, BundleClassLoader bcl, BundleData bd) throws ClassNotFoundException {

+    	if(matchesNegativeCache(name)) {

+    		return null;

+    	}

         if (shouldEnter(MAX_IMPL_SEARCH_DEPTH)) {

             try {

                 enter();

@@ -67,7 +105,8 @@
                 	

 				if (this.implBundles.contains(bundle)) {

                     ClassLoader tccl = Thread.currentThread().getContextClassLoader();

-                    if (tccl != null) {

+                    //TODO: check why openejb tries to load app classes from itself

+                    if (tccl != null/* && isBundleWebAppCL(tccl)*/) {

                         try {

                             return tccl.loadClass(name);

                         } catch (ClassNotFoundException e) {

@@ -142,7 +181,7 @@
 

                 if (this.implBundles.contains(bundle)) {

                     ClassLoader tccl = Thread.currentThread().getContextClassLoader();

-                    if (tccl != null) {

+                    if (tccl != null/* && isBundleWebAppCL(tccl)*/) {

                         return tccl.getResource(name);

                     }

                 }

@@ -215,6 +254,9 @@
 

     @Override

     public Class<?> preFindClass(String name, BundleClassLoader bcl, BundleData bd) throws ClassNotFoundException {

+    	if(matchesNegativeCache(name)) {

+    		return null;

+    	}

         if (shouldEnter(MAX_API_SEARCH_DEPTH)) {

             try {

                 enter();

@@ -424,6 +466,14 @@
         return this.implBundles;

     }

     

+    private boolean isBundleWebAppCL(ClassLoader tccl) {

+		Bundle bundle = FrameworkUtil.getBundle(tccl.getClass());

+		if(bundle!= null && bundle.getSymbolicName().equals(GEMINI_WEB_TOMCAT_SYMBOLIC_NAME)) {

+			return true;

+		}

+		return false;

+	}

+    

     private String getClassPackage(String className) {

     	int packageNameEndsIndex = className.lastIndexOf(".");

     	if(packageNameEndsIndex != -1 && packageNameEndsIndex != className.length() -1) {

@@ -432,4 +482,13 @@
     	return "";

     }

 

+    private boolean matchesNegativeCache(String className) {

+  		for(String prefix : negativeCacheClassPrefixes) {

+  			if(className.startsWith(prefix)) {

+  				return true;

+  			}

+  		}

+  		return false;

+  	}

+

 }

diff --git a/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/WebAppBundleTrackerCustomizer.java b/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/WebAppBundleTrackerCustomizer.java
index 434bc4a..b5e5249 100755
--- a/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/WebAppBundleTrackerCustomizer.java
+++ b/org.eclipse.virgo.web.enterprise.services.accessor/src/main/java/org/eclipse/virgo/web/enterprise/services/accessor/WebAppBundleTrackerCustomizer.java
@@ -16,6 +16,7 @@
 import java.util.Collections;

 import java.util.HashMap;

 import java.util.HashSet;

+import java.util.LinkedHashMap;

 import java.util.List;

 import java.util.Map;

 import java.util.Set;

@@ -272,8 +273,8 @@
      * @param property

      * @return

      */

-    private Map<String, VersionRange> getBundles(String property) {

-        Map<String, VersionRange> bundles = new HashMap<String, VersionRange>();

+    static LinkedHashMap<String, VersionRange> getBundles(String property) {

+    	LinkedHashMap<String, VersionRange> bundles = new LinkedHashMap<String, VersionRange>();

 

         if (property != null) {

             final List<String> bundleNames = parse(property);

@@ -302,7 +303,7 @@
         return bundles;

     }

 

-    private List<String> parse(String property) {

+    private static List<String> parse(String property) {

         List<String> result = new ArrayList<String>();

         int ind = property.indexOf(COMMA_SEPARATOR);

         if (ind >= 0) {

diff --git a/org.eclipse.virgo.web.enterprise.services.accessor/src/test/java/org/eclipse/virgo/web/enterprise/services/accessor/VirgoEEBundleComparableTest.java b/org.eclipse.virgo.web.enterprise.services.accessor/src/test/java/org/eclipse/virgo/web/enterprise/services/accessor/VirgoEEBundleComparableTest.java
new file mode 100755
index 0000000..a656566
--- /dev/null
+++ b/org.eclipse.virgo.web.enterprise.services.accessor/src/test/java/org/eclipse/virgo/web/enterprise/services/accessor/VirgoEEBundleComparableTest.java
@@ -0,0 +1,155 @@
+package org.eclipse.virgo.web.enterprise.services.accessor;

+

+import static org.junit.Assert.*;

+

+import java.util.Set;

+import java.util.TreeSet;

+

+import org.easymock.EasyMock;

+import org.junit.Test;

+import org.osgi.framework.Bundle;

+

+public class VirgoEEBundleComparableTest {

+	

+private static final String BUNDLE2 = "bundle2";

+private static final String BUNDLE1 = "bundle1";

+private static final String ORG_ECLIPSE_PERSISTENCE_CORE = "org.eclipse.persistence.core";

+private static final String ORG_ECLILSE_PERSISTENCE_JPA = "org.eclipse.persistence.jpa";

+private static final String ORG_APACHE_WEBBEANS_WEB = "org.apache.openwebbeans.web";

+private static final String ORG_APACHE_WEBBEANS_IMPL = "org.apache.openwebbeans.impl";

+private static final String ORG_GLASSFISH_COM_SUN_FACES = "org.glassfish.com.sun.faces";

+private static final String OPENEJB_CORE = "org.apache.openejb.core";

+private static final String ORG_APACHE_WEBBEANS_JSF = "org.apache.openwebbeans.jsf";

+

+//"a;bundle-version\\=1.0.0,b;bundle-version\\=1.0.0")

+	@Test

+	public void testCompareTwoNotSpecialBundles() {

+		System.clearProperty(WebAppBundleTrackerCustomizer.IMPL_BUNDLES);

+		VirgoEEBundleComparable comparable = new VirgoEEBundleComparable();

+	

+		Bundle b1 = EasyMock.createMock(Bundle.class);

+		Bundle b2 = EasyMock.createMock(Bundle.class);

+	

+		EasyMock.expect(b1.getSymbolicName()).andReturn("a");

+		EasyMock.expect(b2.getSymbolicName()).andReturn("b");

+		

+		EasyMock.replay(b1, b2);

+		

+		assertEquals("When not matching impl.bundles bundles should be sorted alphabetically",-1, comparable.compare(b1, b2));

+	}

+	

+	@Test

+	public void testEqualNotBundles() {

+		System.clearProperty(WebAppBundleTrackerCustomizer.IMPL_BUNDLES);

+		VirgoEEBundleComparable comparable = new VirgoEEBundleComparable();

+	

+		Bundle b1 = EasyMock.createMock(Bundle.class);

+		EasyMock.expect(b1.getSymbolicName()).andReturn("a");

+

+		EasyMock.replay(b1);

+		

+		assertEquals("Exact bundles comparison is wrong", 0, comparable.compare(b1, b1));

+	}

+	

+	@Test

+	public void testTwoBundlesSameSymbolicNames() {

+		System.clearProperty(WebAppBundleTrackerCustomizer.IMPL_BUNDLES);

+		VirgoEEBundleComparable comparable = new VirgoEEBundleComparable();

+	

+		Bundle b1 = EasyMock.createMock(Bundle.class);

+		Bundle b2 = EasyMock.createMock(Bundle.class);

+	

+		EasyMock.expect(b1.getSymbolicName()).andReturn("a");

+		EasyMock.expect(b2.getSymbolicName()).andReturn("a");

+		

+		EasyMock.replay(b1, b2);

+		

+		assertEquals("Bundles have same symbolic name, should be equal",0, comparable.compare(b1, b2));

+	}

+	

+

+	@Test

+	public void testSpecialToNotSpecialBundles() {

+		System.setProperty(WebAppBundleTrackerCustomizer.IMPL_BUNDLES, "b;bundle-version\\=1.0.0");

+		VirgoEEBundleComparable comparable = new VirgoEEBundleComparable();

+	

+		Bundle b1 = EasyMock.createMock(Bundle.class);

+		Bundle b2 = EasyMock.createMock(Bundle.class);

+	

+		EasyMock.expect(b1.getSymbolicName()).andReturn("a");

+		EasyMock.expect(b2.getSymbolicName()).andReturn("b");

+		

+		EasyMock.replay(b1, b2);

+		

+		assertEquals("Bundle b is declared as impl - should be less", -1, comparable.compare(b2, b1));

+	}

+	

+	@Test

+	public void testTwoSpecialBundles() {

+		System.setProperty(WebAppBundleTrackerCustomizer.IMPL_BUNDLES, "b;bundle-version\\=1.0.0,a;bundle-version\\=1.0.0");

+		VirgoEEBundleComparable comparable = new VirgoEEBundleComparable();

+	

+		Bundle b1 = EasyMock.createMock(Bundle.class);

+		Bundle b2 = EasyMock.createMock(Bundle.class);

+	

+		EasyMock.expect(b1.getSymbolicName()).andReturn("a");

+		EasyMock.expect(b2.getSymbolicName()).andReturn("b");

+		

+		EasyMock.replay(b1, b2);

+		

+		assertEquals("Bundle b is declared first in impl.bundles - should be less",-1, comparable.compare(b2, b1));

+	}

+	

+	@Test

+	public void realScenarioSimulation() {

+		System.setProperty(WebAppBundleTrackerCustomizer.IMPL_BUNDLES, "org.apache.openejb.core;bundle-version\\=4.5.2.SNAPSHOT,org.apache.openwebbeans.impl;bundle-version\\=1.1.7,org.glassfish.com.sun.faces;bundle-version\\=2.1.6.v201205171319-sap-3,org.apache.openwebbeans.jsf;bundle-version\\=1.1.6,org.eclipse.persistence.jpa;bundle-version\\=2.4.1.v20121003-ad44345,org.eclipse.persistence.core;bundle-version\\=2.4.1.v20121003-ad44345,org.apache.openwebbeans.web;bundle-version\\=1.1.7");

+		

+		Bundle openejb = EasyMock.createMock(Bundle.class);

+		Bundle jsf = EasyMock.createMock(Bundle.class);

+		Bundle webbeans_impl = EasyMock.createMock(Bundle.class);

+		Bundle persistence_jpa = EasyMock.createMock(Bundle.class);

+		Bundle persistence_core = EasyMock.createMock(Bundle.class);

+		Bundle webbeans_web = EasyMock.createMock(Bundle.class);

+		Bundle bundle1 = EasyMock.createMock(Bundle.class);

+		Bundle bundle2 = EasyMock.createMock(Bundle.class);

+		Bundle webbeans_jsf = EasyMock.createMock(Bundle.class);

+	

+		EasyMock.expect(openejb.getSymbolicName()).andReturn(OPENEJB_CORE).anyTimes();

+		EasyMock.expect(jsf.getSymbolicName()).andReturn(ORG_GLASSFISH_COM_SUN_FACES).anyTimes();

+		EasyMock.expect(webbeans_impl.getSymbolicName()).andReturn(ORG_APACHE_WEBBEANS_IMPL).anyTimes();		

+		EasyMock.expect(webbeans_web.getSymbolicName()).andReturn(ORG_APACHE_WEBBEANS_WEB).anyTimes();

+		EasyMock.expect(persistence_jpa.getSymbolicName()).andReturn(ORG_ECLILSE_PERSISTENCE_JPA).anyTimes();		

+		EasyMock.expect(persistence_core.getSymbolicName()).andReturn(ORG_ECLIPSE_PERSISTENCE_CORE).anyTimes();

+		EasyMock.expect(bundle1.getSymbolicName()).andReturn(BUNDLE1).anyTimes();

+		EasyMock.expect(bundle2.getSymbolicName()).andReturn(BUNDLE2).anyTimes();

+		EasyMock.expect(webbeans_jsf.getSymbolicName()).andReturn(ORG_APACHE_WEBBEANS_JSF).anyTimes();

+

+		Set<Bundle> sortedBundlesSet = new TreeSet<Bundle>(new VirgoEEBundleComparable());

+		

+		EasyMock.replay(openejb, jsf, persistence_jpa, persistence_core, webbeans_web, webbeans_impl, webbeans_jsf, bundle1, bundle2);

+		

+		sortedBundlesSet.add(bundle2);

+		sortedBundlesSet.add(bundle1);

+		sortedBundlesSet.add(webbeans_web);

+		sortedBundlesSet.add(persistence_core);

+		sortedBundlesSet.add(persistence_jpa);

+		sortedBundlesSet.add(jsf);

+		sortedBundlesSet.add(openejb);

+		sortedBundlesSet.add(webbeans_impl);

+		sortedBundlesSet.add(webbeans_jsf);

+		

+		Bundle[] sortedBundles = sortedBundlesSet.toArray(new Bundle[sortedBundlesSet.size()]);

+		assertEquals(OPENEJB_CORE, sortedBundles[0].getSymbolicName());		

+		assertEquals(ORG_APACHE_WEBBEANS_IMPL, sortedBundles[1].getSymbolicName());

+		assertEquals(ORG_GLASSFISH_COM_SUN_FACES, sortedBundles[2].getSymbolicName());

+		assertEquals(ORG_APACHE_WEBBEANS_JSF, sortedBundles[3].getSymbolicName());

+		assertEquals(ORG_ECLILSE_PERSISTENCE_JPA, sortedBundles[4].getSymbolicName());

+		assertEquals(ORG_ECLIPSE_PERSISTENCE_CORE, sortedBundles[5].getSymbolicName());

+		assertEquals(ORG_APACHE_WEBBEANS_WEB, sortedBundles[6].getSymbolicName());	

+		assertEquals(BUNDLE1, sortedBundles[7].getSymbolicName());

+		assertEquals(BUNDLE2, sortedBundles[8].getSymbolicName());

+		

+	}

+	

+

+}
\ No newline at end of file