Skip to content

Instantly share code, notes, and snippets.

@dblevins
Created March 7, 2015 02:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dblevins/bf192bc47d088be2b747 to your computer and use it in GitHub Desktop.
Save dblevins/bf192bc47d088be2b747 to your computer and use it in GitHub Desktop.
Index: appserver/ejb/ejb-container/src/main/java/org/glassfish/ejb/deployment/descriptor/EjbMessageBeanDescriptor.java
===================================================================
--- appserver/ejb/ejb-container/src/main/java/org/glassfish/ejb/deployment/descriptor/EjbMessageBeanDescriptor.java (revision 59286)
+++ appserver/ejb/ejb-container/src/main/java/org/glassfish/ejb/deployment/descriptor/EjbMessageBeanDescriptor.java (working copy)
@@ -41,10 +41,12 @@
package org.glassfish.ejb.deployment.descriptor;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.logging.Level;
@@ -201,6 +203,10 @@
(methods, classLoader.loadClass(messageListenerType),
MethodDescriptor.EJB_BEAN);
+ addAllInterfaceMethodsIn
+ (methods, classLoader.loadClass(getEjbClassName()),
+ MethodDescriptor.EJB_BEAN);
+
if (isTimedObject()) {
if( getEjbTimeoutMethod() != null) {
methods.add(getEjbTimeoutMethod());
@@ -232,23 +238,25 @@
*/
public Method[] getMessageListenerInterfaceMethods(ClassLoader classLoader)
throws NoSuchMethodException {
-
- Method[] methods;
+
+ List<Method> methods = new ArrayList<Method>();
+
try {
Class messageListenerClass =
classLoader.loadClass(messageListenerType);
- methods = messageListenerClass.getDeclaredMethods();
- if( methods.length == 0 ) {
- throw new NoSuchMethodException
- ("MessageListener interface " + messageListenerType +
- " must declare at least one method");
+ for (Method method : messageListenerClass.getDeclaredMethods()) {
+ methods.add(method);
}
+ final Class<?> ejbClass = classLoader.loadClass(getEjbClassName());
+ for (Method method : ejbClass.getMethods()) {
+ methods.add(method);
+ }
} catch(Exception e) {
NoSuchMethodException nsme = new NoSuchMethodException();
nsme.initCause(e);
throw nsme;
}
- return methods;
+ return methods.toArray(new Method[methods.size()]);
}
public Vector getPossibleTransactionAttributes() {
Index: appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/EjbOptionalIntfGenerator.java
===================================================================
--- appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/EjbOptionalIntfGenerator.java (revision 59286)
+++ appserver/ejb/ejb-container/src/main/java/com/sun/ejb/codegen/EjbOptionalIntfGenerator.java (working copy)
@@ -115,6 +115,15 @@
public void generateOptionalLocalInterface(Class ejbClass, String intfClassName)
throws Exception {
+ generateInterface(ejbClass, intfClassName, Serializable.class);
+ }
+
+ public void generateInterface(Class ejbClass, String intfClassName, final Class... interfaces) throws Exception {
+ String[] interfaceNames = new String[interfaces.length];
+ for (int i = 0; i < interfaces.length; i++) {
+ interfaceNames[i] = Type.getType(interfaces[i]).getInternalName();
+ }
+
if( protectionDomain == null ) {
protectionDomain = ejbClass.getProtectionDomain();
}
@@ -128,7 +137,7 @@
tv.visit(V1_1, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
intfInternalName, null,
Type.getType(Object.class).getInternalName(),
- (new String[] {Type.getType(Serializable.class).getInternalName()}) );
+ interfaceNames );
for (java.lang.reflect.Method m : ejbClass.getMethods()) {
if (qualifiedAsBeanMethod(m)) {
@@ -172,6 +181,13 @@
Class delegateClass)
throws Exception {
+ generateSubclass(superClass, subClassName, delegateClass, IndirectlySerializable.class);
+ }
+
+ public void generateSubclass(Class superClass, String subClassName, Class delegateClass, Class... interfaces)
+ throws Exception {
+
+
if( protectionDomain == null ) {
protectionDomain = superClass.getProtectionDomain();
}
@@ -182,13 +198,14 @@
// ClassVisitor tv = (_debug)
// ? new TraceClassVisitor(cw, new PrintWriter(System.out)) : cw;
- String[] interfaces = new String[] {
- OptionalLocalInterfaceProvider.class.getName().replace('.', '/'),
- IndirectlySerializable.class.getName().replace('.', '/')
- };
+ String[] interfaceNames = new String[interfaces.length + 1];
+ interfaceNames[0] = OptionalLocalInterfaceProvider.class.getName().replace('.', '/');
+ for (int i = 0; i < interfaces.length; i++) {
+ interfaceNames[i+1] = interfaces[i].getName().replace('.', '/');
+ }
tv.visit(V1_1, ACC_PUBLIC, subClassName.replace('.', '/'), null,
- Type.getType(superClass).getInternalName(), interfaces);
+ Type.getType(superClass).getInternalName(), interfaceNames);
String fldDesc = Type.getDescriptor(delegateClass);
FieldVisitor fv = tv.visitField(ACC_PRIVATE, DELEGATE_FIELD_NAME,
@@ -233,8 +250,24 @@
generateSetDelegateMethod(tv, delegateClass, subClassName);
- generateGetSerializableObjectFactoryMethod(tv, fldDesc, subClassName.replace('.', '/'));
+ for (Class anInterface : interfaces) {
+ // dblevins: Don't think we need this special case.
+ // Should be covered by letting generateBeanMethod
+ // handle the methods on IndirectlySerializable.
+ //
+ // Not sure where the related tests are to verify.
+ if (anInterface.equals(IndirectlySerializable.class)) {
+ generateGetSerializableObjectFactoryMethod(tv, fldDesc, subClassName.replace('.', '/'));
+ continue;
+ }
+
+ for (java.lang.reflect.Method method : anInterface.getMethods()) {
+ generateBeanMethod(tv, subClassName, method, delegateClass);
+ }
+ }
+
+
Set<java.lang.reflect.Method> allMethods = new HashSet<java.lang.reflect.Method>();
for (java.lang.reflect.Method m : superClass.getMethods()) {
@@ -264,7 +297,7 @@
}
// add toString() method if it was not overridden
- java.lang.reflect.Method mth = Object.class.getDeclaredMethod("toString", emptyClassArray);
+ java.lang.reflect.Method mth = Object.class.getDeclaredMethod("toString");
if( !hasSameSignatureAsExisting(mth, allMethods)) {
//generateBeanMethod(tv, subClassName, mth, delegateClass);
generateToStringBeanMethod(tv, superClass);
@@ -312,7 +345,7 @@
}
- private static void generateToStringBeanMethod(ClassVisitor cv, Class superClass)
+ private static void generateToStringBeanMethod(ClassVisitor cv, Class superClass)
throws Exception {
String toStringMethodName = "toString";
Index: appserver/ejb/ejb-container/osgi.bundle
===================================================================
--- appserver/ejb/ejb-container/osgi.bundle (revision 59286)
+++ appserver/ejb/ejb-container/osgi.bundle (working copy)
@@ -43,6 +43,7 @@
-exportcontents: \
com.sun.ejb; \
com.sun.ejb.portable; \
+ com.sun.ejb.codegen; \
com.sun.ejb.containers; \
com.sun.ejb.containers.interceptors; \
com.sun.ejb.containers.util; \
Index: appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanInterfaceGenerator.java
===================================================================
--- appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanInterfaceGenerator.java (revision 0)
+++ appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanInterfaceGenerator.java (revision 0)
@@ -0,0 +1,76 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package org.glassfish.ejb.mdb;
+
+import com.sun.ejb.codegen.EjbOptionalIntfGenerator;
+
+import javax.resource.spi.endpoint.MessageEndpoint;
+
+public class MessageBeanInterfaceGenerator extends EjbOptionalIntfGenerator {
+
+ public MessageBeanInterfaceGenerator(ClassLoader loader) {
+ super(loader);
+ }
+
+ public Class generateMessageBeanSubClass(Class<?> beanClass, Class messageBeanInterface) throws Exception {
+ final String generatedMessageBeanSubClassName = messageBeanInterface.getName() + "__Bean__";
+
+ generateSubclass(beanClass, generatedMessageBeanSubClassName, messageBeanInterface, MessageEndpoint.class);
+ return loadClass(generatedMessageBeanSubClassName);
+ }
+
+ public Class generateMessageBeanInterface(Class<?> beanClass) throws Exception {
+ final String generatedMessageBeanInterfaceName = getGeneratedMessageBeanInterfaceName(beanClass);
+
+ generateInterface(beanClass, generatedMessageBeanInterfaceName, MessageEndpoint.class);
+ return loadClass(generatedMessageBeanInterfaceName);
+ }
+
+ public static String getGeneratedMessageBeanInterfaceName(Class<?> ejbClass) {
+ String className = ejbClass.getName();
+ int dot = className.lastIndexOf('.');
+ final String packageName = (dot == -1) ? null : className.substring(0, dot);
+ final String name = "__EJB32_Generated__" + ejbClass.getSimpleName() + "__Intf__";
+
+ return packageName != null ? packageName + "." + name : name;
+ }
+
+}
Property changes on: appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanInterfaceGenerator.java
___________________________________________________________________
Added: svn:eol-style
+ native
Index: appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanContainer.java
===================================================================
--- appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanContainer.java (revision 59286)
+++ appserver/ejb/ejb-full-container/src/main/java/org/glassfish/ejb/mdb/MessageBeanContainer.java (working copy)
@@ -40,8 +40,11 @@
package org.glassfish.ejb.mdb;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -50,11 +53,11 @@
import javax.ejb.EJBHome;
import javax.ejb.MessageDrivenBean;
import javax.ejb.RemoveException;
-import javax.naming.Context;
-import javax.naming.InitialContext;
+import javax.resource.spi.endpoint.MessageEndpoint;
import javax.transaction.Status;
import javax.transaction.xa.XAResource;
+import com.sun.ejb.spi.container.OptionalLocalInterfaceProvider;
import com.sun.enterprise.config.serverbeans.Config;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.invocation.ComponentInvocation;
@@ -130,6 +133,8 @@
private BeanPoolDescriptor beanPoolDesc_ = null;
private int maxMessageBeanListeners_;
private int numMessageBeanListeners_;
+ private Class messageBeanInterface_;
+ private Class messageBeanSubClass_;
// Property used to bootstrap message bean client factory for inbound
// message delivery.
@@ -150,6 +155,7 @@
private int statMessageCount = 0;
private TransactedPoolManager poolMgr;
+ private final Class<?> messageListenerType_;
MessageBeanContainer(EjbDescriptor desc, ClassLoader loader, SecurityManager sm)
throws Exception {
@@ -172,6 +178,17 @@
EjbInvocation ejbInvocation = null;
try {
+ Class<?> beanClass = loader.loadClass(desc.getEjbClassName());
+ messageListenerType_ = loader.loadClass(msgBeanDesc.getMessageListenerType());
+
+ Class<?> messageListenerType_1 = messageListenerType_;
+ if (isModernMessageListener(messageListenerType_1)) {
+ // Generate interface and subclass for EJB 3.2 No-interface MDB VIew
+ MessageBeanInterfaceGenerator generator = new MessageBeanInterfaceGenerator(loader);
+ messageBeanInterface_ = generator.generateMessageBeanInterface(beanClass);
+ messageBeanSubClass_ = generator.generateMessageBeanSubClass(beanClass, messageBeanInterface_);
+ }
+
// Register the tx attribute for each method on MessageListener
// interface. NOTE : These method objects MUST come from the
// MessageListener interface, NOT the bean class itself. This
@@ -702,6 +719,48 @@
return beanPoolDesc_;
}
+ /**
+ * Generates the appropriate Proxy based on the message listener type.
+ *
+ * @param handler InvocationHandler responsible for calls on the proxy
+ * @return an object implementing MessageEndpoint and the appropriate MDB view
+ * @throws Exception
+ */
+ public Object createMessageBeanProxy(InvocationHandler handler) throws Exception {
+
+ if (isModernMessageListener(messageListenerType_)) {
+ // EJB 3.2 No-interface MDB View
+
+ Proxy proxy = (Proxy) Proxy.newProxyInstance(loader, new Class[]{messageBeanInterface_}, handler);
+ OptionalLocalInterfaceProvider provider = (OptionalLocalInterfaceProvider) messageBeanSubClass_.newInstance();
+ provider.setOptionalLocalIntfProxy(proxy);
+
+ return provider;
+ } else {
+
+ // EJB 3.1 - 2.0 Interface View
+ return Proxy.newProxyInstance(loader, new Class[]{messageListenerType_, MessageEndpoint.class}, handler);
+ }
+ }
+
+ /**
+ * Detects if the message-listener type indicates an EJB 3.2 MDB No-Interface View
+ *
+ * In the future this method could potentially just return:
+ *
+ * <pre>
+ * return Annotation.class.isAssignableFrom(messageListenerType)
+ * </pre>
+ *
+ * @param messageListenerType
+ * @return true of the specified interface has no methods
+ */
+ private static boolean isModernMessageListener(Class<?> messageListenerType) {
+ // DMB: In the future, this can just return 'Annotation.class.isAssignableFrom(messageListenerType)'
+
+ return messageListenerType.getMethods().length == 0;
+ }
+
@Override
protected EJBContextImpl _constructEJBContextImpl(Object instance) {
return new MessageBeanContextImpl(instance, this);
Index: appserver/ejb/ejb-internal-api/src/main/java/org/glassfish/ejb/api/MessageBeanProtocolManager.java
===================================================================
--- appserver/ejb/ejb-internal-api/src/main/java/org/glassfish/ejb/api/MessageBeanProtocolManager.java (revision 59286)
+++ appserver/ejb/ejb-internal-api/src/main/java/org/glassfish/ejb/api/MessageBeanProtocolManager.java (working copy)
@@ -40,6 +40,7 @@
package org.glassfish.ejb.api;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.sun.enterprise.deployment.runtime.BeanPoolDescriptor;
@@ -77,6 +78,7 @@
*/
void destroyMessageBeanListener(MessageBeanListener listener);
+ Object createMessageBeanProxy(InvocationHandler handler) throws Exception;
/**
* This is used by the message provider to find out whether message
@@ -97,6 +99,6 @@
/**
* Returns the message-bean container's pool properties.
*/
- BeanPoolDescriptor getPoolDescriptor();
+ BeanPoolDescriptor getPoolDescriptor();
}
Index: appserver/connectors/connectors-inbound-runtime/src/main/java/com/sun/enterprise/connectors/inbound/ConnectorMessageBeanClient.java
===================================================================
--- appserver/connectors/connectors-inbound-runtime/src/main/java/com/sun/enterprise/connectors/inbound/ConnectorMessageBeanClient.java (revision 59286)
+++ appserver/connectors/connectors-inbound-runtime/src/main/java/com/sun/enterprise/connectors/inbound/ConnectorMessageBeanClient.java (working copy)
@@ -41,7 +41,6 @@
package com.sun.enterprise.connectors.inbound;
import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -67,7 +66,6 @@
import com.sun.enterprise.connectors.ConnectorRegistry;
import com.sun.enterprise.connectors.ConnectorRuntime;
import com.sun.enterprise.connectors.util.SetMethodAction;
-import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.ConnectorDescriptor;
import com.sun.enterprise.deployment.EjbMessageBeanDescriptor;
import com.sun.enterprise.deployment.MessageListener;
@@ -90,8 +88,6 @@
public final class ConnectorMessageBeanClient
implements MessageBeanClient, MessageEndpointFactory {
- private static final String MESSAGE_ENDPOINT =
- "javax.resource.spi.endpoint.MessageEndpoint";
private String activationName;
private ConnectorRegistry registry_;
@@ -99,6 +95,7 @@
private MessageBeanProtocolManager messageBeanPM_;
private final EjbMessageBeanDescriptor descriptor_;
private final BasicResourceAllocator allocator_;
+ private Class beanClass_;
private boolean started_ = false;
private final int CREATED = 0;
@@ -155,6 +152,14 @@
*/
public void setup(MessageBeanProtocolManager messageBeanPM) throws Exception {
+ ClassLoader loader = descriptor_.getEjbBundleDescriptor().getClassLoader();
+
+ if (loader == null) {
+ loader = Thread.currentThread().getContextClassLoader();
+ }
+
+ beanClass_ = loader.loadClass(descriptor_.getEjbClassName());
+
messageBeanPM_ = messageBeanPM;
String resourceAdapterMid = descriptor_.getResourceAdapterMid();
@@ -430,46 +435,26 @@
MessageBeanListener listener =
messageBeanPM_.createMessageBeanListener(resourceHandle);
- //Use the MDB's application classloader to load the
- //message listener class. If it is generic listener
- //class, it is expected to be packaged with the MDB application
- //or in the system classpath.
- String moduleID = getDescriptor().getApplication().getModuleID();
- Class endpointClass = null;
- ClassLoader loader = null;
- try {
- BundleDescriptor moduleDesc =
- getDescriptor().getEjbBundleDescriptor();
- loader = moduleDesc.getClassLoader();
- } catch (Exception e) {
- logger.log(Level.WARNING, "endpointfactory.loader_not_found", e);
- }
-
- if (loader == null) {
- loader = Thread.currentThread().getContextClassLoader();
- }
-
- endpointClass = loader.loadClass(MESSAGE_ENDPOINT);
-
-
- String msgListenerType = getDescriptor().getMessageListenerType();
- if (msgListenerType == null || "".equals(msgListenerType))
- msgListenerType = "javax.jms.MessageListener";
-
- Class listenerClass = loader.loadClass(msgListenerType);
-
MessageEndpointInvocationHandler handler =
new MessageEndpointInvocationHandler(listener, messageBeanPM_);
- endpoint = (MessageEndpoint) Proxy.newProxyInstance
- (loader, new Class[]{endpointClass, listenerClass}, handler);
-
+ endpoint = (MessageEndpoint) messageBeanPM_.createMessageBeanProxy(handler);
} catch (Exception ex) {
throw (UnavailableException)
(new UnavailableException()).initCause(ex);
}
return endpoint;
}
-
+
+
+ /**
+ * {@inheritDoc}
+ * @Override
+ */
+ public Class getBeanClass(){
+ return beanClass_;
+ }
+
+
/**
* {@inheritDoc}
* @Override
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment