[jboss-user] [EJB 3.0] - Bundle jars within EAR?

oskar.carlstedt do-not-reply at jboss.com
Sat Mar 17 19:09:12 EDT 2007


Hello!!

I have tried to find a solution on my problem by reading this forum, googling for a day or two, but I can't find a good solution. My problem is EAR files containing other jar files. Deploying this file give 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:

  | 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
  |         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:

  | 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 theRequestXmlObject);
  | }
  | 
  | 
  | 
  | 
  | 
And here is what my war fil looks like

  | 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. Has anyone done tis before?

Can anyone help me with this. I lack in finding more ideas of my trial an error now.

Thanks
Oskar

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4029078#4029078

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4029078



More information about the jboss-user mailing list