Wednesday, June 15, 2011

java.io.FileNotFoundException: http://www.opensymphony.com/osworkflow/workflow_2_8.dtd

Have you started seeing the following error recently in your application that uses open symphony's osworkflow-2.8.0.jar?
Caused by: java.io.FileNotFoundException: http://www.opensymphony.com/osworkflow/workflow_2_8.dtd
 at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
 at org.apache.xerces.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
 at org.apache.xerces.impl.XMLEntityManager.startEntity(Unknown Source)
 at org.apache.xerces.impl.XMLEntityManager.startDTDEntity(Unknown Source)
 at org.apache.xerces.impl.XMLDTDScannerImpl.setInputSource(Unknown Source)
 at org.apache.xerces.impl.XMLDocumentScannerImpl$DTDDispatcher.dispatch(Unknown Source)
 at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
 at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
 at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
 at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
 at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
 at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source)
 at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
Reason for the above error is clear from http://www.opensymphony.com
Looking for an OpenSymphony project? Unfortunately, OpenSymphony has seen it's final days.
All the URLs to www.opensymphony.com including the URL for the DTD is now pointed to the home page. So the XML parser cannot retrieve the DTD to validate the workflow xml file. If you have a production app that uses osworkflow jar, what do you do to get the app working again?

There are couple of options:

1. You can copy the DTD bundled inside osworkflow-2.8.0.jar to your website with a static IP address under /osworkflow path, edit /etc/hosts (or C:\Windows\system32\drivers\etc\host in windows) to point www.osworkflow.com to your IP address. This will make your app to find the DTD on your server.

2. The right way to fix the issue is in your code. The place where you parse the workflow XML file.

for example:
// Load the workflow xml
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
File file = new File(workflowXmlFilename);
Document docWorkflow = builder.parse(file);
where workflowXmlFilename is your workflow xml file with the DTD pointing to http://www.opensymphony.com/osworkflow/workflow_2_8.dtd.

To resolve the DTD inside the osworkflow-2.8.0.jar, you need to set the EntityResolver of DocumentBuilder to the one provided by open symphony. Otherwise XML parser will use the default resolving mechanism.
// Load the workflow xml
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(new DTDEntityResolver());
File file = new File(workflowXmlFilename);
Document docWorkflow = builder.parse(file);
The above code
builder.setEntityResolver(new DTDEntityResolver());
tells the parser to use com.opensymphony.workflow.loader.DTDEntityResolver that has the special logic to reference the DTD inside the jar. Here is the relevant part of the DTDEntityResolver.java
URL url = new URL(systemId);
String file = url.getFile();

if ((file != null) && (file.indexOf('/') > -1)) {
  file = file.substring(file.lastIndexOf('/') + 1);
}
if ("www.opensymphony.com".equals(url.getHost()) && systemId.endsWith(".dtd")) {
  InputStream is = getClass().getResourceAsStream("/META-INF/" + file);

  if (is == null) {
    is = getClass().getResourceAsStream('/' + file);
  }

  if (is != null) {
    return new InputSource(is);
  }
}
You can get the source code of osworkflow-2.8.0.jar from https://maven.atlassian.com/content/repositories/atlassian-3rdparty/opensymphony/osworkflow/2.8.0/osworkflow-2.8.0-sources.jar.

Long live Open Source !!

Wednesday, May 18, 2011

PL/SQL - REST Call and XML Parsing

Looking for an example to make a REST API call in PL/SQL and parse the xml response from the call? Here is one way to do it.
DECLARE
 req     utl_http.req;
 resp    utl_http.resp;
 line    VARCHAR2(1024);
 url     VARCHAR2(1024);
 content VARCHAR2(1024);

 p       xmlparser.Parser;
 doc     xmldom.DOMDocument;
 element    xmldom.DOMElement;
 nodeList xmldom.DOMNodeList;
 node     xmldom.DOMNode;
BEGIN
 dbms_output.enable(1000000);

 url := utl_url.escape('http://host:port/app/rest/something');

 -- example xml response:
 --<?xml version="1.0" encoding="UTF-8"?><something><name>Joe</name><age>40</age></something>

 req := utl_http.begin_request(url);
 utl_http.set_header(req, 'User-Agent', 'Mozilla/4.0');
 resp := utl_http.get_response(req);
 content := '';
 BEGIN
     LOOP
       utl_http.read_line(resp, line, TRUE);
       content := content || line;
     END LOOP;
     utl_http.end_response(resp);
     EXCEPTION
         WHEN utl_http.end_of_body THEN
           utl_http.end_response(resp);
 END;

 dbms_output.put_line(content);

 p := xmlparser.newParser;
 xmlparser.setValidationMode(p, FALSE);
 xmlparser.parseBuffer(p, content);
 doc  := xmlparser.getDocument(p);

 element := xmldom.getDocumentElement(doc);

 nodeList := xmldom.getElementsByTagName(element, 'name');
 node := xmldom.item(nodeList, 0);
 node := xmldom.getFirstChild(node);
 dbms_output.put_line('name: ' || xmldom.getNodeValue(node));

 nodeList := xmldom.getElementsByTagName(element, 'age');
 node := xmldom.item(nodeList, 0);
 node := xmldom.getFirstChild(node);
 dbms_output.put_line('age: ' || xmldom.getNodeValue(node));
END;

Monday, May 16, 2011

Ever stuck in eclipse splash screen?

There have been times my Spring Source Tool Suite (based on eclipse) won't start after a crash or machine restart after automatic windows update when IDE was running. It mainly get stuck in the splash screen after selecting the workspace. One way to get the IDE started is to remove .snap file from
.metadata\.plugins\org.eclipse.core.resources
under your workspace folder and start IDE again.

Monday, March 29, 2010

JSTL madness

I was working on a Java webapp that uses JSTL v1.2 when I hit this JSTL issue. It took me some time to find a work around. Here is the issue: I had a bean that exposes a property called "name". When I tried to output name in jsp using <c:out value="${myBean.name}" /> I always get my webapp context name. Then I came across this article where I saw "The expression language unifies the treatment of dot (.) and bracket ([]) operators. Therefore, ${customer.name} is equivalent to ${customer["name"]}." I tried <c:out value="${myBean["name"]}" /> and got the correct value in jsp. Still not sure why ${myBean.name} didn't work and ${myBean["name"]} worked.

Friday, January 16, 2009

Authenticode signing of windows binary from non-windows platform

After I switched OS for my development from Windows to Mac, I always try to find options that minimize the need for starting Windows on VirtualBox. I had to use Windows for digitally signing exes and dlls. Today I found osslsigncode to sign windows binaries on non-windows platform. One less reason to boot Windows and it is much quicker than on Windows :) Here is how I did it on Mac: 1. Download source zip, unzip, compile and install osslsigncode from http://sourceforge.net/projects/osslsigncode/
cd osslsigncode-1.3 ./configure make make install
2. Generate spc and private key files in DER format from .p12 file
openssl pkcs12 -in CodeSigning.p12 -nokeys -clcerts -out CodeSigning-CL.crt.pem openssl pkcs12 -in CodeSigning.p12 -nokeys -cacerts -out CodeSigning-CA.crt.pem openssl pkcs12 -in CodeSigning.p12 -nocerts -nodes -out CodeSigning-CL.key.pem openssl crl2pkcs7 -certfile CodeSigning-CL.crt.pem -certfile CodeSigning-CA.crt.pem -nocrl -outform DER -out CodeSigning-CL.spc.der openssl rsa -in CodeSigning-CL.key.pem -outform DER -out CodeSigning-CL.key.der
3. Now sign the binary
osslsigncode -spc CodeSigning-CL.spc.der -key CodeSigning-CL.key.der -n "Description" -i "http://www.mydomain.com" -in file.dll -out signed-file.dll

Friday, April 11, 2008

Adobe AIR Application Updater Class

Adobe AIR provides the necessary APIs to implement auto-update for AIR application. You can find an as3 class here that checks for updates at an URL and trigger the application update when a new version is available.

Tuesday, April 1, 2008

as3 Password Strength Meter

I was looking for a password strength meter for my Adobe AIR application and found one written in JavaScript here. It was fairly trivial to convert it to as3. You can see as3 version of it here. Right click on the app to view source.