DWR v2.0-DR1 Hacking

This is for reference only, there have been changes in newer versions of DWR, however these may prove useful for reference to those wanting to hack DWR to get it running in Confluence. These have since been superseeded, but I'm looking for those docs.

Eventually I'll get a SVN/MVN repo up and running to make all this much simpler.

This is just a mind dump of what I did.

  1. Download dwr-2.0.rc1-src
  2. Extract to C:\Java\dwr-2.0.rc1-src
  3. Create a new project/module accepting all the source paths
    • ~/demo
    • ~/java
    • ~/java5
    • ~/monitor
  4. Modified org.directwebremoting.util.LocalUtil#classForName(String)
    return Thread.currentThread().getContextClassLoader().loadClass(className);
    becomes
    return LocalUtil.class.getClassLoader().loadClass(className);
  5. Created PluginHttpRequestWrapper
    package org.directwebremoting.servlet;
    
    import javax.servlet.http.HttpServletRequestWrapper;
    import javax.servlet.http.HttpServletRequest;
    
    public class PluginHttpRequestWrapper extends HttpServletRequestWrapper {
    
        private String servletPath;
        private String pathInfo;
    
        public PluginHttpRequestWrapper(HttpServletRequest request) {
            super(request);
        }
    
        private void confluenceDetection() {
            servletPath = super.getServletPath();
            pathInfo = super.getPathInfo();
            // Detect Confluence
            if ("/plugins/servlet".equals(servletPath) && pathInfo != null && pathInfo.indexOf("/dwr") > -1) {
                // Locate "/dwr" in the pathInfo
                int idx = pathInfo.indexOf("/dwr");
                // Modify the servlet path and path info
                servletPath += pathInfo.substring(0, idx + 4);
                pathInfo = pathInfo.substring(idx + 4);
            }
        }
    
        public String getServletPath() {
            if (servletPath != null) return servletPath;
            confluenceDetection();
            return servletPath;
        }
    
        public String getPathInfo() {
            if (pathInfo != null) return pathInfo;
            confluenceDetection();
            return pathInfo;
        }
    
    }
  6. Modified org.directwebremoting.servlet.UrlProcessor#handle(HttpServletRequest request, HttpServletResponse response) - added to the top of the method
    // Encapsulate the request with my wrapper
    request = new PluginHttpRequestWrapper(request);
  7. Modified org.directwebremoting.impl.DefaultPageNormalizer#initWebXmlWelcomeFileList()
    ServletContext context = WebContextFactory.get().getServletContext();
    InputStream in = context.getResourceAsStream(PathConstants.RESOURCE_WEB_XML);
    becomes
    InputStream in = getClass().getClassLoader().getResourceAsStream(PathConstants.RESOURCE_WEB_XML);
  8. Modified org.directwebremoting.impl.DwrXmlConfigurator#setServletResourceName(String)
            ServletContext servletContext = WebContextFactory.get().getServletContext();
            if (servletContext == null)
            {
                throw new IOException(Messages.getString("DwrXmlConfigurator.MissingServletContext"));
            }
    
            InputStream in = null;
            try
            {
                in = servletContext.getResourceAsStream(servletResourceName);
                if (in == null)
                {
                    throw new IOException(Messages.getString("DwrXmlConfigurator.MissingConfigFile", servletResourceName));
                }
    
                log.debug("Configuring from servlet resource: " + servletResourceName);
                setInputStream(in);
            }
            finally
            {
                LocalUtil.close(in);
            }
    becomes
            InputStream in = null;
            try
            {
                if (servletResourceName.charAt(0) == '/') servletResourceName = servletResourceName.substring(1);
                in = getClass().getClassLoader().getResourceAsStream(servletResourceName);
                if (in == null)
                {
                    throw new IOException(Messages.getString("DwrXmlConfigurator.MissingConfigFile", servletResourceName));
                }
    
                log.debug("Configuring from servlet resource: " + servletResourceName);
                setInputStream(in);
            }
            finally
            {
                LocalUtil.close(in);
            }
  9. Modified org.directwebremoting.impl.DwrXmlConfigurator#setClassResourceName(String)
    InputStream in = getClass().getResourceAsStream(classResourceName);
    becomes
    if (classResourceName.charAt(0) == '/') classResourceName= classResourceName.substring(1);
    InputStream in = getClass().getClassLoader().getResourceAsStream(classResourceName);
  10. Modified org.directwebremoting.impl.DefaultDebugPageGenerator#generateTestPage(String, String)
    InputStream raw = getClass().getResourceAsStream(DwrConstants.PACKAGE + PathConstants.FILE_HELP);
    becomes
    String resource = DwrConstants.PACKAGE + PathConstants.FILE_HELP; 
    if (resource.charAt(0) == '/') resource = resource.substring(1);
    InputStream raw = getClass().getClassLoader().getResourceAsStream(resource);
    
  11. Modified org.directwebremoting.impl.DTDEntityResolver#resolveEntity(String, String)
    InputStream raw = getClass().getResourceAsStream(dtdname);
    becomes
    InputStream raw = getClass().getClassLoader().getResourceAsStream(dtdname);
  12. Modified org.directwebremoting.create.Ejb3Creator#getInstance()
    props.load(getClass().getResourceAsStream("/jndi.properties"));
    becomes
    props.load(getClass().getClassLoader().getResourceAsStream("/jndi.properties"));
  13. Modified org.directwebremoting.servlet.FileHandler#handle(HttpServletRequest, HttpServletResponse)
    InputStream raw = getClass().getResourceAsStream(resource);
    becomes
    if (resource.charAt(0) == '/') resource = resource.substring(1);
    InputStream raw = getClass().getClassLoader().getResourceAsStream(resource);
  14. Modified org.directwebremoting.extend.DwrConstants
    public interface DwrConstants
    {
        /**
         * The package name because people need to load resources in this package.
         */
        public static final String PACKAGE = "/org/directwebremoting";
    
        /**
         * The system dwr.xml resource name
         */
        public static final String FILE_DWR_XML = PACKAGE + "/dwr.xml";
    
        /**
         * The default dwr.xml file path
         */
        public static final String DEFAULT_DWR_XML = "/WEB-INF/dwr.xml";
    }
    becomes
    public interface DwrConstants
    {
        /**
         * The package name because people need to load resources in this package.
         */
        public static final String PACKAGE = "org/directwebremoting";
    
        /**
         * The system dwr.xml resource name
         */
        public static final String FILE_DWR_XML = PACKAGE + "/dwr.xml";
    
        /**
         * The default dwr.xml file path
         */
        public static final String DEFAULT_DWR_XML = "dwr.xml";
    }
  15. Removed the DTD line from ~\java\org\directwebremoting\dwr.xml
    <!DOCTYPE dwr PUBLIC
        "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
        "http://getahead.ltd.uk/dwr/dwr20.dtd">
    
  16. Opened up a shell and gone to c:\java\dwr-2.0.rc1-src and ran mvn package - this left me with a ~\target\dwr-2.0.rc1.jar and a ~\target\dwr-2.0.rc1-java14.jar

In theory that the DWR hacking bit out of the way - although I have to figure out which of the jar's I need to use. I'll start with the java14 one.

Using the DWR 2 hack as a Maven2 Dependency

Dependency
<dependency>
    <groupId>dwr</groupId>
    <artifactId>dwr</artifactId>
    <version>2.0.rc1-java14-confPluginHack</version>
</dependency>
Repository
<repository>
    <id>adaptavist-m1-repository</id>
    <name>Adaptavist Maven 1.x Repository</name>
    <url>http://files.adaptavist.com/maven</url>
    <layout>legacy</layout>
    <snapshots>
        <enabled>true</enabled>
    </snapshots>
</repository>

Further Hacks

When a plugin that uses this hack is used in our hosting environment our security manager borks. This is because resources are first attempted to be loaded as classes!

To counteract this I have further patched DefaultContainer.java replacing the following

// Maybe the value is a classname that needs instansiating
if (value instanceof String)

with the following

// Maybe the value is a classname that needs instansiating
if ((value instanceof String) && ((String) value).indexOf('/') == -1)

I recompiled and redeployed as a new version, the maven2 dependency you want now is:

<dependency>
    <groupId>dwr</groupId>
    <artifactId>dwr</artifactId>
    <version>2.0.rc1-java14-confPluginHack2</version>
</dependency>

DWR 2.0.1 jar

jar file for DWR 2.0.1: [^dwr-2.0.1-java14-confPluginHack2.jar]

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.