Showing posts with label Struts2. Show all posts
Showing posts with label Struts2. Show all posts

Saturday, March 14, 2009

Getting Struts 2.1 to work in Weblogic 10.3 - (contd)

Updates to struts2 convention plugin as well as XWork have been committed by Musachy Barraso based on my observations to help fix Struts2 for Weblogic 10.3. I would suggest you use them. You will need to take the source code for the following classes from the trunk of their src repository:

  • com.opensymphony.xwork2.util.finder.ClassFinder (xwork trunk)

  • com.opensymphony.xwork2.util.UrlUtil (xwork trunk)

  • com.opensymphony.xwork2.util.ClassLoaderUtil (xwork trunk)
    (Based on http://jira.opensymphony.com/browse/XW-672)

  • org.apache.struts2.convention.PackageBasedActionConfigBuilder (Struts2-struts2-convention-plugin trunk)

XWork trunk(http://svn.opensymphony.com/svn/xwork/trunk)
Struts2 convention plugin(http://svn.apache.org/repos/asf/struts/struts2/trunk)


Compile xwork first, install it into your local maven repository before compiling Struts2 convention plugin. The changes checked in will work in Struts 2.1.6 and xwork 2.1.2. While the changes will be present in subsequent versions of Struts2, there are other changes I am looking into for subsequent versions.

Please note here that you will still need to zip the action classes into a jar (that contains a META-INF/Manifest or META-INF/somefile) for the convention plugin to pick up your action classes.

Let me know if you have issues.

- Amit

Sunday, February 22, 2009

Getting Struts 2.1 to work in Weblogic 10.3

Over the last couple of days, I've been looking into the problems of running Struts2 in Weblogic 10.3. Once you wade through the errors however, the resolution is not as complicated. So, the main reason why Struts 2.1 does not work in Weblogic 10.3 (and could be earlier versions) is mainly because of the way Weblogic handles the WEB-INF classes and lib directories. The classes directory is zipped up into a jar called _wl_cls_gen.jar. Struts 2.1 specifically is looking for actions either in the classes directory or in a jar with a "META-INF/Manifest". Unfortunately, the jar created does not have the manifest and Struts2 does not know that it needs to look in a jar for the struts actions. Also, every jar within a WAR file is available as a resource via the zip file protocol, instead of a more standard jar file protocol (a really quirky implementation from BEA on this....:(, shame on them!!!).

So then how does one go about fixing these issues? Here are the steps:

  • You will need to add the META-INF/Manifest file into the classes directory of your WAR. This will guarantee that the _wl_cls_gen.jar is a valid jar that Struts2 will recognize.

  • You will then need to add a struts.xml to your project with the following information:
    <constant name="struts.convention.action.includeJars" value=".*_wl_cls_gen.*"/>
    Note here that with Struts 2.1, you will be using the struts2-convention plugin, and this is an override for one of the constants that the convention plugin uses to look for actions.

  • So far, these steps were pretty easy. Now to a little bit of coding work. You will need to change a small piece of code in the convention plugin. There are 2 pieces. One piece is the change in the plugin's struts-plugin.xml. In talking with Musachy Barroso, a lead developer on Struts, this change has already been committed to the trunk. This change is to allow the convention plugin to accept the zip protocol. The change in the struts-plugin.xml is:
    <constant name="struts.convention.action.fileProtocols" value="jar,zip" />

    The next is the following piece of code in the org.apache.struts2.convention.PackageBasedActionConfigBuilder class:


    private Set fileProtocols;

    @Inject("struts.convention.action.fileProtocols")
    public void setFileProtocols(String fileProtocols) {
    if (!StringTools.isTrimmedEmpty(fileProtocols)) {
    this.fileProtocols = TextParseUtil.commaDelimitedStringToSet(fileProtocols);
    }
    }

    private UrlSet buildUrlSet() throws IOException {
    UrlSet urlSet = new UrlSet(getClassLoader());

    urlSet = urlSet.exclude(ClassLoader.getSystemClassLoader().getParent());
    urlSet = urlSet.excludeJavaExtDirs();
    urlSet = urlSet.excludeJavaEndorsedDirs();
    urlSet = urlSet.excludeJavaHome();
    urlSet = urlSet.excludePaths(System.getProperty("sun.boot.class.path", ""));
    urlSet = urlSet.exclude(".*/JavaVM.framework/.*");

    if (includeJars == null) {
    urlSet = urlSet.exclude(".*?jar(!/)?");
    } else {
    //jar urls regexes were specified
    List rawIncludedUrls = urlSet.getUrls();
    Set includeUrls = new HashSet();
    boolean[] patternUsed = new boolean[includeJars.length];

    //- Changed section begins
    for (URL url : rawIncludedUrls) {
    if (fileProtocols.contains(url.getProtocol())) {
    //it is a jar file, make sure it macthes at least a url regex
    for (int i = 0; i < includeJars.length; i++) {
    String includeJar = includeJars[i];
    String extUrlForm = url.toExternalForm();
    if (Pattern.matches(includeJar, extUrlForm)) {
    // If the protocol is zip, convert to jar protocol
    if ( extUrlForm.indexOf("zip:")!=-1 ) {
    String newUrl = "jar:file:/" +
    extUrlForm.substring(4);
    url = new URL(newUrl);
    }
    includeUrls.add(url);
    patternUsed[i] = true;
    break;
    }
    }
    } else {
    //it is not a jar
    includeUrls.add(url);
    }
    }
    //- Changed section ends
    if (LOG.isWarnEnabled()) {
    for (int i = 0; i < patternUsed.length; i++) {
    if (!patternUsed[i]) {
    LOG.warn("The includeJars pattern [#0] did not match any jars in the classpath", includeJars[i]);
    }
    }
    }
    return new UrlSet(includeUrls);
    }

    return urlSet;
    }

    The piece of code that hasn't been committed and in talking with Musachy Barroso is felt temporary is the conversion of zip protocol to jar in the buildUrlSet method. This hasn't been committed to the trunk and most likely will go in as a broader code change that will affect the XWork library that Struts2 uses.


What I've laid out are fairly simple changes - compiling the struts2 convention plugin should be a cakewalk (maven based). I will keep this site updated as I hear more from Musachy if you are willing to wait it out before trying Struts2 in Weblogic. Let me know if you have problems getting things to work....

- Amit

UPDATE:
The above changes are not required with Struts 2.2. Just put the following in the struts.properties file of the project.
#struts convention property modifications for Weblogic
struts.convention.action.includeJars=.*?/your-web-app-name.*?jar(!/)?
struts.convention.action.fileProtocols=jar,zip

Wednesday, February 18, 2009

Struts2 Annotations, Dojo and Json plugin

Here's a nice way to integrate Dojo, json with the latest Struts2.1 web framework. A point to note here is that Dojo support via a plugin is deprecated in Struts2.1. My example does not use the dojo plugin, but the dojo library directly with the help of the json-plugin from the Google repository.

My Struts2 action looks as follows:

@ParentPackage("json-default")
@Namespace("/testing")
public class AjaxTestAction
{
@Action( interceptorRefs={@InterceptorRef(value="json", params={"enableSMD","true"})},
results={@Result(name = "success", type="json", params={"enableSMD","true"})} )
public String smd() {
return "success";
}

@SMDMethod
public String sayHello(String name)
{
return ("Hello " + name);
}
}


My javascript looks as follows:

//load dojo RPC
dojo.require("dojo.rpc.JsonService");

//create service object(proxy) using SMD (generated by the json result)
var service = new dojo.rpc.JsonService("<%=contextPath%>/testing/ajax-test.action");

// execute remote service call
var deferred = service.sayHello('Amit');

deferred.addCallback(function(result) {
alert(result.toString());
});

That's all you need. Cool eh?? One thing to note above is the url to the action - I'm using the convention plugin - but yours could look different. Have fun with Dojo. To me AJAX has never been easier. I'm not a UI guy, but my application is really looking like a RIA with Dojo toolkit and this JSON-RPC communication with the backend Java Struts2 actions.

- Amit