Thursday, September 19, 2013

How to use java in a standalone bash script

Bash is good for some scripting purposes and not so good for some others.

 If your skills are in java then you can use java within a script like below.

The catch is there is a small delay of a second or two for the javac (compilation) step but beyond that it works a treat.

 I found that this is great for mucking around renaming and moving files on a recent scripting task.

Wednesday, January 9, 2013

How to generate a zip file of schemas from JAXB annotated class

This utility class will zip up all the schemas generated from a JAXB annotated class. I've found it handy sometimes.
package org.moten.david.util.xml;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;

/**
 * Utility class for xml schemas.
 * 
 * @author dxm
 * 
 */
public class SchemaUtil {

 /**
  * Returns a zip file containing all schemas generated from the given class.
  * The class may or may not have xml annotations as per normal JAXB
  * marshaler creation. All non-fundamental classes referenced by the class
  * will be described in the schema as well.
  * 
  * @param os
  *            the output stream to write the zip file to
  * @param cls
  *            the class to generate the schemas from
  */
 public static void writeSchemasAsZip(OutputStream os, Class cls) {
  try {
   JAXBContext context = JAXBContext.newInstance(cls);
   Map map = new HashMap();
   SchemaOutputResolver sor = new MySchemaOutputResolver(map);
   context.generateSchema(sor);

   ZipOutputStream zip = new ZipOutputStream(os);
   for (Entry entry : map.entrySet()) {
    ZipEntry ze = new ZipEntry(entry.getKey());
    zip.putNextEntry(ze);
    zip.write(entry.getValue().toByteArray());
    zip.closeEntry();
   }
   zip.close();
  } catch (IOException e) {
   throw new RuntimeException(e);
  } catch (JAXBException e) {
   throw new RuntimeException(e);
  }
 }

 private static class MySchemaOutputResolver extends SchemaOutputResolver {

  private final Map map;

  MySchemaOutputResolver(Map map) {
   this.map = map;
  }

  @Override
  public synchronized Result createOutput(String namespaceURI,
    String suggestedFileName) throws IOException {
   System.out.println(suggestedFileName);
   File file = new File(suggestedFileName);
   ByteArrayOutputStream bytes = new ByteArrayOutputStream();
   map.put(suggestedFileName, bytes);
   StreamResult result = new StreamResult(bytes);
   result.setSystemId(file.toURI().toURL().toString());
   return result;
  }
 }
}

Monday, September 10, 2012

How to fix Nexus One sd card corruption using linux

Every now and then a forced shutdown of my Nexus One phone leaves me with a corrupted sd card. To fix this using Linux (I use Ubuntu 12.04): Connect the card using a card reader to your linux machine. Type
df
to see the device name of your sdcard. For me it is /dev/sdc1. Then
sudo umount /dev/sdc1
dosfsck -a /dev/sdc1
Job done, remove the card and try it in your phone. Note that
fsck -a /dev/sdc1
has never fixed my problem. I had to use dosfsck.

Friday, January 27, 2012

Sonar and Maven with an overriden derby port

The Sonar server uses a derby database by default that listens on port 1527. This conflicted with another process on our server so we edited the conf/sonar.properties file and set the properties sonar.jdbc.url and sonar.derby.drda.portNumber to use say 1528 instead. Uncomment the sonar.derby.drda.host parameter to allow remote connections. Restart sonar.

To run the maven sonar plugin on a project is simple, you don't even need a reference to it in the pom.xml.

mvn sonar:sonar

However, the sonar maven plugin needs to know where the server is and also the jdbc url for the server (I guess it interacts directly with the sonar database). So add two properties to your pom.xml (we added it to our parent pom.xml so all child projects would inherit it):
<properties>
  <sonar.host.url>http://YOUR_SERVER:9000</sonar.host.url>
  <sonar.jdbc.url>jdbc:derby://localhost:1528/sonar</sonar.jdbc.url> 
</properties>

Tuesday, July 19, 2011

Using scala on android with maven

If you want to deploy an application written in Scala to the android platform then use this sample project to do the whole thing using maven plugins (although you still need a separate download of the Android SDK):

svn checkout http://moten-util.googlecode.com/svn/android-scala-sample android-scala-sample

You need the ANDROID_HOME environment variable to use the maven-android-plugin. On my machine this is

ANDROID_HOME='/opt/android/android-sdk-linux_x86'

cd to the android-scala-sample directory and type

mvn clean package

This will compile and test the scala source and build an android binary using ProGuard to strip out unused classes (needed to remove the bulk of the scala dependency).

If you have the emulator running then deploy to the emulator with

mvn android:deploy

This sample app is just a hello world app for you to modify as you like.

Wednesday, December 8, 2010

Pipe to clipboard in bash on ubuntu

Say you wanted the output of a command like ls to be copied directly into the clipboard for pasting into your gui windows. Use xclip:
sudo apt-get install xclip
Then
ls | xclip -selection clipboard
will copy the output of ls into the clipboard.

I use an alias in my .bashrc for it:
alias c='xclip -selection clipboard'
So the command becomes:
ls | c

Quickly changing your .bashrc file

I use aliases all the time and am always adding more shortcuts for my terminal experience to the .bashrc file. So it's only natural that I made a convenient alias for doing exactly that.

Add this line to your .bashrc file:
alias vib='vi ~/.bashrc && source ~/.bashrc'

Then type source ~/.bashrc and the change will have been made.

So whenever you want to change your .bashrc file and have it come into effect for the current terminal:
vib
which will edit .bashrc and will run source on it automatically when you finish editing.

Sunday, October 10, 2010

Maven site and multi-module broken links on site:stage

Maven 2.2.1 default site plugin does a strange job of making parent to child links for a multimodule site report. When I have the parent reporting url set to a file:// url the links are broken after doing a site:stage. There is an easy workaround though. Make the reporting url a property in the parent pom.xml, say ${site.url} and from parent directory call

mvn clean site site:deploy -Dsite.url=file://`pwd`/target/deployed-site

This will deploy the site into target/deployed-site. Note that the url must be absolute, that's why I use `pwd` to insert the current directory (not for windoze of course). Put whatever url you like in site.url if the above does not suit.

Friday, April 16, 2010

IMDB Lookup from Nautilus in Ubuntu

This is how you implement a Lookup IMDB right click menu action for a movie file visible in Nautilus. It's really easy using Nautilus Actions!

First install nautilus-actions
sudo apt-get install nautilus-actions
Now create the script to launch the browser given a filename.
sudo wget -N -P /usr/bin http://moten-util.googlecode.com/svn/ubuntu/trunk/lookup-imdb/lookup-imdb sudo chmod 755 /usr/bin/lookup-imdb
Choose System - Preferences - Nautilus Actions Configuration - Add.
Set values in Action tab as below
Label: Lookup IMDB
Path: lookup-imdb
Parameters: %b
Logout and back in again and you should be ready to go.

Note: if you find that your default browser is not being opened by the x-www-browser command then select your default browser by
sudo update-alternatives --config x-www-browser
As of 5 May 2013 this works fine in Ubuntu 12.04 with Unity.

Friday, January 29, 2010

Guice 2.0: Mixing injected and non-injected parameters

Have been using Guice for a couple of years now after a friend at Google put me on to it. Guice 2.0 is great too, one thing it makes easier is mixing injector controlled parameters and non-injector controlled parameters into a constructor (I think constructor injection is way more solid than field/method injection when you can).

The feature is called AssistedInject, here is an example:

public class PersonLocator() {
@Inject
public PersonLocator(GeneralLocator locator, @Assisted String name) {
...
}
}

To instantiate PersonLocator using the injector you need to create a PersonLocatorFactory:

public interface PersonLocatorFactory {
PersonLocator create(String name);
}

Put a binding into the injector module:

bind(PersonLocatorFactory.class).toProvider(
FactoryProvider.newFactory(PersonLocatorFactory.class, PersonLocator.class));

Then to instantiate PersonLocator use an injected PersonLocatorFactory:

public PersonHunter {
@Inject
public PersonHunter(PersonLocatorFactory personLocatorFactory, String name){
PersonLocator personLocator = personLocatorFactory.create(name);
}
}

Thursday, September 24, 2009

Unmarshalling and validating xml without a namespace using JAXB

Unmarshalling and validating xml using jaxb where the xml does not have a namespace specified has driven me crazy for years now. I even did text insertion on the xml before unmarshalling as a workaround. Here's a good way of doing it that's great for xml without any namespace attributes (on the child elements too):

This code unmarshals the object into an org.jdom.Document object then recurses through the object setting namespaces. That object is then passed as a Source to the unmarshaller.

Note also that I did not have @XmlRootElement annotation on GCOM3DRequest so I asked the unmarshaller to unmarshal to that class explicitly.

Primary source for this was here.

package au.gov.amsa.er.nwm.scenario;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.apache.log4j.Logger;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.transform.JDOMSource;
import org.xml.sax.SAXException;

import au.gov.amsa.nwm.gcom3drequest.GCOM3DRequest;
import au.gov.amsa.nwm.gcom3drequest.ObjectFactory;

public class RequestMarshaller {

private static Logger log = Logger.getLogger(RequestMarshaller.class);
private JAXBContext jc;
private Schema schema;

public RequestMarshaller() {
try {
jc = JAXBContext.newInstance(ObjectFactory.class.getPackage()
.getName());
} catch (JAXBException e) {
throw new RuntimeException(e);
}

loadSchema();

}

private void loadSchema() {
SchemaFactory sf = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
schema = sf.newSchema(getClass().getResource(
"request/gcom3dRequest.xsd"));
} catch (SAXException e) {
throw new RuntimeException(e);
}
}

private Unmarshaller createUnmarshaller() {
Unmarshaller u;
try {
u = jc.createUnmarshaller();
// validate against the schema
u.setSchema(schema);
return u;
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}

private static Namespace DEFAULT_NS = Namespace
.getNamespace("http://www.amsa.gov.au/nwm/gcom3dRequest");

public GCOM3DRequest unmarshal(InputStream is) throws JAXBException {

try {
SAXBuilder sb = new SAXBuilder(false);
org.jdom.Document doc = sb.build(is);
setNamespace(doc.getRootElement(), DEFAULT_NS, true);

Source src = new JDOMSource(doc);
Unmarshaller u = createUnmarshaller();
u.setSchema(schema);
JAXBElement element = u.unmarshal(src,
GCOM3DRequest.class);
GCOM3DRequest gcom3d = element.getValue();
return gcom3d;
} catch (IOException e) {
throw new RuntimeException(e);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}

private static void setNamespace(Element elem, Namespace ns, boolean recurse) {
elem.setNamespace(ns);
if (recurse) {
for (Object o : elem.getChildren()) {
setNamespace((Element) o, ns, recurse);
}
}
}

public Marshaller createMarshaller() {
Marshaller m;
try {
m = jc.createMarshaller();
m.setSchema(schema);
return m;
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}

}

Monday, November 3, 2008

Create a WFS 1.1 service in java

I wanted to create an OGC Web Feature Service (version 1.1) from scratch in java. When I tried to use jdk6 xjc with the OpenGIS schemas I had lots of errors so I had to create a bindings file to resolve them. It all works fine now, here are the results of my labours:

Ant fragment:

<exec executable="${xjc}"
failonerror="true"
outputproperty="xjc.output"
errorproperty="xjc.error"
logerror="true">
<arg value="-extension">
<arg value="-verbose">
<arg value="-httpproxy">
<arg value="proxy:8080">
<arg value="-b">
<arg value="${opengis}/wfs/1.1.0/wfs-bindings.xml">
<arg value="-d">
<arg value="${generated}">
<arg value="${opengis}/wfs/1.1.0/wfs.xsd">
<arg value="${opengis}/cts/craft-feature.xsd">
<arg value="${opengis}/ows/1.0.0/owsExceptionReport.xsd">
</exec>


wfs-bindings.xml:

<bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<bindings schemaLocation="wfs.xsd" node="/xs:schema">
<globalBindings
underscoreBinding="asCharInWord"
/>
<schemaBindings>
<package name="net.opengis.schema.wfs"/>
</schemaBindings>
</bindings>
<bindings schemaLocation="../../gml/3.1.1/base/gml.xsd" node="/xs:schema">
<schemaBindings>
<package name="net.opengis.schema.gml"/>
</schemaBindings>
<bindings schemaLocation="../../gml/3.1.1/base/defaultStyle.xsd" node="/xs:schema/xs:element[@name='topologyStyle']">
<class name="topologyStyleLowerCase"/>
</bindings>
<bindings schemaLocation="../../gml/3.1.1/base/defaultStyle.xsd" node="/xs:schema/xs:element[@name='geometryStyle']">
<class name="geometryStyleLowerCase"/>
</bindings>
<bindings schemaLocation="../../gml/3.1.1/base/defaultStyle.xsd" node="/xs:schema/xs:element[@name='graphStyle']">
<class name="graphStyleLowerCase"/>
</bindings>
<bindings schemaLocation="../../gml/3.1.1/base/defaultStyle.xsd" node="/xs:schema/xs:element[@name='featureStyle']">
<class name="featureStyleLowerCase"/>
</bindings>
<bindings schemaLocation="../../gml/3.1.1/base/defaultStyle.xsd" node="/xs:schema/xs:element[@name='labelStyle']">
<class name="labelStyleLowerCase"/>
</bindings>
</bindings>
<bindings schemaLocation="../../filter/1.1.0/filter.xsd" node="/xs:schema">
<schemaBindings >
<package name="net.opengis.schema.filter" />
</schemaBindings>
</bindings>
<bindings schemaLocation="../../ows/1.0.0/owsAll.xsd" node="/xs:schema">
<schemaBindings>
<package name="net.opengis.schema.ows"/>
</schemaBindings>
</bindings>
</bindings>

Thursday, October 2, 2008

Starting a background thread in Tomcat

I have long running processes that repeatedly do something (like check a directory for new files or a database table for new records) then sleep for a while. These processes are deployed to Tomcat (giving me jsp interfaces for monitoring and any other requests).

Ideally the Tomcat container should manage this long running thread. i.e Tomcat should be aware of the background thread particularly for stopping a web application completely (stopping the background thread) but also for metrics gathering.

I implement long running threads as HttpServlets and start them in my ant build via the task which does an http get to the servlet url. We want the to return control to the build process and not wait for the long running thread to finish. The trick is to simply close the response output stream and continue. i.e.

public abstract class RunnableServlet extends HttpServlet {

private Runnable runnable;

public RunnableServlet(Runnable runnable) {
this.runnable = runnable;
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String command = req.getParameter("command");

// continue with the task but with the container aware of this thread
if ("start".equals(command)) {
response.getOutputStream().write("started");
response.getOutputStream().close();
runnable.run();
}
}
}

By the way to use the above servlet extend it!
free hit counter

Friday, August 1, 2008

Homemade Digital TV Antenna

living in O'Connor, Canberra I should get good reception from Black Mtn tower but I haven't been able to suss it for a couple of years. Reception was very patchy and for my favourite station SBS was terrible. I just couldn't get my rabbit ears to work well so I made my own antenna. I used that strip tv antenna cable that costs about a dollar per metre from Bunnings and soldered it to a coaxial end.

In detail I cut a 1.8m piece of tv antenna cable and joined the paired wires on the cable together at the ends (so I end up still a 1.8m strip but it has little u turns at the ends). Then I broke one side of the strip and twisted in a bit of copper to then solder the two ends to the coax connector (one end to the centre prong and the other to the outer ring).

Worked ok but was still having some reception problems. Luckily I stumbled upon an article that suggested you make sure there are no sharp curves in your coax cable. When I smoothed that I had flawless reception!

So the deal is you can probably make your own antenna for maybe $10 including a length of coax.

If you have rabbit ears already smooth out the run of coax, no small radius curves. Worked for me.

Friday, January 18, 2008

Start Tomcat using an Ant target

I like using a direct call to the tomcat startup class so I can avoid shell scripts:

<!-- start tomcat -->
<target name="tomcat.start">
<mkdir dir="${tomcat}/temp" />
<mkdir dir="${tomcat}/logs" />
<echo message="starting tomcat" level="info" />
<java classname="org.apache.catalina.startup.Bootstrap"
fork="true"
failonError="false"
dir="${tomcat}/bin"
spawn="true">
<classpath location="${env.JAVA_HOME}/lib/tools.jar" />
<classpath location="${tomcat}/bin/bootstrap.jar" />
<classpath location="${tomcat}/bin/commons-logging.api.jar" />
<jvmarg value="-Dprocess.name=tomcat" />
<jvmarg value="-Xmx800m" />
<jvmarg value="-XX:MaxPermSize=350m" />
<jvmarg value="-Dcom.sun.management.jmxremote.port=9003" />
<jvmarg value="-Dcom.sun.management.jmxremote.ssl=false" />
<jvmarg value="-Dcom.sun.management.jmxremote.authenticate=false" />
<jvmarg value="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" />
<jvmarg value="-Djava.util.logging.config.file=${tomcat}/conf/logging.properties" />
<jvmarg value="-Djava.endorsed.dirs=${tomcat}/endorsed" />
<jvmarg value="-Dcatalina.base=${tomcat}" />
<jvmarg value="-Dcatalina.home=${tomcat}" />
<jvmarg value="-Djava.io.tmpdir=${tomcat}/temp" />
<arg value="start" />
</java>
</target>

How to deploy a Web Service to Tomcat 5.5 or 6.0

This example uses JDK6.

Adapted from http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&f=51&t=004355:

Download the latest JAXWS Release Implementation (RI) from https://jax-ws.dev.java.net/ri-download.html. Unpack its jars as per instructions.

Tomcat 5.5
  • copy the jaxws jars to the shared/lib directory in tomcat.
  • move the jaxb-api.jar in shared/lib to common/endorsed.
  • start tomcat
Tomcat 6.0
  • create a shared directory in tomcat.
  • copy the jaxws jars to that directory.
  • create an endorsed directory in tomcat. If you are running tomcat using an ant task make sure you include the option
-Djava.endorsed.dirs=${catalina}/endorsed
  • Move jaxb-api.jar from shared to endorsed.
  • Edit conf/catalina.properties and set the shared.loader property as follows:
shared.loader=${catalina.home}/shared/*.jar
War

In the war, we update the web.xml to use a special listener that enables the web service. The web.xml should look like this:
    <listener>  
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>MyExampleService</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyExampleService</servlet-name>
<url-pattern>/example</url-pattern>
</servlet-mapping>
Create a sun-jaxws.xml file in WEB-INF directory which the listener uses to configure itself with the web service you want to expose:
    <endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
<endpoint name="MyExampleService" implementation="moten.david.example.ws.MyExample" pattern="/example"/>
</endpoints>
After starting tomcat you can access the service by:

http://localhost:8080/{war-name}/example

Tuesday, December 18, 2007

Simple authentication over https with invalid certificate

Here's the story for opening an input stream on a url via https when the site has an invalid certificate (e.g. expired). You could place the certificate in your trusted store but this is a useful shortcut!

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class SSL {

public static class SimpleAuthenticator extends Authenticator {
private final String username, password;

public SimpleAuthenticator(String username, String password) {
this.username = username;
this.password = password;
}

@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
}

public static void main(String[] args) throws IOException,
NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSL");
TrustManager trustManager = new X509TrustManager() {

@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// don't throw exception
}

@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
// don't throw exception
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}

};
sc.init(null, new TrustManager[] { trustManager },
new java.security.SecureRandom());

HostnameVerifier hostNameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
};
java.net.URL url = new URL("https://hostname/stuff");
Authenticator.setDefault(new SimpleAuthenticator("username", "password"));
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setHostnameVerifier(hostNameVerifier);
con.setSSLSocketFactory(sc.getSocketFactory());

InputStream is = con.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
isr.close();
is.close();

}

}

Thursday, November 29, 2007

XML Schemas - Best Practices to Manage Change

I create xml schemas based on my experience processing them in an automated fashion. Here are some pointers that make things easy for an automated xml consumer and also allow more robust management of (inevitable) schema changes:

When you write code to process xml based on a schema, use objects generated from the schema. This gives you protection from schema change in as much as a change in the schema and a rebuild of your code (including the code generation of course) will then indicate needed changes in your code with compile errors. This is a tremendous help, wherever possible look for compile time indication of errors rather than runtime errors after deployment!

For Java JDK 6 use the xjc tool to generate classes from a schema. Script it up say in Ant as part of your project build.

Designing an xml schema is like designing a relational database, and involves elements of object oriented design. Know these things before embarking on schema design!

Reuse types, both simple and complex. That way when you write code with generated objects you will be able to resuse code working on particular types.

Give maximum size limits to your data types, then when you design database fields to capture this information, provide bigger database field sizes than you initially need to accomodate change (e.g. put 50 chars down as a limit for a surname in the schema but use 100 chars in the database field). Remember, disk space is cheap having the same data in a varchar(100) won't take up more space than in a varchar(50). Somewhat larger field size limits won't slow your database down either.

Use lower case hyphenated element names (<start-time>) or upper camel case (<StartTime>) in the xml. Hyphenated names are still translated into object properties like "startTime" by tools such as xjc.

If an xml element has an associated unit, include the unit in the element name (either the SI unit abbreviation, or spell it out, e.g length-feet, mass-pounds). i.e rather than <time>54</time> use <time-ms>54</time-ms> or <time-milliseconds>54</time-milliseconds>. That way when someone produces xml using generated objects they will always know how to scale the value for the required unit (without having to check documentation for the field).

Thursday, November 8, 2007

oracle sqlplus ant task

Having used oracle and java for yonks I thought I'd improve my toolset a bit with this ant task. It's pretty useful especially as it detects errors in the running of the script and can optionally fail.

This ant task provides all the options available for the sqlplus exe (and a few more).

Note that the end of your script needs an exit, otherwise the task just hangs around.

<target name="run.sqlplus">
<taskdef name="sqlplus" classname="moten.david.util.database.oracle.SqlPlusTask" classpathref="libraries" />
<sqlplus logon="scott/tiger@orcl" failonerror="false">
<sql>
update document set folder_id = 14
where document_id in (
select document_id
from message_details
where message_id in
(5204249,5204257,5204258,5204260,5204273,5204274,
5204280,5204287,5204288,5204290,5204291,5204297)
);

update message_details
set sent_received_dtg=sysdate
where message_id in
(5204249,5204257,5204258,5204260,5204273,5204274,
5204280,5204287,5204288,5204290,5204291,5204297);

commit;

exit;
</sql>
</sqlplus>
</target>


Download the jar and source from moten-util

Tuesday, November 6, 2007

oracle loadjava ant task

Created an ant task to perform loadjava for oracle 10g and later. Works nicely for me. See moten-util for the jar and source code.

<taskdef name="loadjava" classname="moten.david.util.database.oracle.LoadJavaTask" classpathref="libraries" />
<loadjava failonerror="true" resolve="false"
force="false" showchangesonly="false" showlog="true"
thin="true" user="scott/tiger@dbhost:1521:orcl">
<path>
<fileset dir="${lib}/axis1.4">
<include name="*.jar" />
<include name="log4j.properties" />
</fileset>
</path>
</loadjava>
Note that classpathref="libraries" assumes you have defined the class below in the classpathref "libraries". You can just use an embedded classpath element inside the taskdef to point to it (see the ant manual for details or use eclipse for autocomplete).

The java class:
package moten.david.util.database.oracle;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.Path;

public class LoadJavaTask extends Task {
private boolean failOnError = true;
private boolean showLog = true;
private boolean showChangesOnly = true;
private boolean definer = false;
private String user;
private boolean thin = true;
private boolean resolve = true;
private boolean verbose = false;
private boolean force = false;
private boolean oci8 = false;
private boolean showHelp = false;
private List paths = new ArrayList();
private String encoding;
private boolean genmissing = false;
private String genmissingjar;
private String grants;
private boolean nousage = false;
private boolean help = false;
private boolean noverify = false;
private boolean order = false;
private String resolver;
private String schema;
private boolean synonym = false;
private String tableschema;

@Override
public void execute() throws BuildException {
log("executing");
super.execute();
ArrayList args = new ArrayList();
if (failOnError)
args.add("-failOnError");
if (showLog)
args.add("-showLog");
if (showChangesOnly)
args.add("-showChangesOnly");
if (showHelp)
args.add("-showHelp");
if (definer)
args.add("-definer");
if (encoding != null)
args.add("-encoding " + encoding);
if (force)
args.add("-force");
if (genmissing)
args.add("-genmissing");
if (genmissingjar != null) {
args.add("-genmissingjar");
args.add(genmissingjar);
}
if (grants != null) {
args.add("-grant");
args.add(grants);
}
if (help)
args.add("-help");
if (nousage)
args.add("-nousage");
if (noverify)
args.add("-noverify");
if (oci8)
args.add("-oci8");
if (order)
args.add("-order");
if (resolve)
args.add("-resolve");
if (resolver != null) {
args.add("-resolver");
args.add(resolver);
}
if (schema != null) {
args.add("-schema");
args.add(schema);
}
if (synonym)
args.add("-synonym");
if (thin)
args.add("-thin");
if (tableschema != null) {
args.add("-tableschema");
args.add(tableschema);
}
if (user != null) {
args.add("-user");
args.add(user);
}
if (verbose)
args.add("-verbose");
for (Iterator itPaths = paths.iterator(); itPaths.hasNext();) {
Path path = itPaths.next();
String[] includedFiles = path.list();
for (int i = 0; i < includedFiles.length; i++) {
args.add(includedFiles[i]);
}
}
log(args+"");
String[] arguments = args.toArray(new String[] {});
try {
Deployer.main(arguments);
} catch (IOException e) {
throw new BuildException(e);
}
}

public List getPaths() {
return paths;
}

public void setPaths(List paths) {
this.paths = paths;
}

public String getEncoding() {
return encoding;
}

public void setEncoding(String encoding) {
this.encoding = encoding;
}

public boolean isGenMissing() {
return genmissing;
}

public void setGenMissing(boolean genMissing) {
this.genmissing = genMissing;
}

public String getGenMissingJar() {
return genmissingjar;
}

public void setGenMissingJar(String genMissingJar) {
this.genmissingjar = genMissingJar;
}

public String getGrant() {
return grants;
}

public void setGrant(String grant) {
this.grants = grant;
}

public boolean isNousage() {
return nousage;
}

public void setNousage(boolean nousage) {
this.nousage = nousage;
}

public boolean isHelp() {
return help;
}

public void setHelp(boolean help) {
this.help = help;
}

public boolean isNoverify() {
return noverify;
}

public void setNoverify(boolean noverify) {
this.noverify = noverify;
}

public boolean isOrder() {
return order;
}

public void setOrder(boolean order) {
this.order = order;
}

public String getResolver() {
return resolver;
}

public void setResolver(String resolver) {
this.resolver = resolver;
}

public String getSchema() {
return schema;
}

public void setSchema(String schema) {
this.schema = schema;
}

public boolean isSynonym() {
return synonym;
}

public void setSynonym(boolean synonym) {
this.synonym = synonym;
}

public String getTableschema() {
return tableschema;
}

public void setTableschema(String tableschema) {
this.tableschema = tableschema;
}

public LoadJavaTask() {
// do nothing
}

public void addPath(Path path) {
paths.add(path);
}

public boolean isFailOnError() {
return failOnError;
}

public void setFailOnError(boolean failOnError) {
this.failOnError = failOnError;
}

public boolean isShowLog() {
return showLog;
}

public void setShowLog(boolean showLog) {
this.showLog = showLog;
}

public boolean isShowChangesOnly() {
return showChangesOnly;
}

public void setShowChangesOnly(boolean showChangesOnly) {
this.showChangesOnly = showChangesOnly;
}

public String getUser() {
return user;
}

public void setUser(String user) {
this.user = user;
}

public boolean isThin() {
return thin;
}

public void setThin(boolean thin) {
this.thin = thin;
}

public boolean isResolve() {
return resolve;
}

public void setResolve(boolean resolve) {
this.resolve = resolve;
}

public boolean isVerbose() {
return verbose;
}

public void setVerbose(boolean verbose) {
this.verbose = verbose;
}

public boolean isForce() {
return force;
}

public void setForce(boolean force) {
this.force = force;
}

public boolean isOci8() {
return oci8;
}

public void setOci8(boolean oci8) {
this.oci8 = oci8;
}

public boolean isShowHelp() {
return showHelp;
}

public void setShowHelp(boolean showHelp) {
this.showHelp = showHelp;
}

public boolean isDefiner() {
return definer;
}

public void setDefiner(boolean definer) {
this.definer = definer;
}

}

Here's the Deployer class:



package moten.david.util.database.oracle;

/*
* Created on 14/12/2005
*
* Author: DMoten
*/

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.InetAddress;
import java.security.Permission;

import oracle.aurora.server.tools.loadjava.LoadJavaMain;

public class Deployer {

/**
* Runs oracle.aurora.server.tools.loadjava.LoadJavaMain with args and
* appends output to file deployer.log. If the option -failOnError is
* included in the arguments then an Error will be thrown if the word
* 'errors' exists in the output from LoadJavaMain. If the option -showLog
* is included then -verbose info will be output (i.e. info for each class
* being loaded). The log is always shown if an error occurrs or even if a
* System.exit is called (the SecurityManager is overriden).
*
* Note that the LoadJavaMain method hangs if the login is incorrect. Watch
* out for that one!
*
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {

if (args != null && args.length > 0) {
System.out.println("Deploying " + args[args.length - 1]);
}
final PrintStream stdOut = System.out;
final PrintStream stdErr = System.err;
boolean errorOccurred = false;
MainParameters params = new MainParameters(args);
boolean failOnError = params.optionExists("-failOnError");
final boolean showLog = params.optionExists("-showLog");
final boolean showChangesOnly = params.optionExists("-showChangesOnly");
boolean showHelp = params.optionExists("-showHelp");
boolean logToFile = params.optionExists("-logToFile");
args = params.removeOption("-failOnError");
args = params.removeOption("-showLog");
args = params.removeOption("-showChangesOnly");
args = params.removeOption("-showHelp");
args = params.removeOption("-logToFile");
final ByteArrayOutputStream logBytes = new ByteArrayOutputStream() {
@Override
public synchronized void write(int b) {
super.write(b);
if (showLog)
stdOut.append((char) b);
}
};
final PrintStream myOut = new PrintStream(logBytes);
System.setOut(myOut);
System.setErr(myOut);

final SecurityManager sm = System.getSecurityManager();

System.setSecurityManager(new SecurityManager() {
@Override
public void checkAccept(String host, int port) {
// ok
}

@Override
public void checkAccess(Thread t) {
// ok
}

@Override
public void checkAccess(ThreadGroup g) {
// ok
}

@Override
public void checkAwtEventQueueAccess() {
// ok
}

@Override
public void checkConnect(String host, int port, Object context) { // ok
}

@Override
public void checkConnect(String host, int port) { // ok
}

@Override
public void checkCreateClassLoader() { // ok
}

@Override
public void checkDelete(String file) { // ok
}

@Override
public void checkExec(String cmd) { // ok
}

@Override
public void checkLink(String lib) { // ok
}

@Override
public void checkListen(int port) { // ok
}

@Override
public void checkMemberAccess(Class arg0, int arg1) { // ok
}

@Override
public void checkMulticast(InetAddress maddr) { // ok
}

@Override
public void checkPackageAccess(String pkg) { // ok
}

@Override
public void checkPackageDefinition(String pkg) { // ok
}

@Override
public void checkPermission(Permission perm, Object context) { // ok
}

@Override
public void checkPrintJobAccess() { // ok
}

@Override
public void checkPropertyAccess(String key) { // ok
}

@Override
public void checkRead(FileDescriptor fd) { // ok
}

@Override
public void checkRead(String file, Object context) { // ok
}

@Override
public void checkRead(String file) { // ok
}

@Override
public void checkSecurityAccess(String target) {// ok
}

@Override
public void checkSetFactory() {// ok
}

@Override
public void checkSystemClipboardAccess() {// ok
}

@Override
public boolean checkTopLevelWindow(Object window) {// ok
return sm.checkTopLevelWindow(window);
}

@Override
public void checkWrite(FileDescriptor fd) {// ok
}

@Override
public void checkWrite(String file) {// ok
}

@Override
public void checkPermission(Permission perm) {// ok
// sm.checkPermission(perm);
}

@Override
public void checkExit(int status) {
if (status != 0) {
myOut.close();
stdOut.println(logBytes.toString());
}
sm.checkExit(status);
}

@Override
public void checkPropertiesAccess() {
super.checkPropertiesAccess();
}
});

if (showHelp)
LoadJavaMain.main(new String[] { "-help" });

try {
StringBuffer s = new StringBuffer();
for (String element : args) {
s.append(" '" + element + "'");
}
myOut.println("running LoadJavaMain class with args: "
+ s.toString());
LoadJavaMain.main(args);
} catch (Error e) {
e.printStackTrace();
errorOccurred = true;
}
myOut.close();
errorOccurred = errorOccurred
|| logBytes.toString().indexOf("errors :") > 0;
FileOutputStream fos = null;
if (logToFile)
fos = new FileOutputStream(new File("deployJava.log"));
String log;
if (showChangesOnly) {
StringBuffer b = new StringBuffer(logBytes.toString());
while (b.toString().indexOf("identical:") >= 0) {
int startIndex = b.toString().indexOf("identical:");
int endIndex = b.toString().indexOf("\n", startIndex);
b.delete(startIndex, endIndex);
}
while (b.toString().indexOf("skipping :") >= 0) {
int startIndex = b.toString().indexOf("skipping :");
int endIndex = b.toString().indexOf("\n", startIndex);
b.delete(startIndex, endIndex);
}
log = b.toString();
} else
log = logBytes.toString();

if (logToFile) {
fos.write(log.getBytes());
if (errorOccurred) {
String msg = "\nErrors Occurred!";
fos.write(msg.getBytes());
stdOut.write(msg.getBytes());
}
fos.close();
}
System.setOut(stdOut);
System.setErr(stdErr);
if (failOnError) {
if (errorOccurred) {
if (!showLog)
System.out.println(log);
throw new DeployerError(
"deployment failed due to error appearing in ");
}
}
}
}

class DeployerError extends Error {

private static final long serialVersionUID = 1809358860733551336L;

public DeployerError(String msg) {
super(msg);
}
}


MainParameters class:



package au.gov.amsa.util.database.oracle;

/*
* Created on 13/01/2006
*
* Author: DMoten
*/

import java.util.ArrayList;

public class MainParameters {

String[] args;

public MainParameters(String[] args) {
this.args = args;
}

public boolean optionExists(String option) {
boolean found = false;
for (int i = 0; i < args.length; i++) {
found = found || args[i].equalsIgnoreCase(option);
}
return found;
}

public String[] removeOption(String option) {
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < args.length; i++) {
if (!args[i].equalsIgnoreCase(option)) {
list.add(args[i]);
}
}
String[] argsNew = new String[list.size()];
for (int i = 0;i<argsNew.length;i++) {
argsNew[i]=(String) list.get(i);
}
this.args = argsNew;
return args;
}

@Override
public String toString() {
StringBuffer s = new StringBuffer();
for (int i=0;i<args.length;i++) {
s.append(args[i]+"\n");
}
return s.toString();
}

public static void main(String[] args) {
args = new String[] {"a","b","c"};
MainParameters m = new MainParameters(args);
m.removeOption("b");
}
}


free hit counter