[jboss-jira] [JBoss JIRA] Created: (EJBTHREE-917) Cannot deploy ear with log-jars in isolated mode

Oskar Carlstedt (JIRA) jira-events at lists.jboss.org
Mon Mar 19 04:32:59 EDT 2007


Cannot deploy ear with log-jars in isolated mode
------------------------------------------------

                 Key: EJBTHREE-917
                 URL: http://jira.jboss.com/jira/browse/EJBTHREE-917
             Project: EJB 3.0
          Issue Type: Bug
    Affects Versions: EJB 3.0 RC9 - Patch 1
         Environment: JBoss 4.0.5.GA with JBossWs 1.2.0 SP1, Windows Vista Enterprise Ed. (Possible all)
            Reporter: Oskar Carlstedt


Hello!!

This is a short summary of my post at your forum http://www.jboss.org/index.html?module=bb&op=viewtopic&t=104337. I don't know if to place this in the EKB3 project or in the AS project. Maybe it belongs to the AS project.

Deploying below EAR file gives an error telling me "EJBLocal is not visible..."

A std. EAR file can contain a jar file that are used by the EJB- and web modules packed within the EAR file. Doing this with an EAR containing a war file having JAX-WS web service and a jar file containing a simple stateless Session bean. I run JBoss 4.0.5.GA in isolated mode.

My EAR file looks like:
Code:

my-test-ear
    beans.jar (having a MANIFEST.MF file with classpath pointing to lib/...)
    jaxws-web.war (having a MANIFEST.MF with classpath pointing to lib/...)
    /lib
        log4j.jar
        commons-logging.jar
        xbean.jar
        xmlpublic.jar
        saxon.jar
        ...

    /META-INF
        application.xml
        MANIFEST.MF
        jboss-app.xml (containing a loader-repository-tag with valie my-ear:app=ejb3)



************ application.xml ****************
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/application_1_4.xsd" version="1.4">
  <description>my-test</description>
  <display-name>my-test</display-name>
  <module>
    <ejb>my-test-beans.jar</ejb>
  </module>
  <module>
    <web>
      <web-uri>my-test-jaxws-web.war</web-uri>
      <context-root>/my-test-jaxws-web</context-root>
    </web>
  </module>
</application>



************** jboss-app.xml *****************
<!DOCTYPE jboss-app
          PUBLIC "-//JBoss//DTD J2EE Application 1.4//EN"
          "http://www.jboss.org/j2ee/dtd/jboss-app_4_0.dtd">
<jboss-app>
	<loader-repository>my-test:app=ejb3</loader-repository>
</jboss-app>

	


Here is the contents of my beans.jar:
Code:

my-test-beans.jar
    META-INF
        MANIFEST.MF
        maven
            my-test
                my-test-beans
                    pom.xml
                    pom.properties
    my
        beans
            TestBean.class



***************** TestBean.java ****************
package my.test;

import javax.ejb.Stateless;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlbeans.XmlObject;


@Stateless
public class TestBean implements Test {
	
	/**
	 * Declare a logger to use in this class
	 */
	private final static Log log = LogFactory.getLog(TestBean.class);

	public XmlObject doSomething(XmlObject theRequestXmlObject) {
		return theRequestXmlObject;
	}
}



******************* Test.java *********************
package my.test;

public interface Test {

    public org.apache.xmlbeans.XmlObject doSomething(org.apache.xmlbeans.XmlObject theRequestXmlObje
ct);
}




	


And here is what my war fil looks like
Code:

my-test-jaxws-web.war
    META-INF
        MANIFEST.MF
        maven
            my-test
                my-test-jaxws-web
                    pom.xml
                    pom.properties
    WEB-INF
        wsdl
            test.wsdl
            test.xsd
        classes
            my
                test
                    TestServiceEnpoint.class
        web.xml

********************** TestServiceEndpoint.java ******************
package my.test;

import java.io.ByteArrayOutputStream;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.naming.InitialContext;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.Provider;
import javax.xml.ws.Service;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.handler.MessageContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.w3c.dom.Node;

@Stateless
@WebServiceProvider(
		serviceName = "Test",
		portName = "TestSoap11Port",
		targetNamespace = "http://my-test/service",
		wsdlLocation = "WEB-INF/wsdl/test.wsdl")
@ServiceMode(value = Service.Mode.PAYLOAD)
public class TestServiceEndpoint implements Provider<Source> {

	/**
	 * Declare a logger to use
	 */
	private final static Log log = LogFactory.getLog(TestServiceEndpoint.class);
	
	/**
	 * The sei to use
	 */
	private Object sei = null;

	/**
	 * The soapaction http header. Just a string with the value 'soapaction'
	 */
	private static final String HTTP_HEADER_SOAP_ACTION = "soapaction";

	@Resource
	protected WebServiceContext webServiceContext;

	/**
	 * Does everything that must be done. This method is a kind of dispatcher
	 * that finds the business method to invoke. Invokes the method and
	 * serializes the response.
	 */
	public Source invoke(Source requestSource) {

		try {
			
			// get transformer and set output to xml
			Transformer transformer = TransformerFactory.newInstance()
					.newTransformer();
			transformer.setOutputProperty(OutputKeys.METHOD, "xml");

			// holder of encoding, used in debug
			String encoding = null;
			
			// get everything as a dom result
			DOMResult domResult = new DOMResult();
			transformer.transform(requestSource, domResult);

			// get dom node from dom result
			Node domNode = domResult.getNode();

			// let xml beans parse the dom node
			XmlObject xmlRequestObject = XmlObject.Factory.parse(domNode);

			if (log.isDebugEnabled()) {

				// get everything as a stream result
				ByteArrayOutputStream outTmpStream = new ByteArrayOutputStream();
				StreamResult streamResult = new StreamResult();
				streamResult.setOutputStream(outTmpStream);

				// transform everything into the out stream
				transformer.transform(requestSource, streamResult);

				// get encoding of incomming request, default to utf-8
				String tmpContent = new String(outTmpStream.toByteArray());
				String encodingStartToken = "encoding=\"";
				String encodingEndToken = "\"";
				
				int encodingStart = tmpContent.indexOf(encodingStartToken);
				if(encodingStart != -1) {
					
					// get end index of encoding
					encodingStart = encodingStart + encodingStartToken.length();
					int encodingEnd = tmpContent.indexOf(encodingEndToken, encodingStart);
					
					// set new encoding
					encoding = tmpContent.substring(encodingStart, encodingEnd);
				}
				else {
					
					// default encoding is UTF-8
					encoding = "UTF-8";
				}
				
				// get a string reppresentation of incomming request
				String xmlRequestString = new String(outTmpStream.toByteArray(), encoding);

				log.debug("Incomming request:\n" + xmlRequestString);
			}
			
			// instantiate the sei
			InitialContext initialContext = new InitialContext();
			sei = initialContext.lookup("my-test/TestBean/local");

			// get business method
			Method wsdlJavaMethod = getWsdlJavaMethod();
			
			// invoke method
			XmlObject xmlResponseObject = (XmlObject) wsdlJavaMethod.invoke(sei, xmlRequestObject);
			
			// if debug, debug response
			if(log.isDebugEnabled()) {
				
				// create xml options
				XmlOptions xmlOptions = new XmlOptions();
				xmlOptions.setSavePrettyPrint();
				xmlOptions.setSavePrettyPrintIndent(4);
				xmlOptions.setUseDefaultNamespace();
				
				// creat a byte arry stream where to print result
				ByteArrayOutputStream tmpStream = new ByteArrayOutputStream();
				xmlResponseObject.save(tmpStream, xmlOptions);
				
				// debug result
				log.debug("Outgoing response:\n" + new String(tmpStream.toByteArray(), encoding));
			}
			
			// return the object
			return new DOMSource(xmlResponseObject.newDomNode());
			
		} catch (RuntimeException re) {

			throw re;
		} catch (Exception e) {

			throw new WebServiceException(e);
		}
	}

	private Method getWsdlJavaMethod() {

		// get message context
		MessageContext messageContext = webServiceContext.getMessageContext();

		// get request headers from message context
		Map<String, ?> requestHeaders = (Map<String, ?>) messageContext
				.get(MessageContext.HTTP_REQUEST_HEADERS);

		// get soap action header
		List<String> soapactions = (List<String>) requestHeaders
				.get(HTTP_HEADER_SOAP_ACTION);

		// ceck soapaction assertions
		if (soapactions == null || soapactions.size() != 1) {

			// one soapaction must be given per each request
			throw new WebServiceException(
					"...");
		}
		
		// get soapaction
		String soapaction = soapactions.get(0);
		
		log.debug("Got soapaction httpheader: " + soapaction);
		
		// extract method name
		String methodName = extractJavaMethodName(soapaction);
		
		log.debug("Extracted method name from soapaction: " + methodName);
		
		// get the method to invoke
		Method wsdlJavaMethod;
		try {
			wsdlJavaMethod = sei.getClass().getMethod(methodName, new Class<?>[]{XmlObject.class});
			
			// return the found method
			return wsdlJavaMethod;
			
		} catch (SecurityException e) {
			
			throw new RuntimeException("...", e);
		} catch (NoSuchMethodException e) {
			
			throw new RuntimeException("..." xmlObject)", e);
		}
	}
	
	/**
	 * Returns the java method name extracted from a given soap action string.
	 * This method does not validate the returned value, it just extracts a
	 * possible java method name.
	 * 
	 * @param soapaction
	 *            the soap action to extract method from
	 * @return a java method name
	 */
	private String extractJavaMethodName(String soapaction) {
		
		String methodName = null;
		
		if(soapaction.indexOf(":") != -1) {
			
			// get part of soapaction after the ':'-character
			methodName = soapaction.substring(soapaction.lastIndexOf(":") + 1);
		}
		else {
			
			// no ':'-character. method name is same as soapaction
			methodName = soapaction;
		}
		
		// remove trailing cite character and then return
		return methodName.substring(0, methodName.length() - 1);
	}
}



When I deploy the war file itself (but then having all the dependencies in the WEB-INF/lib folder, that part works. But putting EJB3s and WARs together in an EAR file seems to be a problem.

Deploying the same file again, but without the jars log4j and commons-logging. Wolla!!, It seems to work.

Is this a classloader bug/error? What I mean is. The files I put in my ear are those I want to use, especially in isolated mode. As far as i know it shall not matter if a put a log4j jar in my ear, it shall override the one in the server/default/lib folder. I think this is very important when delivering ready to install archives (an archive I can send to a customer just telling him "drop the ear in the deploy folder and that's it"). 

After investigation this, I realized the problem is even worse. If I deploy my EAR file with the log4j and commons-logging jars bundled, then I must restart JBoss to be able to deploy the new ear without my logging jars. 

Best Regards
Oskar Carlstedt


-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.jboss.com/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        



More information about the jboss-jira mailing list