Archive

Posts Tagged ‘Java’

JAutodoc

January 5, 2011 1 comment

Things on my project have quieted down a bit, so I’m trying to get done some of the nice touches that I don’t usually have time to do. Because my module is brand new, it’s completely doable to make the inline documentation really spiffy. I want to do all the stuff to make the Javadoc look just right.

One of those things is to do package javadoc. You used to do that with a package.html file, but as of Java 5 they want you to create a package-info.java file instead. You can read all about it at http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html

Because I use Eclipse, I figured there’d be some buried menu command to generate this stuff, but surprisingly there wasn’t. I did, however, find an Eclipse plugin called JAutodoc to do this for me.

Great! Except the plugin installation failed. The installation exception message mentioned a missing module, org.eclipse.team.cvs.ssh. Eclipse 3.6 Helios comes with the org.eclipse.team.cvs.ssh2 plugin, but for some reason they did not include org.eclipse.team.cvs.ssh.

I couldn’t find a site to download just that (54k) plugin jar file, but I did discover that Eclipse 3.5 Galileo did include it. So I moved that jar from my Galileo Eclipse installation to the Helios installation, retried the JAutodoc install, and everything works.

So if you want to be fussy about your Javadocs in Eclipse, check out JAutodoc, and if you have trouble installing it, this could be your solution!

Advertisements
Categories: code Tags: , ,

XOP Converter

December 18, 2010 2 comments

My most recent task at work involves XOP, or XML-binary Optimized Packaging. Basically, if you have an XML document that needs to have binary data in it, like images, you have two ways of doing it. You can base64 encode the data and put it directly in an XML element, or you can use XOP to keep the data in binary form and attach the file to the message using MIME. XOP is usually used to represent SOAP messages with MTOM (Message Transmission Optimization Mechanism).

My app uses JiBX to convert my Java objects into XML documents, and base64 encodes them. But I got a new requirement to also support XOP encoding. So to minimize impact on the app, I decided to write a converter that would take in a XML document with base64 encoded data and spit out a properly encoded XOP document. Then it would also be useful to convert existing documents and creating new ones. The module that helped me do this was Apache Axiom, a component of the Apache Axis2 web services engine.

The main problem with Axiom is its poor documentation. Almost all of the docs I could find about Axiom and Axis2 were from a server-side perspective, and I am writing a client-side app. So I thought I’d share the bit of code I wrote to do this conversion.

public class XOPConverter {

    @SuppressWarnings("rawtypes")
    public static void convertToXOP(String xml, OutputStream os) 
        throws XMLStreamException, JaxenException, JiBXException, IOException {

        // set up all the AXIOM objects
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader parser = factory.createXMLStreamReader(new StringReader(xml));
        StAXOMBuilder builder = new StAXOMBuilder(parser);
        OMDocument document = builder.getDocument();
        OMElement documentElement =  builder.getDocumentElement();
        OMFactory fac = OMAbstractFactory.getOMFactory();
        
        // find all the BinaryBase64Object nodes
        AXIOMXPath xpathExpression = new AXIOMXPath("//niem-nc:BinaryBase64Object");
        xpathExpression.addNamespace("niem-nc", "http://niem.gov/niem/niem-core/2.0");
        List nodeList = xpathExpression.selectNodes(documentElement);
        
        for (Iterator i = nodeList.iterator(); i.hasNext(); ) {
            Object obj = i.next();
            if (!(obj instanceof OMElement)) {
                continue;
            }
            OMElement element = (OMElement)obj;
            // get bytes data out of that node
            String base64data = element.getText();
            // decode base 64 encoding
            byte[] data = Base64Serializer.deserializeBase64(base64data);
            // create ByteArrayDataSource
            ByteArrayDataSource ds = new ByteArrayDataSource(data);
            // set the MIME type
            ds.setType("image/" + XOPConverter.getMIMEType(data));
            // create OMText object
            OMText textElement = fac.createOMText(new DataHandler(ds), true);
            // replace BinaryBase64Object node text with OMText object
            element.setText("");
            element.addChild(textElement);
        }
        
        // do the XOP conversion
        OMOutputFormat format = new OMOutputFormat();
        format.setDoOptimize(true);
        format.setMimeBoundary("MIME");
        format.setContentType("Multipart/Related");
        MTOMXMLStreamWriter mtomWriter = new MTOMXMLStreamWriter(os, format);
        mtomWriter.setDoOptimize(true);
        document.serializeAndConsume(mtomWriter);
        document.close(false);
    }
    
    /**
     * @param args
     * @throws IOException 
     * @throws XMLStreamException 
     * @throws JaxenException 
     * @throws JiBXException 
     */
    public static void main(String[] args) 
        throws IOException, XMLStreamException, JaxenException, JiBXException {
        
        if (args.length == 0) {
            System.out.println("Usage: <filename>");
            return;
        }
        String inputFileName = args[0];
        String outputFileName = inputFileName.substring(0, 
                inputFileName.lastIndexOf(".")) + ".xop";
        boolean overwrite = false;
        if (args.length > 1) {
            String overwriteStr = args[1];
            overwrite = Boolean.parseBoolean(overwriteStr);
        }
        // check if output file exists
        if (new java.io.File(outputFileName).exists() && !overwrite) {
            System.out.println("ERROR: Output file " + outputFileName + 
                    " exists, please move it.");
            return;
        }
        
        java.io.BufferedReader reader = 
            new java.io.BufferedReader(new java.io.FileReader(args[0]));
        String line = null;
        StringBuilder stringBuilder = new StringBuilder();
        String ls = System.getProperty("line.separator");
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(ls);
        }
        String xml = stringBuilder.toString();
        
        FileOutputStream os = new FileOutputStream(outputFileName);
        convertToXOP(xml, os);
        System.out.println("done");
    }
}

Now I’ll step through the code and explain it a bit.

The convertToXOP method takes the XML text as a String, and an OutputStream where the XOP is written. In my original document, all the base64 encoded objects I need to extract and attach are in elements labeled . So I cook up an XPath expression to find all those elements for processing. The code gets the data out of the element and un-base64 encodes it. I didn’t write that code, so you’ll have to do that yourself. Then we put the byte array in a ByteArrayDataSource and tag it with the MIME type we want to use. In a later post I’ll show how to figure out what encoding an image uses. Then use the OMFactory to create a new OMText element containing the byte array and set it to be optimized. Add it to the original element and reset its text, clearing out the base64 encoded data.

The key to doing the conversion is Axiom’s MTOMXMLStreamWriter class. You send the MTOMXMLStreamWriter the OutputStream where you want the XOP document to go, and an OMOutputFormat object. Setting the doOptimize flag on the OMOutputFormat object enables the optimization step that moves the binary objects to MIME attachments. Sending the MTOMXMLStreamWriter to the OMDocument’s serializeAndConsume method writes the XOP output.

I hope this code and explanation has been helpful to you.

Categories: code Tags: , ,

Links

December 12, 2010 Leave a comment

I wanted to share some links to some cool stuff I’ve found recently.

PragPub
This is a free monthly magazine by the folks to publish the Pragmatic Programmers series of books. They release the issues in pdf, epub and mobi formats in addition to HTML on the site. Lots of great stuff to load onto your ereader.

JAXenter
This site is a hub for software news. There’s a lot of press releases for Apache projects you’ve never heard of, but there’s also some Q&A with project managers and commentary on the goings on with Oracle and whatnot. Add the RSS feed to your feed reader and subscribe to their free occasional PDF magazine JAXmag.

The Java Posse
This is a group of four high-level developers who do a semi-regular podcast discussing Java. It can get really annoying when they talk over each other, and the episodes sometimes approach two rambling hours in length, but they are really smart and well-connected guys who are usually worth listening to.

Categories: miscellaneous Tags: , ,

Local Variables

November 3, 2010 Leave a comment

A few years ago a colleague criticized some code I wrote for local variable inefficiency. Here’s an example of what he did not like:

for (int i = 0; i < 10; i++)
{
	String s = String.valueOf(i);
}

He said that Java allocated 10 Strings when that code ran. A better way was this:

String s;
for (int i = 0; i < 10; i++)
{
	s = String.valueOf(i);
}

So that’s the way I’ve been writing Java code for years now, thinking I am being super efficient.

Well, joke’s on me. Today I found this blog post and learned that his assumption is completely incorrect. The first way above is better because it makes the code more readable and prevents possible variable scoping problems.

Categories: code Tags:

keytool

October 28, 2010 Leave a comment

My most recent project, the Multimodal Operational Test Harness (OTH), is a thick Java Swing client used to gather biometrics and package them up into a properly formatted XML document. The Maven 2 build generates an uber jar including all the dependencies that can be run from the command line, but we also have a requirement to run as a WebStart application. It’s not generally required to digitally sign the software, but we have the requirement locally.

So here’s how I went about signing the OTH.

1) Generate the key pair and self-signed certificate.
I could have used the command line for this step, but instead I decided to use the Maven Keytool plugin.
Here’s a clip of the pom.xml file I created:

<pluginManagement>
	<plugins>
		<plugin>
			<groupId>org.codehaus.mojo</groupId>
			<artifactId>keytool-maven-plugin</artifactId>
			<executions>
				<execution>
					<phase>generate-resources</phase>
					<id>clean</id>
					<goals>
						<goal>clean</goal>
					</goals>
				</execution>
				<execution>
					<phase>generate-resources</phase>
					<id>genkey</id>
					<goals>
						<goal>genkey</goal>
					</goals>
				</execution>
			</executions>
			<configuration>
				<keystore>keystore.jks</keystore>
				<dname>cn=commonName, ou=organizationUnit, o=organizationName, c=countryCode</dname>
				<keypass>password</keypass>
				<storepass>password</storepass>
				<alias>OTH</alias>
				<keyalg>RSA</keyalg>
				<keysize>2048</keysize>
				<validity>3650</validity>
			</configuration>
		</plugin>
	</plugins>
</pluginManagement>

I know it’s not the best idea to put the passwords in the pom.xml file, but the security of this keystore isn’t very important and I wanted to allow other developers to access the keystore without needing to discover the password.

Take special note of the option. If you don’t specify this value, the default is only 90 days. 10 years is much better.

2) Instead of just relying on a self-signed certificate, I need to get my certificate signed by a Certificate Authority. To do that, I generate a certificate signing request (CSR) file.

keytool -certreq -alias oth -file oth.csr -keystore keystore.jks -v

3) I sent that through our security team to our Certificate Authority. They first sent me their root certificates. These have to be imported into our keystore before we can authtenticate the certificate reply.

keytool -importcert -file "rootcert.crt" -alias rootcert -trustcacerts -keystore keystore.jks -v

4) Then I receive my certificate reply from the certificate authority. Now I can import that into my keystore and my certificate is authenticated.

keytool -importcert -file "cert.txt" -trustcacerts -keystore keystore.jks -v

5) You can verify the contents of your keystore by running the following command:

keytool -list -keystore keystore.jks -v

6) Here’s the bit of Maven WebStart plugin configuration that uses the keystore to sign the war.

<plugin>
	<groupId>org.codehaus.mojo.webstart</groupId>
	<artifactId>webstart-maven-plugin</artifactId>
	<version>1.0-beta-1</version>
	<executions>
		<execution>
			<phase>compile</phase>
			<goals>
				<goal>jnlp-download-servlet</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<outputDirectory>src/webapp</outputDirectory>
		<excludeTransitive>true</excludeTransitive>
		<jnlpFiles>
			<jnlpFile>
				<templateFilename>jnlp_launch_template.vm</templateFilename>
				<outputFilename>oth.jnlp</outputFilename>
				<jarResources>
					<jarResource>
						<groupId>videology</groupId>
						<artifactId>videology-driver</artifactId>
						<version>1.0.0</version>
						<classifier>win32</classifier>
					</jarResource>
					...
				</jarResources>
			</jnlpFile>
		</jnlpFiles>
		<sign>
			<keystore>${project.basedir}/keystore.jks</keystore>
			<keypass>password</keypass>
			<storepass>password</storepass>
			<alias>OTH</alias>
			<verify>true</verify> <!-- verify that the signing operation succeeded -->
		</sign>
		<!-- BUILDING PROCESS -->
		<pack200>false</pack200>
		<gzip>false</gzip>
		<verbose>true</verbose>
		<outputJarVersions>true</outputJarVersions>
	</configuration>
</plugin>

Finally, here’s the URL of the documentation of the Java keytool tool.
http://download.oracle.com/javase/6/docs/technotes/tools/windows

Categories: code Tags: ,