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 SetfileProtocols;
@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
ListrawIncludedUrls = urlSet.getUrls();
SetincludeUrls = 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
15 comments:
Hello Amit,
thanks for the proposed solution. I've been having problems using the new convention plugin on Weblogic 10.3 too.
I tried implementing the changes you suggested, but unfortunately I still can't get it to work. After applying the fix, my application's actions were properly listed in the config-browser, but when I tried to retrieve a page the properties of my action were not displayed in the view. I used a debugger to make sure that the action was actually initialised and the execute method got called just as expected. However, the get method of the property I wanted to display was never called ... Setting values from a form seems to work fine, though.
Any idea of what could be wrong?
Kind regards,
Emil
Blogger Amit said...
Quick simple example to try which works for me:
@Namespace("/test")
@Results( { @Result(name = "success", location = "/index.jsp") } )
public class HelloWorldAction extends ActionSupport
{
public String execute() throws Exception
{
return ActionSupport.SUCCESS;
}
/**
* @return the greetings
*/
public String getGreetings()
{
return "Hello Amit";
}
}
And then reference the property in a jsp as follows:
<%@ taglib prefix="s" uri="/struts-tags">
<html<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Hello</title>
</head>
<body>
<p>Hey :<s:property value="greetings"/></p>
</body>
</html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Hello</title>
</head>
<body>
<p>Hey :<s:property value="greetings"/></p>
</body>
</html>
You probably have something similar I presume. If not, try this out - this works for me.
Actually, my template did look slightly different, instead of using <s:property value="..." /> I was using EL style syntax, ${ ... }. This worked fine while running on Tomcat, but when I deployed my application on WebLogic the properties weren't displayed. I'm not sure which of the two is doing the right thing :-)
I've changed my code to use the Struts tag and now it works perfectly. Thanks again!
/e.
Hello,
Could you please tell me what do I write in the META-INF/Manifest.mf file?
Thanks
Nilima
Actually Amit, we did not need the MANIFEST file, we just need a file within META-INF. The file does not need to have anything in it.
Chris
Chris is right, however, I purposely did not suggest that because adding any file in the META-INF doesn't hold a meaning to the application classes. Creating a META-INF with a MANIFEST is in line with the JAR packaging standard.
I would recommend from a jar perspective, that you create a proper manifest. The manifest could be as simple and have just this in it -
Manifest-Version: 1.0
Built-By: YourName
Build-Jdk: 1.6.0_07
- Amit
I also added a property to inject the "jar:file:/" so that I could make it "jar:file:" on Linux.
Otherwise you get jar:file:// and xwork tries to load it as a URL.
Brilliant, thank you! This saved us hours of frustration.
Fantastic. This solved the issue. Why Weblogic decides to do things like this is beyond me.
Hello Amit,
thanks before,
i tried your solution, but im still getting error like this
Error loading configuration file struts.xml - [unknown location]
im using weblogic 10.3
do you know why ?
Vicky
Vicky
The code I've put down isn't required anymore. The updates are already now part of Struts. Just enhance the struts.properties file with the following:
#struts convention property modifications for Weblogic
struts.convention.action.includeJars=.*?/yourwebapp.*?jar(!/)?
struts.convention.action.fileProtocols=jar,zip
I added your solution to official Struts 2 Docs, thanks for support!
https://cwiki.apache.org/WW/weblogic.html
Hi,
What is 'yourwebapp' supposed to be? I used the same statements but Weblogic is showing 'the includeJars pattern yourwebapp.* did not match any jars in the classpath.
Been a while, but if you generate a jar to package the WEB-INF/classes into a jar while building the WAR file, then the name of that jar is what you’d give in this pattern.
In maven, your WAR plugin can be tweaked to create the jar
<archiveClasses>true</archiveClasses>
Hope that helps.
Post a Comment