You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2009/05/12 08:14:03 UTC

svn commit: r773796 - in /openejb/trunk/openejb3: assembly/openejb-tomcat/openejb-tomcat-catalina/src/main/java/org/apache/openejb/tomcat/catalina/ container/ container/openejb-api/ container/openejb-api/src/ container/openejb-api/src/main/ container/o...

Author: dblevins
Date: Tue May 12 06:14:01 2009
New Revision: 773796

URL: http://svn.apache.org/viewvc?rev=773796&view=rev
Log:
OPENEJB-1024: TestCase Dependency Injection via @LocalClient

Still not complete -> OPENEJB-1025: Remote Client Dependency Injection via @RemoteClient

Added:
    openejb/trunk/openejb3/container/openejb-api/
    openejb/trunk/openejb3/container/openejb-api/pom.xml
    openejb/trunk/openejb3/container/openejb-api/src/
    openejb/trunk/openejb3/container/openejb-api/src/main/
    openejb/trunk/openejb3/container/openejb-api/src/main/java/
    openejb/trunk/openejb3/container/openejb-api/src/main/java/org/
    openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/
    openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/
    openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/
    openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/LocalClient.java
    openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/RemoteClient.java
    openejb/trunk/openejb3/container/openejb-api/src/main/resources/
    openejb/trunk/openejb3/container/openejb-api/src/test/
    openejb/trunk/openejb3/container/openejb-api/src/test/java/
    openejb/trunk/openejb3/container/openejb-api/src/test/resources/
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/GeneratedClientModules.java
    openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/LocalClientTest.java
Removed:
    openejb/trunk/openejb3/container/openejb-core/src/test/resources/altddapp/
Modified:
    openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-catalina/src/main/java/org/apache/openejb/tomcat/catalina/TomcatWebAppBuilder.java
    openejb/trunk/openejb3/container/openejb-core/pom.xml
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/InjectionProcessor.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ClientInfo.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/EjbReferenceInfo.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/client/LocalInitialContext.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModule.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ClearEmptyMappedName.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ClientModule.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentLoader.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentsResolver.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EjbModule.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EnvEntriesPropertiesDeployer.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/JndiEncInfoBuilder.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ReadDescriptors.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/MdbInstanceFactory.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java
    openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/webservices/HandlerResolverImpl.java
    openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/webservices/HandlerResolverImplTest.java
    openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/ApplicationClient.java
    openejb/trunk/openejb3/container/pom.xml
    openejb/trunk/openejb3/server/openejb-axis2/src/main/java/org/apache/openejb/server/axis2/pojo/PojoWsContainer.java
    openejb/trunk/openejb3/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/pojo/PojoEndpoint.java

Modified: openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-catalina/src/main/java/org/apache/openejb/tomcat/catalina/TomcatWebAppBuilder.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-catalina/src/main/java/org/apache/openejb/tomcat/catalina/TomcatWebAppBuilder.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-catalina/src/main/java/org/apache/openejb/tomcat/catalina/TomcatWebAppBuilder.java (original)
+++ openejb/trunk/openejb3/assembly/openejb-tomcat/openejb-tomcat-catalina/src/main/java/org/apache/openejb/tomcat/catalina/TomcatWebAppBuilder.java Tue May 12 06:14:01 2009
@@ -62,6 +62,7 @@
 import org.apache.openejb.config.ReadDescriptors;
 import org.apache.openejb.config.UnknownModuleTypeException;
 import org.apache.openejb.config.WebModule;
+import org.apache.openejb.config.ClientModule;
 import org.apache.openejb.core.ivm.naming.SystemComponentReference;
 import org.apache.openejb.core.webservices.JaxWsUtils;
 import org.apache.openejb.core.CoreWebDeploymentInfo;
@@ -566,12 +567,15 @@
                     
                     // create the ejb module and set its moduleId to the webapp context root name
                     EjbModule ejbModule = new EjbModule(webModule.getClassLoader(), getEjbModuleId(standardContext),file.getAbsolutePath(), null, null);
+                    ejbModule.setClientModule(new ClientModule(null, ejbModule.getClassLoader(), ejbModule.getJarLocation(), null, ejbModule.getModuleId()));
 
                     // EJB deployment descriptors
                     try {
                         ResourceFinder ejbResourceFinder = new ResourceFinder("", standardContext.getLoader().getClassLoader(), file.toURL());
                         Map<String, URL> descriptors = ejbResourceFinder.getResourcesMap("META-INF/");
+                        descriptors = DeploymentLoader.altDDSources(descriptors, true);
                         ejbModule.getAltDDs().putAll(descriptors);
+                        ejbModule.getClientModule().getAltDDs().putAll(descriptors);
                     } catch (IOException e) {
                         logger.error("Unable to determine descriptors in jar.", e);
                     }

Added: openejb/trunk/openejb3/container/openejb-api/pom.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-api/pom.xml?rev=773796&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-api/pom.xml (added)
+++ openejb/trunk/openejb3/container/openejb-api/pom.xml Tue May 12 06:14:01 2009
@@ -0,0 +1,34 @@
+<!--
+    
+    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.
+    
+-->
+
+<!-- $Rev: 714127 $ $Date: 2008-11-14 12:27:54 -0800 (Fri, 14 Nov 2008) $ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <artifactId>container</artifactId>
+    <groupId>org.apache.openejb</groupId>
+    <version>3.1.1-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>openejb-api</artifactId>
+  <packaging>jar</packaging>
+  <name>OpenEJB :: Container :: API</name>
+
+</project>
+

Added: openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/LocalClient.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/LocalClient.java?rev=773796&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/LocalClient.java (added)
+++ openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/LocalClient.java Tue May 12 06:14:01 2009
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.api;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface LocalClient {
+}

Added: openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/RemoteClient.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/RemoteClient.java?rev=773796&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/RemoteClient.java (added)
+++ openejb/trunk/openejb3/container/openejb-api/src/main/java/org/apache/openejb/api/RemoteClient.java Tue May 12 06:14:01 2009
@@ -0,0 +1,13 @@
+package org.apache.openejb.api;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RemoteClient {
+}

Modified: openejb/trunk/openejb3/container/openejb-core/pom.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/pom.xml?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/pom.xml (original)
+++ openejb/trunk/openejb3/container/openejb-core/pom.xml Tue May 12 06:14:01 2009
@@ -219,6 +219,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.openejb</groupId>
+      <artifactId>openejb-api</artifactId>
+      <version>${version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.openejb</groupId>
       <artifactId>openejb-loader</artifactId>
       <version>${version}</version>
     </dependency>

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/InjectionProcessor.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/InjectionProcessor.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/InjectionProcessor.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/InjectionProcessor.java Tue May 12 06:14:01 2009
@@ -46,6 +46,16 @@
     private final List<Method> preDestroyMethods;
     private final Context context;
     private T instance;
+    private T suppliedInstance;
+
+    public InjectionProcessor(T suppliedInstance, List<Injection> injections, Context context) {
+        this.beanClass = null;
+        this.suppliedInstance = suppliedInstance;
+        this.injections = injections;
+        this.context = context;
+        postConstructMethods = null;
+        preDestroyMethods = null;
+    }
 
     public InjectionProcessor(Class<? extends T> beanClass, List<Injection> injections, Context context) {
         this.beanClass = beanClass;
@@ -81,7 +91,16 @@
     private void construct() throws OpenEJBException {
         if (instance != null) throw new IllegalStateException("Instance already constructed");
 
-        ObjectRecipe objectRecipe = new ObjectRecipe(beanClass);
+        Class<? extends T> clazz = beanClass;
+
+        ObjectRecipe objectRecipe;
+        if (suppliedInstance != null) {
+            clazz = (Class<? extends T>) suppliedInstance.getClass();
+            objectRecipe = getInstanceRecipe(suppliedInstance);
+        } else {
+            objectRecipe = new ObjectRecipe(clazz);
+        }
+        
         objectRecipe.allow(Option.FIELD_INJECTION);
         objectRecipe.allow(Option.PRIVATE_PROPERTIES);
         objectRecipe.allow(Option.IGNORE_MISSING_PROPERTIES);
@@ -95,18 +114,18 @@
 
         Object object;
         try {
-            object = objectRecipe.create(beanClass.getClassLoader());
+            object = objectRecipe.create(clazz.getClassLoader());
         } catch (Exception e) {
-            throw new OpenEJBException("Error while creating bean " + beanClass.getName(), e);
+            throw new OpenEJBException("Error while creating bean " + clazz.getName(), e);
         }
 
         Map unsetProperties = objectRecipe.getUnsetProperties();
         if (unsetProperties.size() > 0) {
             for (Object property : unsetProperties.keySet()) {
-                logger.warning("Injection: No such property '" + property + "' in class " + beanClass.getName());
+                logger.warning("Injection: No such property '" + property + "' in class " + clazz.getName());
             }
         }
-        instance = beanClass.cast(object);
+        instance = clazz.cast(object);
     }
 
     public void postConstruct() throws OpenEJBException {
@@ -144,18 +163,22 @@
         
         boolean usePrefix = true;
         try {
-            beanClass.getConstructor();
+            if (beanClass != null) beanClass.getConstructor();
         } catch (NoSuchMethodException e) {
             // Using constructor injection
             // xbean can't handle the prefix yet
             usePrefix = false;
         }
 
+        Class clazz = beanClass;
+
+        if (suppliedInstance != null) clazz = suppliedInstance.getClass();
+
         for (Injection injection : injections) {
-            if (!injection.getTarget().isAssignableFrom(beanClass)) continue;
+            if (!injection.getTarget().isAssignableFrom(clazz)) continue;
             try {
                 String jndiName = injection.getJndiName();
-                Object value = context.lookup("java:comp/env/" + jndiName);
+                Object value = context.lookup(jndiName);
 
                 String prefix;
                 if (usePrefix) {
@@ -166,8 +189,36 @@
 
                 objectRecipe.setProperty(prefix + injection.getName(), value);
             } catch (NamingException e) {
-                logger.warning("Injection data not found in JNDI context: jndiName='" + injection.getJndiName() + "', target=" + injection.getTarget() + "/" + injection.getName());
+                logger.warning("Injection data not found in JNDI context: jndiName='" + injection.getJndiName() + "', target=" + injection.getTarget().getName() + "/" + injection.getName());
             }
         }
     }
+
+    public static Context unwrap(Context context) {
+        try {
+            context = (Context) context.lookup("java:comp/env/");
+        } catch (NamingException notAnIssue) {
+        }
+        
+        return context;
+    }
+    
+    private static ObjectRecipe getInstanceRecipe(Object instance) {
+        ObjectRecipe recipe = new ObjectRecipe(PassthroughFactory.class);
+        recipe.setFactoryMethod("create");
+
+        String param = "instance"+recipe.hashCode();
+
+        recipe.setConstructorArgNames(new String[]{param});
+        recipe.setProperty(param, instance);
+
+        return recipe;
+    }
+
+    public static class PassthroughFactory {
+        public static Object create(Object instance) {
+            return instance;
+        }
+    }
+
 }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java Tue May 12 06:14:01 2009
@@ -603,10 +603,11 @@
                 List<Injection> injections = injectionBuilder.buildInjections(clientInfo.jndiEnc);
 
                 // build the enc
-                JndiEncBuilder jndiEncBuilder = new JndiEncBuilder(clientInfo.jndiEnc, injections, clientInfo.moduleId, classLoader);
+                JndiEncBuilder jndiEncBuilder = new JndiEncBuilder(clientInfo.jndiEnc, injections, "Bean", clientInfo.moduleId, classLoader);
                 jndiEncBuilder.setClient(true);
                 jndiEncBuilder.setUseCrossClassLoaderRef(false);
                 Context context = (Context) jndiEncBuilder.build().lookup("comp/env");
+
                 containerSystem.getJNDIContext().bind("java:openejb/client/" + clientInfo.moduleId + "/comp/env", context);
                 if (clientInfo.codebase != null) {
                     containerSystem.getJNDIContext().bind("java:openejb/client/" + clientInfo.moduleId + "/comp/path", clientInfo.codebase);
@@ -618,6 +619,14 @@
                     containerSystem.getJNDIContext().bind("java:openejb/client/" + clientInfo.moduleId + "/comp/callbackHandler", clientInfo.callbackHandler);
                 }
                 containerSystem.getJNDIContext().bind("java:openejb/client/" + clientInfo.moduleId + "/comp/injections", injections);
+
+                for (String clientClassName : clientInfo.remoteClients) {
+                    containerSystem.getJNDIContext().bind("java:openejb/client/" + clientClassName, clientInfo.moduleId);
+                }
+                
+                for (String clientClassName : clientInfo.localClients) {
+                    containerSystem.getJNDIContext().bind("java:openejb/client/" + clientClassName, clientInfo.moduleId);
+                }
             }
 
             SystemInstance systemInstance = SystemInstance.get();
@@ -837,6 +846,12 @@
         List<String> clientIds = new ArrayList<String>();
         for (ClientInfo clientInfo : appInfo.clients) {
             clientIds.add(clientInfo.moduleId);
+            for (String className : clientInfo.localClients) {
+                clientIds.add(className);
+            }
+            for (String className : clientInfo.remoteClients) {
+                clientIds.add(className);
+            }
         }
 
         // Clear out naming for all components first

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ClientInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ClientInfo.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ClientInfo.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ClientInfo.java Tue May 12 06:14:01 2009
@@ -30,6 +30,9 @@
     public String largeIcon;
     public String moduleId;
     public String mainClass;
+    public final List<String> localClients = new ArrayList<String>();
+    public final List<String> remoteClients = new ArrayList<String>();
+
     public String callbackHandler;
     public final Set<String> watchedResources = new TreeSet<String>();
 

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/EjbReferenceInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/EjbReferenceInfo.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/EjbReferenceInfo.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/EjbReferenceInfo.java Tue May 12 06:14:01 2009
@@ -22,6 +22,7 @@
     public String homeClassName;
     public String interfaceClassName;
     public String ejbDeploymentId;
+    public boolean ambiguous;
     public boolean externalReference;
     public String link;
 

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/client/LocalInitialContext.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/client/LocalInitialContext.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/client/LocalInitialContext.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/client/LocalInitialContext.java Tue May 12 06:14:01 2009
@@ -17,12 +17,17 @@
 package org.apache.openejb.client;
 
 import org.apache.openejb.OpenEJB;
+import org.apache.openejb.Injection;
+import org.apache.openejb.InjectionProcessor;
+import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.api.LocalClient;
 import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.loader.Options;
 import org.apache.openejb.spi.SecurityService;
 import org.apache.openejb.spi.ContainerSystem;
 import org.apache.openejb.util.Logger;
 import org.apache.openejb.util.LogCategory;
+import org.apache.openejb.util.Debug;
 import org.apache.openejb.core.ivm.ClientSecurity;
 import org.apache.openejb.core.ivm.naming.ContextWrapper;
 
@@ -32,6 +37,8 @@
 import javax.security.auth.login.LoginException;
 import java.util.Hashtable;
 import java.util.Properties;
+import java.util.List;
+import java.util.Map;
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationTargetException;
 
@@ -201,9 +208,57 @@
 
 
     private static Context getContainerSystemEjbContext() throws NamingException {
+        Context context = getRoot();
+        context = (Context) context.lookup("openejb/local");
+        return context;
+    }
+
+    private static Context getRoot() {
         ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class);
         Context context = containerSystem.getJNDIContext();
-        context = (Context) context.lookup("openejb/local");
         return context;
     }
+
+    @Override
+    public void bind(String name, Object obj) throws NamingException {
+        if ("inject".equalsIgnoreCase(name)) {
+            inject(obj);
+        } else {
+            super.bind(name, obj);
+        }
+    }
+
+    private void inject(Object obj) throws NamingException {
+        if (obj == null) throw new NullPointerException("Object supplied to 'inject' operation is null");
+        Class clazz = obj.getClass();
+
+        Context clients = (Context) getRoot().lookup("openejb/client/");
+
+        Context context = null;
+        List<Injection> injections = null;
+
+        while (clazz != null && !clazz.equals(Object.class)) {
+            try {
+                String moduleId = (String) clients.lookup(clazz.getName());
+                injections = (List<Injection>) clients.lookup(moduleId + "/comp/injections");
+                context = (Context) clients.lookup(moduleId + "/comp/env/");
+                break;
+            } catch (NamingException e) {
+                clazz = clazz.getSuperclass();
+            }
+        }
+
+        if (injections == null) throw new NamingException("Unable to find injection meta-data for "+obj.getClass().getName()+".  Ensure that class was annotated with @"+ LocalClient.class.getName()+" and was successfully discovered and deployed.  See http://openejb.apache.org/3.0/local-client-injection.html");
+
+        Map<String,Object> env = Debug.contextToMap(context);
+
+
+        try {
+            InjectionProcessor processor = new InjectionProcessor(obj, injections, context);
+
+            processor.createInstance();
+        } catch (OpenEJBException e) {
+            throw (NamingException) new NamingException("Injection failed").initCause(e);
+        }
+    }
 }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java Tue May 12 06:14:01 2009
@@ -18,6 +18,8 @@
 
 import org.apache.openejb.DeploymentInfo;
 import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.api.LocalClient;
+import org.apache.openejb.api.RemoteClient;
 import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.core.webservices.JaxWsUtils;
 import org.apache.openejb.finder.ClassFinder;
@@ -277,6 +279,68 @@
         }
 
         public ClientModule deploy(ClientModule clientModule) throws OpenEJBException {
+
+            if (clientModule.getApplicationClient() == null){
+                if (clientModule.getRemoteClients().size() > 0 || clientModule.getLocalClients().size() > 0) {
+                    clientModule.setApplicationClient(new ApplicationClient());
+                }
+            }
+            
+            // Lots of jars have main classes so this might not even be an app client.
+            // We're not going to scrape it for @LocalClient or @RemoteClient annotations
+            // unless they flag us specifically by adding a META-INF/application-client.xml
+            // this will have been read in as the JAXB ApplicationClient object below.
+            // This applies only to jars that have just been flagged as ClientModules,
+            // EjbModules are also scraped for @LocalClient and @RemoteClient annotations
+            if (clientModule.getFinder() == null && clientModule.getApplicationClient() == null) return clientModule;
+
+            if (clientModule.getApplicationClient() != null && clientModule.getApplicationClient().isMetadataComplete()) return clientModule;
+
+            ClassFinder finder = clientModule.getFinder();
+
+            if (finder == null) {
+                if (clientModule.getJarLocation() != null) {
+                    try {
+                        String location = clientModule.getJarLocation();
+                        File file = new File(location);
+
+                        URL url;
+                        if (file.exists()) {
+                            url = file.toURL();
+                        } else {
+                            url = new URL(location);
+                        }
+                        finder = new ClassFinder(clientModule.getClassLoader(), url);
+                    } catch (MalformedURLException e) {
+                        startupLogger.warning("startup.scrapeFailedForModule", clientModule.getJarLocation());
+                        return clientModule;
+                    }
+                } else {
+                    try {
+                        finder = new ClassFinder(clientModule.getClassLoader());
+                    } catch (Exception e) {
+                        startupLogger.warning("Unable to scrape for @LocalClient or @RemoteClient annotations. ClassFinder failed.", e);
+                        return clientModule;
+                    }
+                }
+            }
+
+            // This method is also called by the deploy(EjbModule) method to see if those
+            // modules have any @LocalClient or @RemoteClient classes
+            for (Class<?> clazz : finder.findAnnotatedClasses(LocalClient.class)) {
+                clientModule.getLocalClients().add(clazz.getName());
+            }
+
+            for (Class<?> clazz : finder.findAnnotatedClasses(RemoteClient.class)) {
+                clientModule.getRemoteClients().add(clazz.getName());
+            }
+
+            if (clientModule.getApplicationClient() == null){
+                if (clientModule.getRemoteClients().size() > 0 || clientModule.getLocalClients().size() > 0) {
+                    clientModule.setApplicationClient(new ApplicationClient());
+                }
+            }
+
             return clientModule;
         }
 
@@ -358,7 +422,7 @@
                 Singleton singleton = beanClass.getAnnotation(Singleton.class);
                 String ejbName = getEjbName(singleton, beanClass);
 
-                if (!isValidAnnotationUsage(Singleton.class, beanClass, ejbName, ejbModule)) continue;
+                if (!isValidEjbAnnotationUsage(Singleton.class, beanClass, ejbName, ejbModule)) continue;
 
                 EnterpriseBean enterpriseBean = ejbJar.getEnterpriseBean(ejbName);
                 if (enterpriseBean == null) {
@@ -378,7 +442,7 @@
                 Stateless stateless = beanClass.getAnnotation(Stateless.class);
                 String ejbName = getEjbName(stateless, beanClass);
 
-                if (!isValidAnnotationUsage(Stateless.class, beanClass, ejbName, ejbModule)) continue;
+                if (!isValidEjbAnnotationUsage(Stateless.class, beanClass, ejbName, ejbModule)) continue;
 
                 EnterpriseBean enterpriseBean = ejbJar.getEnterpriseBean(ejbName);
                 if (enterpriseBean == null) {
@@ -402,7 +466,7 @@
                 Stateful stateful = beanClass.getAnnotation(Stateful.class);
                 String ejbName = getEjbName(stateful, beanClass);
 
-                if (!isValidAnnotationUsage(Stateful.class, beanClass, ejbName, ejbModule)) continue;
+                if (!isValidEjbAnnotationUsage(Stateful.class, beanClass, ejbName, ejbModule)) continue;
 
                 EnterpriseBean enterpriseBean = ejbJar.getEnterpriseBean(ejbName);
                 if (enterpriseBean == null) {
@@ -427,7 +491,7 @@
                 MessageDriven mdb = beanClass.getAnnotation(MessageDriven.class);
                 String ejbName = getEjbName(mdb, beanClass);
 
-                if (!isValidAnnotationUsage(MessageDriven.class, beanClass, ejbName, ejbModule)) continue;
+                if (!isValidEjbAnnotationUsage(MessageDriven.class, beanClass, ejbName, ejbModule)) continue;
 
                 MessageDrivenBean messageBean = (MessageDrivenBean) ejbJar.getEnterpriseBean(ejbName);
                 if (messageBean == null) {
@@ -452,6 +516,8 @@
                 }
             }
 
+            ejbModule.getFinderReference().set(finder);
+
             return ejbModule;
         }
 
@@ -475,7 +541,7 @@
             return ejbName;
         }
 
-        private boolean isValidAnnotationUsage(Class annotationClass, Class<?> beanClass, String ejbName, EjbModule ejbModule) {
+        private boolean isValidEjbAnnotationUsage(Class annotationClass, Class<?> beanClass, String ejbName, EjbModule ejbModule) {
             List<Class<? extends Annotation>> annotations = new ArrayList(asList(Singleton.class, Stateless.class, Stateful.class, MessageDriven.class));
             annotations.remove(annotationClass);
 
@@ -515,6 +581,7 @@
 
             return b;
         }
+
     }
 
     public static class ProcessAnnotatedBeans implements DynamicDeployer {
@@ -583,29 +650,115 @@
                 return clientModule;
 
             ClassLoader classLoader = clientModule.getClassLoader();
-            Class<?> clazz;
-            try {
-                clazz = classLoader.loadClass(clientModule.getMainClass());
-            } catch (ClassNotFoundException e) {
-                throw new OpenEJBException("Unable to load Client main-class: " + clientModule.getMainClass(), e);
-            }
+
             ApplicationClient client = clientModule.getApplicationClient();
-            ClassFinder inheritedClassFinder = createInheritedClassFinder(clazz);
 
-            /*
-             * @EJB
-             * @Resource
-             * @WebServiceRef
-             * @PersistenceUnit
-             * @PersistenceContext
-             */
-            buildAnnotatedRefs(client, inheritedClassFinder, classLoader);
+            if (client == null) client = new ApplicationClient();
+
+            Set<Class> remoteClients = new HashSet<Class>();
+
+            if (clientModule.getMainClass() != null){
+                String className = clientModule.getMainClass();
+
+                Class clazz;
+                try {
+                    clazz = classLoader.loadClass(className);
+                    remoteClients.add(clazz);
+                } catch (ClassNotFoundException e) {
+                    throw new OpenEJBException("Unable to load Client main-class: " + className, e);
+                }
+
+                ClassFinder inheritedClassFinder = createInheritedClassFinder(clazz);
+
+                buildAnnotatedRefs(client, inheritedClassFinder, classLoader);
+
+            }
+
+            for (String className : clientModule.getRemoteClients()) {
+                Class clazz;
+                try {
+                    clazz = classLoader.loadClass(className);
+                    remoteClients.add(clazz);
+                } catch (ClassNotFoundException e) {
+                    throw new OpenEJBException("Unable to load RemoteClient class: " + className, e);
+                }
+
+                ClassFinder inheritedClassFinder = createInheritedClassFinder(clazz);
+
+                buildAnnotatedRefs(client, inheritedClassFinder, classLoader);
+            }
+
+            for (String className : clientModule.getLocalClients()) {
+                Class clazz;
+                try {
+                    clazz = classLoader.loadClass(className);
+                } catch (ClassNotFoundException e) {
+                    throw new OpenEJBException("Unable to load LocalClient class: " + className, e);
+                }
+
+                ClassFinder inheritedClassFinder = createInheritedClassFinder(clazz);
+
+                buildAnnotatedRefs(client, inheritedClassFinder, classLoader);
+            }
+
+            validateRemoteClientRefs(classLoader, client, remoteClients);
 
             processWebServiceClientHandlers(client, classLoader);
 
             return clientModule;
         }
 
+        private void validateRemoteClientRefs(ClassLoader classLoader, ApplicationClient client, Set<Class> remoteClients) {
+            for (EjbLocalRef ref : client.getEjbLocalRef()) {
+                for (InjectionTarget target : ref.getInjectionTarget()) {
+                    try {
+                        Class<?> targetClass = classLoader.loadClass(target.getInjectionTargetClass());
+                        for (Class remoteClient : remoteClients) {
+                            if (targetClass.isAssignableFrom(remoteClient)) {
+                                fail(remoteClient.getName(), "remoteClient.ejbLocalRef", target.getInjectionTargetClass(), target.getInjectionTargetName());
+                            }
+                        }
+                    } catch (ClassNotFoundException ignore) {
+                    }
+                }
+            }
+
+            for (PersistenceContextRef ref : client.getPersistenceContextRef()) {
+                for (InjectionTarget target : ref.getInjectionTarget()) {
+                    try {
+                        Class<?> targetClass = classLoader.loadClass(target.getInjectionTargetClass());
+                        for (Class remoteClient : remoteClients) {
+                            if (targetClass.isAssignableFrom(remoteClient)) {
+                                fail(remoteClient.getName(), "remoteClient.persistenceContextRef", target.getInjectionTargetClass(), target.getInjectionTargetName());
+                            }
+                        }
+                    } catch (ClassNotFoundException ignore) {
+                    }
+                }
+            }
+
+            List<String> unusableTypes = new ArrayList<String>(knownResourceEnvTypes);
+            unusableTypes.remove("javax.jms.Topic");
+            unusableTypes.remove("javax.jms.Queue");
+
+            for (ResourceEnvRef ref : client.getResourceEnvRef()) {
+
+                if (!unusableTypes.contains(ref.getType())) continue;
+
+                for (InjectionTarget target : ref.getInjectionTarget()) {
+                    try {
+                        Class<?> targetClass = classLoader.loadClass(target.getInjectionTargetClass());
+                        for (Class remoteClient : remoteClients) {
+                            if (targetClass.isAssignableFrom(remoteClient)) {
+                                fail(remoteClient.getName(), "remoteClient.resourceEnvRef", target.getInjectionTargetClass(), target.getInjectionTargetName(), ref.getType());
+                            }
+                        }
+                    } catch (ClassNotFoundException ignore) {
+                    }
+                }
+            }
+        }
+
         public ConnectorModule deploy(ConnectorModule connectorModule) throws OpenEJBException {
             // resource modules currently don't have any annotations
             return connectorModule;

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java Tue May 12 06:14:01 2009
@@ -250,6 +250,8 @@
             clientInfo.displayName = applicationClient.getDisplayName();
             clientInfo.codebase = clientModule.getJarLocation();
             clientInfo.mainClass = clientModule.getMainClass();
+            clientInfo.localClients.addAll(clientModule.getLocalClients());
+            clientInfo.remoteClients.addAll(clientModule.getRemoteClients());
             clientInfo.callbackHandler = applicationClient.getCallbackHandler();
             clientInfo.moduleId = getClientModuleId(clientModule);
             clientInfo.watchedResources.addAll(clientModule.getWatchedResources());

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModule.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModule.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModule.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/AppModule.java Tue May 12 06:14:01 2009
@@ -16,17 +16,17 @@
  */
 package org.apache.openejb.config;
 
+import org.apache.openejb.jee.jpa.EntityMappings;
+
+import java.io.File;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.HashMap;
-import java.util.Collection;
 import java.util.Set;
 import java.util.TreeSet;
-import java.io.File;
-
-import org.apache.openejb.jee.jpa.EntityMappings;
 
 /**
  * @version $Rev$ $Date$

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ClearEmptyMappedName.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ClearEmptyMappedName.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ClearEmptyMappedName.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ClearEmptyMappedName.java Tue May 12 06:14:01 2009
@@ -44,6 +44,8 @@
     }
 
     private void clearEmptyMappedName(JndiConsumer consumer) {
+        if (consumer == null) return;
+        
         List<JndiReference> refs = new ArrayList<JndiReference>();
         refs.addAll(consumer.getEjbLocalRef());
         refs.addAll(consumer.getEjbRef());

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ClientModule.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ClientModule.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ClientModule.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ClientModule.java Tue May 12 06:14:01 2009
@@ -17,11 +17,14 @@
 package org.apache.openejb.config;
 
 import org.apache.openejb.jee.ApplicationClient;
+import org.apache.openejb.finder.ClassFinder;
 
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicReference;
 import java.io.File;
 
 /**
@@ -33,6 +36,10 @@
     private String jarLocation;
     private ClassLoader classLoader;
     private String mainClass;
+    private boolean ejbModuleGenerated;
+    private AtomicReference<ClassFinder> finder;
+    private final Set<String> localClients = new HashSet<String>();
+    private final Set<String> remoteClients = new HashSet<String>();
     private final Map<String,Object> altDDs = new HashMap<String,Object>();
     private final String moduleId;
     private final Set<String> watchedResources = new TreeSet<String>();
@@ -56,6 +63,26 @@
         validation = new ValidationContext(ClientModule.class, jarLocation);
     }
 
+    public boolean isEjbModuleGenerated() {
+        return ejbModuleGenerated;
+    }
+
+    public void setEjbModuleGenerated(boolean ejbModuleGenerated) {
+        this.ejbModuleGenerated = ejbModuleGenerated;
+    }
+
+    public ClassFinder getFinder() {
+        return (finder != null)? finder.get(): null;
+    }
+
+    public void setFinderReference(AtomicReference<ClassFinder> finder) {
+        this.finder = finder;
+    }
+
+    public AtomicReference<ClassFinder> getFinderReference() {
+        return this.finder;
+    }
+
     public ValidationContext getValidation() {
         return validation;
     }
@@ -76,6 +103,14 @@
         this.applicationClient = applicationClient;
     }
 
+    public Set<String> getLocalClients() {
+        return localClients;
+    }
+
+    public Set<String> getRemoteClients() {
+        return remoteClients;
+    }
+
     public ClassLoader getClassLoader() {
         return classLoader;
     }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ConfigurationFactory.java Tue May 12 06:14:01 2009
@@ -127,10 +127,14 @@
 
         Chain chain = new Chain();
 
+        chain.add(new GeneratedClientModules.Add());
+
         chain.add(new ReadDescriptors());
 
         chain.add(new AnnotationDeployer());
 
+        chain.add(new GeneratedClientModules.Prune());
+
         chain.add(new ClearEmptyMappedName());
 
         if (!options.get(VALIDATION_SKIP_PROPERTY, false)) {

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentLoader.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentLoader.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentLoader.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentLoader.java Tue May 12 06:14:01 2009
@@ -34,6 +34,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.LinkedHashSet;
 import java.util.jar.Attributes;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
@@ -43,6 +44,8 @@
 import org.apache.openejb.ClassLoaderUtil;
 import org.apache.openejb.OpenEJB;
 import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.api.LocalClient;
+import org.apache.openejb.api.RemoteClient;
 import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.jee.Application;
 import org.apache.openejb.jee.ApplicationClient;
@@ -138,6 +141,15 @@
                 addPersistenceUnits(appModule, baseUrl);
 
                 return appModule;
+            } else if (ClientModule.class.equals(moduleClass)) {
+                String jarLocation = URLs.toFilePath(baseUrl);
+                ClientModule clientModule = createClientModule(baseUrl, jarLocation, OpenEJB.class.getClassLoader(), null);
+
+                // Wrap the resource module with an Application Module
+                AppModule appModule = new AppModule(clientModule.getClassLoader(), jarLocation);
+                appModule.getClientModules().add(clientModule);
+
+                return appModule;
             } else if (ConnectorModule.class.equals(moduleClass)) {
                 String jarLocation = URLs.toFilePath(baseUrl);
                 ConnectorModule connectorModule = createConnectorModule(jarLocation, jarLocation, OpenEJB.class.getClassLoader(), null);
@@ -397,15 +409,28 @@
         }
     }
 
-    protected static ClientModule createClientModule(URL clientUrl, String absolutePath, ClassLoader appClassLoader, String moduleName) throws IOException, OpenEJBException {
+    protected static ClientModule createClientModule(URL clientUrl, String absolutePath, ClassLoader appClassLoader, String moduleName) throws OpenEJBException {
         ResourceFinder clientFinder = new ResourceFinder(clientUrl);
 
-        URL manifestUrl = clientFinder.find("META-INF/MANIFEST.MF");
-        InputStream is = manifestUrl.openStream();
-        Manifest manifest = new Manifest(is);
-        String mainClass = manifest.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
+        URL manifestUrl = null;
+        try {
+            manifestUrl = clientFinder.find("META-INF/MANIFEST.MF");
+        } catch (IOException e) {
+            // 
+        }
+
+        String mainClass = null;
+        if (manifestUrl != null) {
+            try {
+            InputStream is = manifestUrl.openStream();
+            Manifest manifest = new Manifest(is);
+            mainClass = manifest.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS);
+            } catch (IOException e) {
+                throw new OpenEJBException("Unable to determine Main-Class defined in META-INF/MANIFEST.MF file", e);
+            }
+        }
 
-        if (mainClass == null) throw new IllegalStateException("No Main-Class defined in META-INF/MANIFEST.MF file");
+//        if (mainClass == null) throw new IllegalStateException("No Main-Class defined in META-INF/MANIFEST.MF file");
         Map<String, URL> descriptors = getDescriptors(clientUrl);
 
         ApplicationClient applicationClient = null;
@@ -442,6 +467,8 @@
             ejbModule.getWatchedResources().add(URLs.toFilePath(ejbJarXmlUrl));
         }
 
+        ejbModule.setClientModule(createClientModule(baseUrl, jarPath, classLoader, null));
+
         // load webservices descriptor
         addWebservices(ejbModule);
         return ejbModule;
@@ -948,7 +975,7 @@
         return altDDSources(map, true);
     }
 
-    private static Map<String, URL> altDDSources(Map<String, URL> map, boolean log) {
+    public static Map<String, URL> altDDSources(Map<String, URL> map, boolean log) {
         String prefixes = SystemInstance.get().getProperty(OPENEJB_ALTDD_PREFIX);
 
         if (prefixes == null || prefixes.length() <= 0) return map;
@@ -1073,7 +1100,6 @@
         }
     }
 
-
     public static Class<? extends DeploymentModule> discoverModuleType(URL baseUrl, ClassLoader classLoader, boolean searchForDescriptorlessApplications) throws IOException, UnknownModuleTypeException {
         ResourceFinder finder = new ResourceFinder("", classLoader, baseUrl);
 
@@ -1116,6 +1142,8 @@
         if (searchForDescriptorlessApplications) {
             AnnotationFinder classFinder = new AnnotationFinder(classLoader, baseUrl);
 
+            final Set<Class<? extends DeploymentModule>> otherTypes = new LinkedHashSet();
+            
             AnnotationFinder.Filter filter = new AnnotationFinder.Filter() {
                 public boolean accept(String annotationName) {
                     if (annotationName.startsWith("javax.ejb.")) {
@@ -1123,6 +1151,9 @@
                         if ("javax.ejb.Stateless".equals(annotationName)) return true;
                         if ("javax.ejb.Singleton".equals(annotationName)) return true;
                         if ("javax.ejb.MessageDriven".equals(annotationName)) return true;
+                    } else if (annotationName.startsWith("org.apache.openejb.annotation.")){
+                        if (LocalClient.class.getName().equals(annotationName)) otherTypes.add(ClientModule.class);
+                        if (RemoteClient.class.getName().equals(annotationName)) otherTypes.add(ClientModule.class);
                     }
                     return false;
                 }
@@ -1131,6 +1162,11 @@
             if (classFinder.find(filter)) {
                 return EjbModule.class;
             }
+
+            if (otherTypes.size() > 0){
+                // We may want some ordering/sorting if we add more type scanning
+                return otherTypes.iterator().next();
+            }
         }
 
         if (descriptors.containsKey("persistence.xml")) {

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentsResolver.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentsResolver.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentsResolver.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/DeploymentsResolver.java Tue May 12 06:14:01 2009
@@ -292,7 +292,7 @@
             String path;
             try {
                 Class<? extends DeploymentModule> moduleType = DeploymentLoader.discoverModuleType(url, classLoader, searchForDescriptorlessApplications);
-                if (AppModule.class.isAssignableFrom(moduleType) || EjbModule.class.isAssignableFrom(moduleType) || PersistenceModule.class.isAssignableFrom(moduleType) || ConnectorModule.class.isAssignableFrom(moduleType)) {
+                if (AppModule.class.isAssignableFrom(moduleType) || EjbModule.class.isAssignableFrom(moduleType) || PersistenceModule.class.isAssignableFrom(moduleType) || ConnectorModule.class.isAssignableFrom(moduleType) || ClientModule.class.isAssignableFrom(moduleType)) {
                     deployment = JaxbOpenejb.createDeployments();
                     if (url.getProtocol().equals("jar")) {
                         url = new URL(url.getFile().replaceFirst("!.*$", ""));

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EjbModule.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EjbModule.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EjbModule.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EjbModule.java Tue May 12 06:14:01 2009
@@ -20,12 +20,14 @@
 import org.apache.openejb.jee.EjbJar;
 import org.apache.openejb.jee.Webservices;
 import org.apache.openejb.jee.oejb3.OpenejbJar;
+import org.apache.openejb.finder.ClassFinder;
 
 import java.io.File;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Class is to remain "dumb" and should not have deployment logic added to it.
@@ -42,9 +44,12 @@
     private OpenejbJar openejbJar;
     private Webservices webservices;
     private String moduleId;
+    private final AtomicReference<ClassFinder> finder = new AtomicReference<ClassFinder>();
     private final Map<String,Object> altDDs = new HashMap<String,Object>();
     private final Set<String> watchedResources = new TreeSet<String>();
 
+    private ClientModule clientModule;
+
     public EjbModule(EjbJar ejbJar){
         this(Thread.currentThread().getContextClassLoader(), null, ejbJar, null);
     }
@@ -91,6 +96,26 @@
         this(classLoader, null, jarURI, ejbJar, openejbJar);
     }
 
+    public ClassFinder getFinder() {
+        return (finder != null)? finder.get(): null;
+    }
+
+    public AtomicReference<ClassFinder> getFinderReference() {
+        return this.finder;
+    }
+
+    public ClientModule getClientModule() {
+        return clientModule;
+    }
+
+    public void setClientModule(ClientModule clientModule) {
+        this.clientModule = clientModule;
+        if (clientModule != null) {
+            clientModule.setEjbModuleGenerated(true);
+            clientModule.setFinderReference(finder);
+        }
+    }
+
     public ValidationContext getValidation() {
         return validation;
     }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EnvEntriesPropertiesDeployer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EnvEntriesPropertiesDeployer.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EnvEntriesPropertiesDeployer.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/EnvEntriesPropertiesDeployer.java Tue May 12 06:14:01 2009
@@ -45,6 +45,7 @@
 
         // ApplicationClient META-INF/env-entries.properties
         for (ClientModule module : appModule.getClientModules()) {
+            if (module.getApplicationClient() == null) continue;
             for (Map.Entry<String, String> entry : getEnvEntries(module).entrySet()) {
                 EnvEntry envEntry = new EnvEntry(entry.getKey(), "java.lang.String", entry.getValue());
                 apply(module.getApplicationClient(), envEntry, "AppClient");

Added: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/GeneratedClientModules.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/GeneratedClientModules.java?rev=773796&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/GeneratedClientModules.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/GeneratedClientModules.java Tue May 12 06:14:01 2009
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.config;
+
+import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.jee.ApplicationClient;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class encompasses a little technique that saves lots of architecture rework.
+ *
+ * Essentially we're allowing an EjbModule to be both an EjbModule and a ClientModule.
+ * Trick is we don't really know if it has any @LocaClient or @RemoteClient classes
+ * until we've scanned it.  Since it's already an EjbModule and we do plan to scan
+ * it, we just automatically generate a ClientModule for all EjbModules and ensure that
+ * the ClientModule will be able to reuse the ClassFinder instance, which is a pretty
+ * heavy object created by reading all of the class files in a jar via ASM.  We really
+ * don't want to do that twice if we don't have to.  We link them by giving them the
+ * same AtomicReference<ClassFinder> object.  When one of them sets it, they both see it
+ * and the need to create a second one is avoided.
+ *
+ * If the automatically generated ClientModule doesn't turn out to really be a client after
+ * any descriptors have been read and the jar scanned, then we just remove it so it doesn't
+ * factor into the remainder of the deploy chain.
+ */
+public class GeneratedClientModules {
+
+    /**
+     * Add the auto-generated and linked ClientModule from each EjbModule
+     */
+    public static class Add implements DynamicDeployer {
+        public AppModule deploy(AppModule appModule) throws OpenEJBException {
+            for (EjbModule ejbModule : appModule.getEjbModules()) {
+                if (ejbModule.getClientModule() != null) {
+                    appModule.getClientModules().add(ejbModule.getClientModule());
+                    ejbModule.setClientModule(null);
+                }
+            }
+            return appModule;
+        }
+    }
+
+    /**
+     * Clean up any that didn't turn out to have any actual ejb clients
+     */
+    public static class Prune implements DynamicDeployer {
+        public AppModule deploy(AppModule appModule) throws OpenEJBException {
+            List<ClientModule> clientModules = new ArrayList<ClientModule>(appModule.getClientModules());
+
+            for (ClientModule clientModule : clientModules) {
+                // we automatically add a ClientModule to every EjbModule
+                // if there didn't turn out to be any clients in the module
+                // just ingore it and remove it from the clientModule list
+                boolean haveMainClassAndDescriptor = clientModule.getMainClass() != null && clientModule.getApplicationClient() != null;
+                boolean haveAnnotatedClients = clientModule.getLocalClients().size() > 0 || clientModule.getRemoteClients().size() > 0;
+
+                if (clientModule.isEjbModuleGenerated() && !haveMainClassAndDescriptor && !haveAnnotatedClients) {
+                    appModule.getClientModules().remove(clientModule);
+                } else if (clientModule.getApplicationClient() == null) {
+                    // If we're keeping it, make sure it has an ApplicationClient object.
+                    // Several places in the deploy chain check the contents of the JndiConsumer,
+                    // which is the ApplicationClient JAXB object for this module type.
+                    clientModule.setApplicationClient(new ApplicationClient());
+                }
+            }
+
+            return appModule;
+        }
+    }
+}

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/JndiEncInfoBuilder.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/JndiEncInfoBuilder.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/JndiEncInfoBuilder.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/JndiEncInfoBuilder.java Tue May 12 06:14:01 2009
@@ -197,12 +197,12 @@
             if (ref.getRefType() == EjbReference.Type.UNKNOWN) {
                 EnterpriseBeanInfo otherBean = ejbResolver.getEnterpriseBeanInfo(deploymentId);
                 if (otherBean != null) {
-                    if (otherBean.businessRemote.contains(ref.getInterface())) {
-                        ref.setRefType(EjbReference.Type.REMOTE);
-                    } else {
+                    if (otherBean.businessLocal.contains(ref.getInterface())) {
                         ref.setRefType(EjbReference.Type.LOCAL);
                         jndiConsumer.getEjbRef().remove(ref);
                         jndiConsumer.getEjbLocalRef().add(new EjbLocalRef(ref));
+                    } else {
+                        ref.setRefType(EjbReference.Type.REMOTE);
                     }
                 }
             }

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ReadDescriptors.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ReadDescriptors.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ReadDescriptors.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/ReadDescriptors.java Tue May 12 06:14:01 2009
@@ -272,8 +272,10 @@
             ApplicationClient applicationClient = readApplicationClient(url);
             clientModule.setApplicationClient(applicationClient);
         } else {
-            DeploymentLoader.logger.warning("No application-client.xml found assuming annotations present: " + appModule.getJarLocation() + ", module: " + clientModule.getModuleId());
-            clientModule.setApplicationClient(new ApplicationClient());
+            if (!clientModule.isEjbModuleGenerated()) {
+                DeploymentLoader.logger.warning("No application-client.xml found assuming annotations present: " + appModule.getJarLocation() + ", module: " + clientModule.getModuleId());
+                clientModule.setApplicationClient(new ApplicationClient());
+            }
         }
     }
 

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/MdbInstanceFactory.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/MdbInstanceFactory.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/MdbInstanceFactory.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/mdb/MdbInstanceFactory.java Tue May 12 06:14:01 2009
@@ -28,6 +28,7 @@
 
 import org.apache.openejb.Injection;
 import org.apache.openejb.InjectionProcessor;
+import static org.apache.openejb.InjectionProcessor.unwrap;
 import org.apache.openejb.core.BaseContext;
 import org.apache.openejb.core.CoreDeploymentInfo;
 import org.apache.openejb.core.Operation;
@@ -188,7 +189,7 @@
                 }
             }
 
-            InjectionProcessor injectionProcessor = new InjectionProcessor(beanClass, deploymentInfo.getInjections(), null, null, ctx);
+            InjectionProcessor injectionProcessor = new InjectionProcessor(beanClass, deploymentInfo.getInjections(), null, null, unwrap(ctx));
 
             // only in this case should the callback be used
             callContext.setCurrentOperation(Operation.INJECTION);
@@ -203,7 +204,7 @@
                 if (interceptorData.getInterceptorClass().equals(beanClass)) continue;
 
                 Class clazz = interceptorData.getInterceptorClass();
-                InjectionProcessor interceptorInjector = new InjectionProcessor(clazz, deploymentInfo.getInjections(), ctx);
+                InjectionProcessor interceptorInjector = new InjectionProcessor(clazz, deploymentInfo.getInjections(), unwrap(ctx));
 
                 try {
                     Object interceptorInstance = interceptorInjector.createInstance();

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/stateful/StatefulContainer.java Tue May 12 06:14:01 2009
@@ -48,6 +48,7 @@
 import org.apache.openejb.ProxyInfo;
 import org.apache.openejb.RpcContainer;
 import org.apache.openejb.SystemException;
+import static org.apache.openejb.InjectionProcessor.unwrap;
 import org.apache.openejb.core.CoreDeploymentInfo;
 import org.apache.openejb.core.ExceptionType;
 import static org.apache.openejb.core.ExceptionType.APPLICATION_ROLLBACK;
@@ -545,7 +546,7 @@
             }
 
             // Create bean instance
-            InjectionProcessor injectionProcessor = new InjectionProcessor(beanClass, deploymentInfo.getInjections(), null, null, ctx);
+            InjectionProcessor injectionProcessor = new InjectionProcessor(beanClass, deploymentInfo.getInjections(), null, null, unwrap(ctx));
             try {
                 if (SessionBean.class.isAssignableFrom(beanClass) || beanClass.getMethod("setSessionContext", SessionContext.class) != null) {
                     callContext.setCurrentOperation(Operation.INJECTION);
@@ -564,7 +565,7 @@
                 }
 
                 Class clazz = interceptorData.getInterceptorClass();
-                InjectionProcessor interceptorInjector = new InjectionProcessor(clazz, deploymentInfo.getInjections(), ctx);
+                InjectionProcessor interceptorInjector = new InjectionProcessor(clazz, deploymentInfo.getInjections(), unwrap(ctx));
                 try {
                     Object interceptorInstance = interceptorInjector.createInstance();
                     interceptorInstances.put(clazz.getName(), interceptorInstance);

Modified: openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/webservices/HandlerResolverImpl.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/webservices/HandlerResolverImpl.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/webservices/HandlerResolverImpl.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/webservices/HandlerResolverImpl.java Tue May 12 06:14:01 2009
@@ -19,6 +19,7 @@
 
 import org.apache.openejb.Injection;
 import org.apache.openejb.InjectionProcessor;
+import static org.apache.openejb.InjectionProcessor.unwrap;
 
 import javax.naming.Context;
 import javax.xml.namespace.QName;
@@ -78,7 +79,7 @@
                         injections,
                         handler.getPostConstruct(),
                         handler.getPreDestroy(),
-                        context);
+                        unwrap(context));
                 processor.createInstance();
                 processor.postConstruct();
                 Handler handlerInstance = processor.getInstance();

Added: openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/LocalClientTest.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/LocalClientTest.java?rev=773796&view=auto
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/LocalClientTest.java (added)
+++ openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/config/LocalClientTest.java Tue May 12 06:14:01 2009
@@ -0,0 +1,215 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.openejb.config;
+
+import junit.framework.TestCase;
+import junit.framework.Assert;
+import org.apache.openejb.OpenEJBException;
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.assembler.classic.SecurityServiceInfo;
+import org.apache.openejb.assembler.classic.TransactionServiceInfo;
+import org.apache.openejb.client.LocalInitialContextFactory;
+import org.apache.openejb.jee.EjbJar;
+import org.apache.openejb.jee.StatelessBean;
+import org.apache.openejb.jee.jpa.unit.Persistence;
+
+import javax.ejb.Local;
+import javax.ejb.Remote;
+import javax.ejb.EJB;
+import javax.jws.WebService;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+import javax.jms.ConnectionFactory;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.persistence.PersistenceUnit;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceContext;
+import javax.persistence.EntityManager;
+import javax.transaction.UserTransaction;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Properties;
+
+public class LocalClientTest extends TestCase {
+
+    @EJB
+    private Everything local;
+
+    @Resource
+    private UserTransaction useerTransaction;
+
+    @Resource
+    private DataSource daataSource;
+
+    @Resource
+    private Queue quueue;
+
+    @Resource
+    private Topic toopic;
+
+    @Resource
+    private ConnectionFactory coonnectionFactory;
+
+    @Resource
+    private QueueConnectionFactory queueCoonnectionFactory;
+
+    @Resource
+    private TopicConnectionFactory topicCoonnectionFactory;
+
+    @PersistenceUnit
+    private EntityManagerFactory emf;
+
+    @PersistenceContext
+    private EntityManager em;
+
+    public void setUp() throws OpenEJBException, NamingException, IOException {
+        ConfigurationFactory config = new ConfigurationFactory();
+        Assembler assembler = new Assembler();
+
+        assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class));
+        assembler.createSecurityService(config.configureService(SecurityServiceInfo.class));
+
+        AppModule app = new AppModule(this.getClass().getClassLoader(), "test-app");
+
+        Persistence persistence = new Persistence(new org.apache.openejb.jee.jpa.unit.PersistenceUnit("foo-unit"));
+        app.getPersistenceModules().add(new PersistenceModule("root", persistence));
+
+        EjbJar ejbJar = new EjbJar();
+        ejbJar.addEnterpriseBean(new StatelessBean(SuperBean.class));
+        app.getEjbModules().add(new EjbModule(ejbJar));
+
+        ClientModule clientModule = new ClientModule(null, app.getClassLoader(), app.getJarLocation(), null, null);
+        clientModule.getLocalClients().add(this.getClass().getName());
+
+        app.getClientModules().add(clientModule);
+        
+        assembler.createApplication(config.configureApplication(app));
+    }
+
+    public void test() throws Exception {
+
+        Properties properties = new Properties();
+        properties.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, LocalInitialContextFactory.class.getName());
+        InitialContext context = new InitialContext(properties);
+        context.bind("inject", this);
+
+        // @EJB
+        Reference reference = new Reference("test");
+
+        assertNotNull("The EJB BusinessRemote is null", local);
+        assertEquals(reference, local.echo(reference));
+        assertSame(reference, local.echo(reference)); // pass by reference
+
+        // @Resource DataSource
+        assertNotNull("The DataSource is null", daataSource);
+
+        // @Resource Topic
+        assertNotNull("The Topic is null", toopic);
+
+        // @Resource Queue
+        assertNotNull("The Queue is null", quueue);        
+
+        // @Resource ConnectionFactory
+        assertNotNull("The ConnectionFactory is null", coonnectionFactory);
+        testJmsConnection(coonnectionFactory.createConnection());
+
+        // @Resource QueueConnectionFactory
+        assertNotNull("The QueueConnectionFactory is null", queueCoonnectionFactory);
+        testJmsConnection(queueCoonnectionFactory.createConnection());
+
+        // @Resource TopicConnectionFactory
+        assertNotNull("The TopicConnectionFactory is null", queueCoonnectionFactory);
+        testJmsConnection(queueCoonnectionFactory.createConnection());
+
+        // @Resource UserTransaction
+        assertNotNull("The UserTransaction is null", useerTransaction);
+
+        // @PersistenceUnit
+        assertNotNull("The EntityManagerFactory is null", emf);
+
+        // @PersistenceContext
+        assertNotNull("The EntityManager is null", em);
+    }
+
+    public void lookupPersistenceContext() {
+        assertNotNull("The EntityManager is null", em);
+
+        try {
+            // call a do nothing method to assure entity manager actually exists
+            em.getFlushMode();
+        } catch (Exception e) {
+            fail("Received Exception " + e.getClass() + " : " + e.getMessage());
+        }
+    }
+
+    private void testJmsConnection(javax.jms.Connection connection) throws JMSException {
+        Session session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
+        Topic topic = session.createTopic("test");
+        MessageProducer producer = session.createProducer(topic);
+        producer.send(session.createMessage());
+        producer.close();
+        session.close();
+        connection.close();
+    }
+
+    @Local
+    @Remote
+    @WebService
+    public static interface Everything {
+        public Object echo(Object o);
+    }
+
+    public static class SuperBean implements Everything {
+        public Object echo(Object o) {
+            return o;
+        }
+    }
+
+    public static class Reference implements Serializable {
+        private final String value;
+
+        public Reference(String value) {
+            this.value = value;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Reference value1 = (Reference) o;
+
+            if (!value.equals(value1.value)) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return value.hashCode();
+        }
+    }
+
+}

Modified: openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/webservices/HandlerResolverImplTest.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/webservices/HandlerResolverImplTest.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/webservices/HandlerResolverImplTest.java (original)
+++ openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/core/webservices/HandlerResolverImplTest.java Tue May 12 06:14:01 2009
@@ -23,6 +23,7 @@
 import org.apache.openejb.config.ConfigurationFactory;
 import org.apache.openejb.assembler.classic.HandlerChainInfo;
 import org.apache.openejb.assembler.classic.WsBuilder;
+import org.apache.openejb.assembler.classic.Assembler;
 
 import javax.xml.ws.handler.Handler;
 import javax.xml.ws.handler.PortInfo;
@@ -33,6 +34,10 @@
 
 public class HandlerResolverImplTest extends TestCase {
 
+    public void setUp() throws Exception {
+        new Assembler();
+    }
+    
     public void testBasic() throws Exception {
         HandlerChains handlerChains = readHandlerChains("/handlers.xml");
         assertEquals(3, handlerChains.getHandlerChain().size());

Modified: openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/ApplicationClient.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/ApplicationClient.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/ApplicationClient.java (original)
+++ openejb/trunk/openejb3/container/openejb-jee/src/main/java/org/apache/openejb/jee/ApplicationClient.java Tue May 12 06:14:01 2009
@@ -40,10 +40,12 @@
         "icon",
         "envEntry",
         "ejbRef",
+        "ejbLocalRef",
         "serviceRef",
         "resourceRef",
         "resourceEnvRef",
         "messageDestinationRef",
+        "persistenceContextRef",
         "persistenceUnitRef",
         "postConstruct",
         "preDestroy",
@@ -63,6 +65,8 @@
     protected KeyedCollection<String,EnvEntry> envEntry;
     @XmlElement(name = "ejb-ref", required = true)
     protected KeyedCollection<String,EjbRef> ejbRef;
+    @XmlElement(name = "ejb-local-ref", required = true)
+    protected KeyedCollection<String,EjbLocalRef> ejbLocalRef;
     @XmlElement(name = "service-ref", required = true)
     protected KeyedCollection<String,ServiceRef> serviceRef;
     @XmlElement(name = "resource-ref", required = true)
@@ -71,6 +75,8 @@
     protected KeyedCollection<String,ResourceEnvRef> resourceEnvRef;
     @XmlElement(name = "message-destination-ref", required = true)
     protected KeyedCollection<String,MessageDestinationRef> messageDestinationRef;
+    @XmlElement(name = "persistence-context-ref", required = true)
+    protected KeyedCollection<String,PersistenceContextRef> persistenceContextRef;
     @XmlElement(name = "persistence-unit-ref", required = true)
     protected KeyedCollection<String,PersistenceUnitRef> persistenceUnitRef;
     @XmlElement(name = "post-construct", required = true)
@@ -180,11 +186,17 @@
     }
 
     public Collection<EjbLocalRef> getEjbLocalRef() {
-        return Collections.emptyList();
+        if (ejbLocalRef == null) {
+            ejbLocalRef = new KeyedCollection<String,EjbLocalRef>();
+        }
+        return this.ejbLocalRef;
     }
 
     public Map<String,EjbLocalRef> getEjbLocalRefMap() {
-        return Collections.emptyMap();
+        if (ejbLocalRef == null) {
+            ejbLocalRef = new KeyedCollection<String,EjbLocalRef>();
+        }
+        return this.ejbLocalRef.toMap();
     }
 
     public Collection<ServiceRef> getServiceRef() {
@@ -244,11 +256,17 @@
     }
 
     public Collection<PersistenceContextRef> getPersistenceContextRef() {
-        return Collections.emptyList();
+        if (persistenceContextRef == null) {
+            persistenceContextRef = new KeyedCollection<String,PersistenceContextRef>();
+        }
+        return this.persistenceContextRef;
     }
 
     public Map<String,PersistenceContextRef> getPersistenceContextRefMap() {
-        return Collections.emptyMap();
+        if (persistenceContextRef == null) {
+            persistenceContextRef = new KeyedCollection<String,PersistenceContextRef>();
+        }
+        return this.persistenceContextRef.toMap();
     }
 
     public Collection<PersistenceUnitRef> getPersistenceUnitRef() {

Modified: openejb/trunk/openejb3/container/pom.xml
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/pom.xml?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/container/pom.xml (original)
+++ openejb/trunk/openejb3/container/pom.xml Tue May 12 06:14:01 2009
@@ -27,6 +27,7 @@
   <packaging>pom</packaging>
   <name>OpenEJB :: Container</name>
   <modules>
+    <module>openejb-api</module>
     <module>openejb-core</module>
     <module>openejb-loader</module>
     <module>openejb-javaagent</module>

Modified: openejb/trunk/openejb3/server/openejb-axis2/src/main/java/org/apache/openejb/server/axis2/pojo/PojoWsContainer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/server/openejb-axis2/src/main/java/org/apache/openejb/server/axis2/pojo/PojoWsContainer.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/server/openejb-axis2/src/main/java/org/apache/openejb/server/axis2/pojo/PojoWsContainer.java (original)
+++ openejb/trunk/openejb3/server/openejb-axis2/src/main/java/org/apache/openejb/server/axis2/pojo/PojoWsContainer.java Tue May 12 06:14:01 2009
@@ -26,6 +26,7 @@
 import org.apache.axis2.transport.http.HTTPConstants;
 import org.apache.axis2.transport.http.HTTPTransportUtils;
 import org.apache.openejb.InjectionProcessor;
+import static org.apache.openejb.InjectionProcessor.unwrap;
 import org.apache.openejb.core.webservices.PortData;
 import org.apache.openejb.server.axis2.Axis2WsContainer;
 import org.apache.openejb.server.httpd.HttpRequest;
@@ -63,7 +64,7 @@
         
         // instantiate and inject resources into service
         try {
-            injectionProcessor = new InjectionProcessor<Object>(endpointClass, port.getInjections(), null, null, context);
+            injectionProcessor = new InjectionProcessor<Object>(endpointClass, port.getInjections(), null, null, unwrap(context));
             injectionProcessor.createInstance();
             injectionProcessor.postConstruct();
             endpointInstance = injectionProcessor.getInstance();

Modified: openejb/trunk/openejb3/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/pojo/PojoEndpoint.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/pojo/PojoEndpoint.java?rev=773796&r1=773795&r2=773796&view=diff
==============================================================================
--- openejb/trunk/openejb3/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/pojo/PojoEndpoint.java (original)
+++ openejb/trunk/openejb3/server/openejb-cxf/src/main/java/org/apache/openejb/server/cxf/pojo/PojoEndpoint.java Tue May 12 06:14:01 2009
@@ -21,6 +21,7 @@
 import org.apache.cxf.jaxws.JAXWSMethodInvoker;
 import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
 import org.apache.openejb.InjectionProcessor;
+import static org.apache.openejb.InjectionProcessor.unwrap;
 import org.apache.openejb.core.webservices.JaxWsUtils;
 import org.apache.openejb.core.webservices.PortData;
 import org.apache.openejb.server.cxf.CxfEndpoint;
@@ -53,7 +54,7 @@
 
         // instantiate and inject resources into service
         try {
-            injectionProcessor = new InjectionProcessor<Object>(instance, port.getInjections(), null, null, context);
+            injectionProcessor = new InjectionProcessor<Object>(instance, port.getInjections(), null, null, unwrap(context));
             injectionProcessor.createInstance();
             injectionProcessor.postConstruct();
             implementor = injectionProcessor.getInstance();