Showing posts with label websphere. Show all posts
Showing posts with label websphere. Show all posts

Friday, November 30, 2012

Using CXF in Containers with JAX-WS handling - WebSphere/WebLogic

Keywords:
cxf jax-ws websphere weblogic annotation DisableIBMJAXWSEngine Ignore-Scanning-Packages Ignore-Scanning-Archives prefer-web-inf-classes prefer-application-packages prefer-application-resources

Problem:
So CXF is your chosen JAX-WS framework for your application - perhaps because you want your appplication to work the same way in every servlet container - tomcat included - or because you can't avoid the need to reference the implementation rather than just the pure JAX-WS spec (access to the http-session for example). While these reasons seem valid they seem to have been considered as an afterthought in containers with built in JAX-WS handling - such as WebSphere and WebLogic.

So you follow the CXF notes and perhaps blog/mail-list posts and either are in the state where: (a) the application is not working or (b) is working but you're not sure how or why. What steps can you perform to guarantee successful deployment, and (if possible) can you understand the context for them - so you can decide if they're needed for example.

Solution:
The following are useful references:
Normally for these container/class-loader issues you can get the desired behaviour by simply getting the container to load the application's libraries first (parent last). The complication in this case is the annotation processing, which seems (in my testing at least) can happen independently of the annotation processing implementation - particularly for the association of @Resource references.

To get past this, there's essentially three areas to cover:
  1. Supply JAX-WS annotation processing libraries (geronimo) that will override the container defaults - this includes all libraries that the CXF framework and annotation processing require - because nothing can be used from the container (parent)
  2. Tell the container you're handling annotations - explicitly
  3. Setup Parent-Last Class-loading - get the container to use your applications libraries before its own

Step 1: Supply JAX-WS annotation processing libraries and dependencies

There's a longer list of libraries in the CXF Notes but many of these are not specifically essential to the JAX-WS issue (the latest JAXB libraries for example will be required by CXF in a tomcat deployment). These are the libraries that appear to be need in addition to those that would have otherwise been included with the application:
  • geronimo-annotation_1.0_spec-1.1.1.jar - Annotation Processing
  • geronimo-jaxws_2.2_spec-1.1.jar - Runtime Override
  • geronimo-stax-api_1.0_spec-1.0.1.jar - Runtime Override
  • geronimo-ws-metadata_2.0_spec-1.1.3.jar - Annotation Processing
  • stax2-api-3.1.1.jar - Runtime Override
  • woodstox-core-asl-4.1.1.jar - Library Requirement
geronimo and woodstox/stax2 are the same Apache license as CXF and these libraries are supplied as part of the CXF distribution. In WebSphere you'll know it's taken effect as in deployment you'll see:
[19/10/12 8:34:46:641 EST] 00000044 AbstractInjec W   CWNEN0070W: The javax.annotation.Resource annotation class will not be recognized because it was loaded from the 
    file:/E:/IBM/WebSphere/AppServer/profiles/AppSrv01/installedApps/SERVERNode01Cell/example-app.ear/lib/geronimo-annotation_1.0_spec-1.1.1.jar location rather than from a product class loader.
[19/10/12 8:34:46:645 EST] 00000044 AbstractInjec W   CWNEN0070W: The javax.xml.ws.WebServiceRef annotation class will not be recognized because it was loaded from the 
    file:/E:/IBM/WebSphere/AppServer/profiles/AppSrv01/installedApps/SERVERNode01Cell/example-app.ear/lib/geronimo-jaxws_2.2_spec-1.1.jar location rather than from a product class loader.
The "Runtime Override" libraries listed above are essential as the overridden annotation processing code can not load certain classes from the parent - this may include classes from javax.xml.*. These 'parent prevention' issues are most likely going to be reported as java.lang.VerifyError. In WebSphere for example you'll encounter 'parent prevention' issues as:
Caused by: java.lang.VerifyError: JVMVRFY013 class loading constraint violated; 
    class=org/apache/cxf/jaxws/context/WebServiceContextImpl,
    method=getEndpointReference([Lorg/w3c/dom/Element;)Ljavax/xml/ws/EndpointReference;,
    pc=0
    at java.lang.J9VMInternals.verifyImpl(Native Method)
    at java.lang.J9VMInternals.verify(J9VMInternals.java:85)
    at java.lang.J9VMInternals.initialize(J9VMInternals.java:162)
    at org.apache.cxf.jaxws.context.WebServiceContextResourceResolver.resolve(WebServiceContextResourceResolver.java:61)

Step 2: Tell the container you're handling annotations

This seems the strangest part but both WebSphere and WebLogic will continue to report errors - in particular about the @Resource annotation. For example, on WebSphere:
[19/10/12 17:11:03:261 EST] 00000053 webapp        E com.ibm.ws.webcontainer.webapp.WebAppImpl populateJavaNameSpace SRVE8084E: An unexpected internal server error occurred while populating the namespace.
    com.ibm.wsspi.injectionengine.InjectionException: CWNEN0044E: A resource reference binding could not be found for the following resource references [org.example.hello.HelloSoapService/context], defined for the example-app component.
    at com.ibm.wsspi.injectionengine.InjectionProcessor.resolveInjectionBindings(InjectionProcessor.java:1208)
For example, on WebLogic:
<24/10/2012 2:17:27 PM EST> <Error> <J2EE> <BEA-160223> 
    <The resource-env-ref 'org.example.hello.HelloSoapService/context' declared in the standard descriptor or annotation has no JNDI name mapped to it. 
    The resource-env-ref must be mapped to a JNDI name using the resource-env-description element of the weblogic proprietary descriptor or corresponding annotation.>

For WebSphere - Disable and Ignore Annotation Scanning

There are ways to configure this globally - in the application server settings and configuration. I'll only note here the application-specific approach. This involves setting attributes in the META-INF/MANIFEST.MF of the war file.
  1. DisableIBMJAXWSEngine: true
  2. Ignore-Scanning-Packages: comma-separated list of packages where there are service implementations - and use of the @Resource and @WebService annotations
  3. Ignore-Scanning-Archives: comma-separated list of jar-file libraries where there are service implementations - and use of the @Resource and @WebService annotations
You don't necessarily have to do both 2 & 3 - use 2 if implementations are in (war-app)/WEB-INF/classes for example. It does seem setting the Ignore-Scanning-Archives setting can significantly speed application deployment - and is harmless if there is no annotation processing required. Hand-coding MANIFEST files is risky - I'd recommend using an ant task (and define all three attributes):
<target name="dist" description="make the war and ear">
        <!-- list of packages with WS implementations - which should be ignored by container annotation processing -->
        <property name="service.packages">
            org.example.hello,
            org.example.goodbye
        </property>
        <loadresource property="service.packages.delim">
            <propertyresource name="service.packages"/>
            <filterchain>
                <tabstospaces/>
                <deletecharacters chars=" "/>
                <striplinebreaks/>
            </filterchain>
        </loadresource>    
        <path id="webapp.archives">
            <fileset dir="./example-app/WEB-INF/lib">
                <include name="**/*.jar"/>
            </fileset>
        </path>
        <pathconvert property="webapp.archives.delim" refid="webapp.archives" pathsep="," dirsep="/">
            <map from="${basedir}/example-app/WEB-INF/lib/" to=''/>
        </pathconvert>
        
     <!-- Define META-INF attributes -->  
        <manifest file="./example-app/META-INF/MANIFEST.MF" mode="update" flattenAttributes="true">
            <attribute name="DisableIBMJAXWSEngine" value="true"/>
            <attribute name="Ignore-Scanning-Packages" value="${service.packages.delim}"/>
            <attribute name="Ignore-Scanning-Archives" value="${webapp.archives.delim}"/>
        </manifest>
        <copy todir="./example-app/WEB-INF/lib">
            <fileset dir="./runtime">
                <include name="**/*.*"/>
            </fileset>
        </copy>
            
        <jar destfile="example-app.war" basedir="./example-app/"
            manifest="./example-app/META-INF/MANIFEST.MF"/>       
        <ear destfile="example-app.ear" appxml="metadata/application.xml">
            <fileset dir="." includes="example-app.war"/>
            <metainf dir="metadata" includes="*.*" excludes="application.xml"/>
        </ear>
    </target>

For WebLogic - Prefer Packages and Resources

In the (ear-app)/META-INF/weblogic-application.xml you must explicitly preference the packages supplied as part of the CXF solution and the service resources these libraries include:
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-application xmlns="http://www.bea.com/ns/weblogic/90">
    <xml>
        <parser-factory>
            <saxparser-factory>org.apache.xerces.jaxp.SAXParserFactoryImpl</saxparser-factory>
            <document-builder-factory>org.apache.xerces.jaxp.DocumentBuilderFactoryImpl</document-builder-factory>
            <transformer-factory>org.apache.xalan.processor.TransformerFactoryImpl</transformer-factory>
        </parser-factory>
    </xml>
    <application-param>
        <param-name>webapp.encoding.default</param-name>
        <param-value>UTF-8</param-value>
    </application-param>
    <prefer-application-packages>
        <!-- // for logging  --> 
        <package-name>org.apache.log4j.*</package-name> 
        <!-- // for jaxb  --> 
        <package-name>com.sun.xml.*</package-name> 
        <!-- // for apache commons lang/io  --> 
        <package-name>org.apache.commons.*</package-name> 
  <!-- // for spring/hibernate --> 
        <package-name>antlr.*</package-name> 
        <package-name>org.springframework.*</package-name>
        <!-- // for jstl -->
        <package-name>javax.servlet.jsp.jstl.*</package-name>
        <!-- // for jax-ws -->
        <package-name>javax.jws.*</package-name>
        <package-name>javax.ws.*</package-name>
  <!-- // xml processing -->
        <package-name>javax.xml.*</package-name>
        <package-name>javax.xml.stream.*</package-name>
        <package-name>org.xml.sax.*</package-name>
        <package-name>org.w3c.*</package-name>
        <package-name>org.apache.xmlcommons.*</package-name>
        <package-name>org.apache.xml.serializer.*</package-name>
        <package-name>org.apache.xerces.*</package-name>
        <package-name>org.apache.xalan.*</package-name>
        <package-name>com.ctc.wstx.*</package-name>
        <package-name>org.codehaus.*</package-name>        
    </prefer-application-packages>
    <prefer-application-resources> 
        <resource-name>META-INF/services/javax.ws.rs.ext.RuntimeDelegate</resource-name> 
        <resource-name>META-INF/services/javax.xml.bind.JAXBContext</resource-name> 
        <resource-name>META-INF/services/javax.xml.datatype.DatatypeFactory</resource-name> 
        <resource-name>META-INF/services/javax.xml.parsers.DocumentBuilderFactory</resource-name> 
        <resource-name>META-INF/services/javax.xml.parsers.SAXParserFactory</resource-name> 
        <resource-name>META-INF/services/javax.xml.stream.XMLEventFactory</resource-name> 
        <resource-name>META-INF/services/javax.xml.stream.XMLInputFactory</resource-name> 
        <resource-name>META-INF/services/javax.xml.stream.XMLOutputFactory</resource-name> 
        <resource-name>META-INF/services/javax.xml.transform.TransformerFactory</resource-name> 
        <resource-name>META-INF/services/javax.xml.validation.SchemaFactory</resource-name> 
        <resource-name>META-INF/services/javax.xml.ws.spi.Provider</resource-name> 
        <resource-name>META-INF/services/javax.xml.xpath.XPathFactory</resource-name> 
        <resource-name>META-INF/services/org.apache.cxf.bus.factory</resource-name> 
        <resource-name>META-INF/services/org.apache.xalan.extensions.bsf.BSFManager</resource-name> 
        <resource-name>META-INF/services/org.apache.xml.dtm.DTMManager</resource-name>
        <resource-name>META-INF/services/org.codehaus.stax2.validation.XMLValidationSchemaFactory.dtd</resource-name>
        <resource-name>META-INF/services/org.codehaus.stax2.validation.XMLValidationSchemaFactory.relaxng</resource-name>
        <resource-name>META-INF/services/org.codehaus.stax2.validation.XMLValidationSchemaFactory.w3c</resource-name>
        <resource-name>META-INF/services/org.osgi.framework.launch.FrameworkFactory</resource-name> 
        <resource-name>META-INF/services/org.relaxng.datatype.DatatypeLibraryFactory</resource-name> 
        <resource-name>META-INF/services/org.w3c.dom.DOMImplementationSourceList</resource-name> 
        <resource-name>META-INF/services/org.xml.sax.driver</resource-name> 
        <!-- // geronimo (at present) has no service such declaration (glassfish and others do) - include for future reference -->
        <resource-name>META-INF/services/com.sun.xml.ws.spi.db.BindingContextFactory</resource-name>
    </prefer-application-resources>    
</weblogic-application>

Step 3: Setup Parent-Last Class-loading

This is probably the easiest step.

For WebSphere - set flags during deployment

Note that this should be set at the ear and war (web module) level.

For WebLogic - set prefer-web-inf-classes

This doesn't seem to be a comprehensive setting based on what is required in the weblogic-application.xml file, but in the (war-app)/WEB-INF/weblogic.xml file, ensure prefer-web-inf-classes is set to true:
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app 
 xmlns="http://www.bea.com/ns/weblogic/90" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-web-app.xsd"> 
    <jsp-descriptor>
        <keepgenerated>false</keepgenerated>
        <page-check-seconds>-1</page-check-seconds>
        <precompile>true</precompile>
        <precompile-continue>true</precompile-continue>
        <verbose>false</verbose>
    </jsp-descriptor>
    <container-descriptor>
        <servlet-reload-check-secs>-1</servlet-reload-check-secs>
        <prefer-web-inf-classes>true</prefer-web-inf-classes>
    </container-descriptor>
</weblogic-web-app>

Happy CXF servicing.

Tuesday, October 23, 2012

Stop Hibernate info level logging to Console in WebSphere

Keywords:
websphere hibernate logging info commons logging log4j info SystemOut.log Console stdout WAS7 WAS8.5

Problem:
The application is packaged with hibernate and configured with log4j logging (to a rolling, application-specific file - hibernate set to WARN level logging) and deployed to WebSphere with parent last class loading.

Despite all this info-level messages are being output to the WebSphere system-out/console log (in WAS_HOME\profiles\[profile_name]\logs\[server_name]\SystemOut.log).

Why is the application log4j configuration (in log4j.properties) being ignored and how can the application's hibernate logging be diverted away from the console?

Solution:
Various resources on the web describe configuring WebSphere logging or hibernate logging but the bottom of this post on Hibernate and Logging specifically describes this 'leaking' of log configuration/output and how to resolve it.

Create a commons-logging.properties with the content:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
... and put this file in the application's classpath (WEB-INF/classes for example).



Notes:
By default, WebSphere Application Server is installed to use info level tracing (for all loggers that it knowns about). In WAS 8.5 you'll see this in the SystemOut.log:
[22/10/12 12:00:00:000 EST] 00000001 ManagerAdmin  I   TRAS0017I: The startup trace state is *=info.

You can edit this by going to (in WAS 8.5) Application Servers > [server_name] > Troubleshooting | Change log detail levels. You can specify the logging definition in plain text. For example, turning default logging to audit-level and disabling logging for the verbose com.ibm.ws.webcontainer.annotation module (this is a ':' delimited list):
*=audit: com.ibm.ws.webcontainer.annotation=off

Alternatively, use the "Components and Groups" section of the interface to expand items of the "tree" and right-click to select custom logging levels for a given "node" (NB for log4j users, the log levels may not match log4j - eg "audit" and "warning" instead of "warn").

Also interesting to note is that without the commons-logging.properties file defined in your web-app you will see every package from your application(s) and their libraries (where classes include logging definitions) included in this "Components and Groups" interface. Therefore if you see org.hibernate.* disappear from this interface you can be certain the configuration has worked.



Wednesday, July 18, 2007

NullPointerException tomcat5 realWriteChars

Keywords:
NullPointerException tomcat5 realWriteChars servlet

Problem:
Getting this stack trace on each access of a servlet:

java.lang.NullPointerException
 at org.apache.coyote.tomcat5.OutputBuffer.realWriteChars(OutputBuffer.java:569)
 at org.apache.tomcat.util.buf.CharChunk.flushBuffer(CharChunk.java:435)
 at org.apache.tomcat.util.buf.CharChunk.append(CharChunk.java:366)
 at org.apache.coyote.tomcat5.OutputBuffer.write(OutputBuffer.java:516)
 at org.apache.coyote.tomcat5.CoyoteWriter.write(CoyoteWriter.java:149)
 at org.apache.coyote.tomcat5.CoyoteWriter.write(CoyoteWriter.java:158)
 at org.apache.coyote.tomcat5.CoyoteWriter.print(CoyoteWriter.java:208)
 at org.apache.coyote.tomcat5.CoyoteWriter.println(CoyoteWriter.java:265)
 at com.example.MyServlet.doGet(MyServlet.java:56)


The line number in "MyServlet" code that's kicking this off is a simple PrintWriter.println() ... what it's writing to the stream is definitely not null. How could a NPE be caused in tomcat?

Solution:
I wouldn't have guessed at the issue if not trying the same servlet on WebSphere ... then you get a more useful error message:
Invalid character encoding "UTF=8"

There's a typo (ie '=' instead of '-') in the call to set the content type on the HttpResponse object! Correcting this to "UTF-8" fixes the issue:
response.setContentType("text/html; charset=UTF-8");

Thursday, January 04, 2007

JSTL TransformerFactoryImpl ClassCastException on WAS 6.0.2.11

Keywords:
JSTL TransformerFactoryImpl ClassCastException WAS 6.0.2.11 xalan JAXP core xerces

Problem:
A web application that has the following properties:
  1. includes the JAXP api jar files (in WEB-INF\lib)
  2. deploys with the class loader properties of "Parent Last"
  3. uses JSTL core
Will encounter the following stack trace from WAS when ever a JSP is loaded that contains JSTL (core reference):

JSP Processing Error
HTTP Error Code: 500
java.lang.ClassCastException: org.apache.xalan.processor.TransformerFactoryImpl
at javax.xml.transform.TransformerFactory.newInstance(Unknown Source)
at com.ibm.ws.jsp.translator.visitor.validator.PageDataImpl._getInputStream(PageDataImpl.java:125)
at com.ibm.ws.jsp.translator.visitor.validator.PageDataImpl.getInputStream(PageDataImpl.java:117)
at org.apache.taglibs.standard.tlv.JstlBaseTLV.validate(JstlBaseTLV.java:156)
at org.apache.taglibs.standard.tlv.JstlCoreTLV.validate(JstlCoreTLV.java:96)
at com.ibm.ws.jsp.translator.visitor.validator.ValidateVisitor.validateTagLib(ValidateVisitor.java:939)
at com.ibm.ws.jsp.translator.visitor.validator.ValidateVisitor.visitJspRootStart(ValidateVisitor.java:453)
at com.ibm.ws.jsp.translator.visitor.JspVisitor.processJspElement(JspVisitor.java:124)
at com.ibm.ws.jsp.translator.visitor.JspVisitor.visit(JspVisitor.java:110)
at com.ibm.ws.jsp.translator.JspTranslator.processVisitors(JspTranslator.java:121)
at com.ibm.ws.jsp.translator.utils.JspTranslatorUtil.translateJsp(JspTranslatorUtil.java:168)
at com.ibm.ws.jsp.translator.utils.JspTranslatorUtil.translateJspAndCompile(JspTranslatorUtil.java:81)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.translateJsp(JSPExtensionServletWrapper.java:360)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper._checkForTranslation(JSPExtensionServletWrapper.java:329)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.checkForTranslation(JSPExtensionServletWrapper.java:237)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.handleRequest(JSPExtensionServletWrapper.java:144)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3003)
at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:221)
at com.ibm.ws.webcontainer.VirtualHost.handleRequest(VirtualHost.java:210)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:1958)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:88)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:472)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:411)
at com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:101)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager.requestComplete(WorkQueueManager.java:566)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager.attemptIO(WorkQueueManager.java:619)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager.workerRun(WorkQueueManager.java:952)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager$Worker.run(WorkQueueManager.java:1039)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1470)


Solution:
In short, make sure the JSPs, JSTL refs and the web app are 2.4 compliant (see past post: What Spec?) and install the latest fix pack for WAS from IBM.

In detail, the following Problem ID is a different issue but underlying problem is the same - incorrect handling of loading XML & XSLT API classes for Parent Last apps - IBM - PK26233. The comment says it is resolved in the fix pack 6.0.2.15 for WebSphere Application Server, but I used 6.0.2.17 seeing it was newer - V6.0.2 Fix Pack 17.

Friday, December 08, 2006

WebSphere DTMConfigurationException: No default implementation found

Keywords:
WebSphere DTMConfigurationException DTMManager xalan 6.0.2.11

Problem:After upgrading the WebSphere Application Server JDK with the .11 Fix pack (making it 6.0.2.11) there is the following error when my web app. tries to get a transformer:
org.apache.xml.dtm.DTMConfigurationException: No default implementation found
    at org.apache.xml.dtm.DTMManager.newInstance(DTMManager.java:177)
    at org.apache.xpath.XPathContext.(XPathContext.java:125)
    at org.apache.xalan.transformer.TransformerImpl.(TransformerImpl.java:398)
    at org.apache.xalan.templates.StylesheetRoot.newTransformer(StylesheetRoot.java:197)

Solution:
The problem seems to be at least associated with the fix pack creating a new file "xalan.properties" in APPSERVER_HOME\java\jre\lib. It could also be upgrading the xalan libraries as well (in xml.jar).

Edit this file - you'll notice this isn't defining any properties, everything is commented out - and add the property:
org.apache.xml.dtm.DTMManager=org.apache.xml.dtm.ref.DTMManagerDefault


Notes:
Alternatively, remove or rename this file and the problem should also go away.

Alternatively again, add the JVM system property "org.apache.xml.dtm.DTMManager". You can do this on WebSphere by going to:
Application servers > server1 > Process Definition > Java Virtual Machine
... and adding to the Generic JVM arguments:
-Dorg.apache.xml.dtm.DTMManager=org.apache.xml.dtm.ref.DTMManagerDefault

Restart the server and the problem should also go away - use this approach for where you don't have access to the APPSERVER_HOME\java\jre\lib files and can only configure your application's JVM.

Wednesday, July 26, 2006

Slide 2.1 working with Security on WebSphere 6.0.2.11

Keywords:
slide 2.1 security websphere 6.0.2.11
Problem:
Slide 2.1 does not work "out-of-the-box" with WebSphere 6. It seems most slide-users have worked around it by turning off security. Clearly, this is not an option for a production system - so we need to get it working.
Solution:
This is a elaboration on my post #12099 to the slide-user list. Thanks to the post on the list from Lynn Richards #10690. A committer is welcome to add any content from here to the Slide-Wiki on WebSphere Setup. It certainly needs more detail. You will need:
  • slide-server-2.1 source code - in order to make corrections and re-build.

  • IBM HTTP Server (IHS) and the Web Server Plugin

Slide Source Changes - UTF-8

There are a two places (that I could find) in the code where the content type is set to "text/xml; charset=\"UTF-8\"". The WebSphere servlet container can't handle the quotes around the encoding. This needs to be changed to "text/xml; charset=UTF-8". This works for Tomcat too, so perhaps it should be committed in the server source?
  1. jakarta-slide-server-src-2.1\src\webdav\server\org\apache\slide\webdav\method\AbstractWebdavMethod.java
    128c128
    < public static final String TEXT_XML_UTF_8 = "text/xml; charset=\"UTF-8\"";
    ---
    > public static final String TEXT_XML_UTF_8 = "text/xml; charset=UTF-8";
  2. jakarta-slide-server-src-2.1\src\webdav\server\org\apache\slide\webdav\util\DirectoryIndexGenerator.java
    145c145
    
    <         res.setContentType("text/html; charset=\"UTF-8\"");
    ---
    >         res.setContentType("text/html; charset=UTF-8");

Slide Configuration

"/" Path "Forbidden"

The issue where all paths appear to be "/" no matter what path is accessed on Slide is due to the following code in jakarta-slide-server-src-2.1-\src\webdav\server\org\apache\slide\webdav\util\WebdavUtils.java and a difference in implementation between WebSphere and Tomcat
    String result = null;
  if (config.isDefaultServlet()) {
      result = req.getServletPath();
  } else {
      result = req.getPathInfo();
  }
req.getServletPath() seems to always be "/" in WebSphere when the WebDAV servlet is mapped to "/". The solution is to force slide to use the getPathInfo() method by turning off the Default Servlet flag in the web.xml:
 <param-name>default-servlet</param-name>
<param-value>false</param-value>

The EAR file might be corrupt? web.xml validation

When you install a war file on WebSphere the web.xml is parsed and validated against the spec. Any discrepancies with the spec will give you the un-helpful error that the "EAR file might be corrupt". Add the detail below to you opening node in the web.xml and make sure it is valid according to the schema (using an editor such as XML Spy) before including it in the war file:
<web-app
 version="2.4"
 xmlns="http://java.sun.com/xml/ns/j2ee";
 xsi="http://www.w3.org/2001/XMLSchema-instance"
 schemalocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
You'll find that all the <description> nodes are in the wrong place within the <init-param> nodes - they should be the first child rather than the last.
More importantly is the security-constraint section. To get authentication, you must define the constraint for all the possible http (WebDAV) methods. The problem is according to the web.xml spec, the only valid http-method values are: HEAD, GET, POST, PUT, DELETE, OPTIONS and TRACE. To have the other WebDAV methods secure as well, leave the specific http-method constraints out. This node is optional and if you don't specify any, all Http methods will be secure and this will include the WebDAV extensions too.
 <!-- Uncomment this to get authentication -->
<security-constraint>
  <web-resource-collection>
      <web-resource-name>DAV resource</web-resource-name>
      <url-pattern>/*</url-pattern>
      <!-- comment out the explicit http-method list                     
   'valid' Http Methods
         <http-method>GET</http-method>
         <http-method>HEAD</http-method>
         <http-method>OPTIONS</http-method>
         <http-method>POST</http-method>
         <http-method>PUT</http-method>
         <http-method>DELETE</http-method>
         Http Extensions
         <http-method>COPY</http-method>
         <http-method>LOCK</http-method>
         <http-method>MKCOL</http-method>
         <http-method>MOVE</http-method>
         <http-method>PROPFIND</http-method>
         <http-method>PROPPATCH</http-method>
         <http-method>UNLOCK</http-method>
         <http-method>VERSION-CONTROL</http-method>
         <http-method>REPORT</http-method>
         <http-method>CHECKIN</http-method>
         <http-method>CHECKOUT</http-method>
         <http-method>UNCHECKOUT</http-method>
         <http-method>MKWORKSPACE</http-method>
         <http-method>UPDATE</http-method>
         <http-method>LABEL</http-method>
         <http-method>MERGE</http-method>
         <http-method>BASELINE-CONTROL</http-method>
         <http-method>MKACTIVITY</http-method>
         <http-method>ACL</http-method>
         <http-method>SEARCH</http-method>
         <http-method>BIND</http-method>
         <http-method>UNBIND</http-method>
         <http-method>REBIND</http-method>
         <http-method>SUBSCRIBE</http-method>
         <http-method>UNSUBSCRIBE</http-method>
         <http-method>POLL</http-method>
         <http-method>NOTIFY</http-method>
  -->
  </web-resource-collection>
  <auth-constraint>
      <role-name>SlideAdmin</role-name>
      <role-name>User</role-name>
  </auth-constraint>
</security-constraint>

WebSphere Configuration

Global Security

How to configure WebSphere with a Custom or LDAP realm is beyond the scope of this post (maybe later) but with Security turned on, you will need to either Turn off "Java 2 Security" or define a policy file for the slide web-app.
With Java 2 security on, slide will get AccessControlException(s) when it tries to check for the existence of things like its properties file (from the "java.home" location? See Configuration.java - it will catch the exception if the load fails but not if the file.exists() check is forbidden).

WebServer Integration

It appears that when the WebSphere AppServer handles HTTP requests it assumes the same default as the IBM WebServer, namely - content is only to be expected and read for POST and PUT requests. This page on IBM's support site is old but seems to apply for v6 as well: Software
Group Ref #1145705
.
To get the WebDAV extensions to HTTP working you need to configure the IBM WebServer with the AppServer using IBM's WebServer Plugin. It's in the Plugin where you're then able to allow content in all HTTP/WebDAV requests. Ie "true" for
AcceptAllContent
Specifies whether or not users can include content in POST, PUT, GET, and HEAD requests when a Content-Length or Transfer-encoding header is contained in the request header. You can specify one of the following values for this attribute:

  • true if content is to be expected and read for all requests
  • false if content only is only to be expected and read for POST and PUT requests.
false is the default.
If you have version 6, with the WebServer and AppServer on the same machine and the Server setup to propagate changes to the plugin-cfg.xml file, you can set this flag in the Admin Console:
  • Web servers > webserver1 > Plug-in properties > Request and response
    Check the box for - Accept content for all requests
I found integrating the AppServer with the WebServer via plugin not a simple process. You should do this before installing slide and use the /snoop servlet to check if things are working via the WebServer.

Aside: If you try a URL like: http://localhost/snoop/hello/world/ok you will see the difference between the ServletPath and PathInfo in WebSphere and why we need to force slide to use the later.
You could actually use a WebServer other than IBM's. The difference will be that you may need to manually configure the Plugin in the AppServer and WebServer and then when the Admin console updates the plugin-cfg.xml file you may need to copy this to the place where the WebServer expects.

Installing Slide

After you install/deploy the slide.war (I gave it the enterprise application name of "slide") you need to edit the Class Loading properties.
Class loader mode = Parent Last
WAR class loader policy = Application
This avoids the problem of WebSphere v6 including an older version of JDOM (1.0Beta7) in its lib folder as well as property file loading issues. Check that slide has been correctly associated with the WebServer Plugin:
  • Enterprise Applications > slide > Map modules to servers
    You should see something like:
    Server
    WebSphere:cell=wasNode01Cell,node=webserver1_node,server=webserver1
    WebSphere:cell=wasNode01Cell,node=wasNode01,server=server1
It's important to see both the server and the webserver "module" in this list.
After starting the slide application it should be accessible via the WebServer (port 80 by default). All access will have to be via the WebServer and this should hopefully work without error and will be secure.

Tuesday, July 18, 2006

AccessControlException access denied WebSphere

Keywords:
java.security.AccessControlException: access denied websphere

Problem:
After enabling global security in WebSphere, all access to file system resources from the web app gives "AccessControlException" messages. The application can't load it's properties file(s).

Solution:
I actually found this solution pretty quickly with a google search. Need to turn off "Java 2 Security" in the Global Security settings or define a policy that allows your application access to the resources it needs.

To disable "Java 2 Security"
  1. Open the administrative console and go to Security-->Gloabal Security
  2. Uncheck "Enforce Java 2 Security"
  3. Save the changes and restart WebSphere
To define a policy

Monday, July 17, 2006

Can't deploy WAR on WebSphere 6 - AppDeploymentException

Keywords:
websphere war deploy install "The EAR file might be corrupt or incomplete" DeploymentDescriptorLoadException

Problem:
Trying to deploy ("install") a war file (for the Jakarta Slide WebDAV Server) in WebSphere after it appeared to work fine on Tomcat & JBoss gets the following two messages in the WebSphere Administration Console:

  1. The EAR file might be corrupt or incomplete.

  2. AppDeploymentException: [null] com.ibm.etools.j2ee.commonarchivecore.exception.DeploymentDescriptorLoadException: IWAE0022E Exception occurred loading deployment descriptor for module "[warfilename].war" in EAR file "[WebSphereHome]\profiles\[ProfileName]\wstemp\[TempFolder]\upload\[warfilename]_war.ear"


Solution:
The first message (and the .ear part of the second) is very confusing and from a quick google it seems that many developers are thrown off and attempt to put their war file in an ear ... it's not necessary.

The clue was the cause exception "DeploymentDescriptorLoadException" in the second message. It's a long story how I got to this, but the issue was my deployment descriptor - WEB-INF\web.xml. WebSphere validates this against the schema for the web.xml and is not flexible. Add this detail to you opening <web-app> node in your web.xml and make sure it is valid according to the schema (using an editor such as XML Spy):
<web-app version="2.4" 
xmlns="http://java.sun.com/xml/ns/j2ee"   
xsi="http://www.w3.org/2001/XMLSchema-instance" 
schemalocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">


In my situation slide contained a security-constraint which in turn referenced http-method names that aren't valid according to the web.xml spec (limited to HEAD, GET, POST, PUT, DELETE, OPTIONS, TRACE). But WebDAV extends the HTTP spec ... not sure what to do about that. Commenting out the entire security-constraint section or the offending http-method references fixes the issue for the mean time.


Notes:
Next issue is how to configure some basic users and roles in WebSphere. The documentation seems very thorough on overviews and definitions, but light-on when it comes to how-tos.