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