Bundle jars within EAR?
oskar.carlstedt Mar 17, 2007 7:09 PMHello!!
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