Skip to content

By Programmer For Programmer

Here I lay down the useful tips, tricks and utilities for programmers like myself.

Just wanted to give props real quick to the awesome profiler JProfiler (http://www.ej-technologies.com/products/jprofiler/overview.html) for providing me with an open-source license to profile my open-source project HTML4Java (https://sourceforge.net/projects/html4java/). The open-source community is so friendly :) .

Ever wanted to continue from a doubly-nested for loop? How about break from a switch statement more than one level deep?

Simple! First you have to label your loop, and then put that label name after the break or continue keyword.

“continue” example:

fooloop: for(foo: foos) {
    ...
    barloop: for(bar : bars) {
        ...
        for (blotto : blottos) {
            ...
            if (next_innermost_loop)
                continue; //normal
            if (next_middle_loop)
                continue barloop; //goes to the next iteration of "barloop"
            if (next_outer_loop)
                continue fooloop; //goes to the next iteration of the outermost loop, "fooloop"
        }
    }
}

“break” example:

fooswitch: switch(foo) {
    case 1:
        ...
        break;
    case 2:
        ...
       switch(bar) {
            ...
            if (break_this_switch)
                break; //normal
            if (break_outer_switch)
                break fooswitch; // breaks out of the out switch, "fooswitch"
        }
}

While most might consider this bad practice, when writing some scratch code to do some one-off task that only you will ever use, sometimes it’s nice to use a shortcut :) .

Every time I feel like I know all the Java syntax there is, I learn something new :)

Let’s say you have a class with a static constructor that returns a map, and that map is typed and does fancy things, but you still want to use generics from wherever you are using the Map.

public class MyClass {

    public static final <K,V> Map<K,V> createMyMap() {
        ...
        return map;
    }
}

If you are like me, you hate hate hate casting to generics, but you are forced to do that or have a big ugly @SuppressWarnings("unchecked") on the method that you access this method.

@SuppressWarnings("unchecked")
function Map<String, Object> getMyMap() {
    return MyClass.createMyMap();
}

Well not anymore!. Today I just learned (by looking through some Java source code) that you can assign generics on your static calls by using the following syntax.

function Map<String, Object> getMyMap() {
    return MyClass.<String, Object>createMyMap();
}

Just put the generics right after the period and before the method name. Easy.

I learned this while trying to figure out why java.util.Collections has static fields EMPTY_LIST, EMPTY_SET, and EMPTY_MAP, and also static methods emptyList(), emptySet, and emptyMap. It says right in the code, “Unlike this method, the field does not provide type safety”.

I was getting the annoying error in Eclipse with Tomcat where it didn’t think it could publish an application since some files were locked, when they were locked by the javaw.exe process that eclipse.exe started. The fix for me was to not have “Use Tomcat installation” selected in my server configuration. When I switched back to the default of “Use workspace metadata”, the error stopped happening.

So recently I had to build a web service, and had a really hard time finding documentation or instructions on how to make web services work in Tomcat using the web service annotations from JSR 181 (@WebService, @WebMethod, @WebParam, etc).  So I created this post as a way to help someone else in the same situation.  I’m sure there are many ways to do this, but this is one way.

My goal was to create java files annotated with web service annotations and deploy the application to Tomcat, and just have everything magically work.  I didn’t want to use the wsgen tool.  I wanted it to work like it does in JBoss, Weblogic, and Glassfish, where you just deploy the application and the web service endpoints are created automatically.

Environment

Here is the environment that I was working with:

  • Java 1.6.0_16
  • Tomcat 6.0.18
  • Eclipse 3.4
  • Building a WAR and dropping into webapps folder in Tomcat

Example Class

MyWebService.java:

package com.example.webservice;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

/**
 * An example web service implementation
 * @author Sean Adkinson
 */
@WebService(targetNamespace = "http://com.example.webservice", name = "mywebservice")
public class MyWebService
{

    /**
     * Says hello to the given name
     * @param name A name
     * @return Hello, name
     */
    @WebMethod(operationName = "hello")
    @WebResult(name = "return")
    public String hello(@WebParam(name = "name") String name)
    {
        return "Hello, " + name;
    }

}

Instructions

Follow these instructions to create a web service from our example class above:

  1. Download Metro 1.5 binary (or latest point release) at https://metro.dev.java.net/1.5/
  2. Run java -jar metro-1_5.jar to unpack the contents of the jar
  3. Take all the lib/webservices-*.jar files from the expanded Metro installation, and copy them into your web application’s WEB-INF/lib folder. Note that I chose to put these in my application’s library, but you can also put them in the server’s library at tomcat.home/lib.
  4. Create a sun-jaxws.xml file right next to web.xml under WEB-INF. This is where you specify where to find the classes that have your web service annotations. Here is a sample file:

    sun-jaxws.xml:

    <endpoints xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime' version='2.0'>
        <endpoint
            name='mywebservice'
            implementation='com.example.webservice.MyWebService'
            url-pattern='/mywebservice' />
    </endpoints>
    

    Here, name can be anything, implementation is the classpath reference to the class with the web service annotations that should have a web service created from it, and url-pattern is the path after your web application’s URL that will hit this web service (so if your application is at http://localhost:8080/MyApplication, this web service will be available at http://localhost:8080/MyApplication/mywebservice).

  5. Edit your web.xml to map the URL pattern above to class com.sun.xml.ws.transport.http.servlet.WSServlet, and add a listener for class com.sun.xml.ws.transport.http.servlet.WSServletContextListener. Here is an example:
    <listener>
        <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>myws</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>myws</servlet-name>
        <url-pattern>/mywebservice</url-pattern>
    </servlet-mapping>
    
  6. Now deploy your webapp, start Tomcat, and go to http://localhost:8080/MyApplication/mywebservice, and you should see details about the endpoint that was created, with a link to the generated WSDL file.
  7. From here you should be able point whatever client code generating utilities you have at the WSDL and talk with the web service from a client. I use built-in Eclipse Axis2 code generation for this, but check out wsimport in the Metro /bin folder for another option.

That’s it! Hope this helps someone who had as hard a time as I did with getting this working in Tomcat.

Given a class that is mapped in Hibernate, you can get the table name that it is mapped to with the following piece of code.

import org.hibernate.SessionFactory;
import org.hibernate.persister.entity.Joinable;

public String getTableName(SessionFactory sessionFactory, Class<?> mappedClass)
{
    ClassMetadata cmd = sessionFactory.getClassMetadata(mappedClass);

    //check that the class is mapped to something with a table name
    if (cmd == null || !Joinable.class.isInstance(cmd))
        return null;

    return Joinable.class.cast(cmd).getTableName();
}

Hey everyone,

I created a bash script to update an index created by SupoSE, keeping track of what revision was last successfully updated. I liked this better than their built-in scheduler because it has to continuously be running, and if for some reason our servers had to be restarted, it wouldn’t automatically start up again. Thus, I made a script to set up in cron to run hourly.

To use this script:

  • Create an index normally with SupoSE
  • Create a file to hold the last successfully indexed revision, and put this number in the file as the only text
  • Set the variables in the script below for your environment
  • Use bash 3.0 or higher, since I’m using regular expressions. If this isn’t an option, you may just need to rewrite the parsing of “svn info” to get the HEAD revision.

Enjoy!

#!/bin/sh

# Variables
SUPOSE_EXE="supose"
SUPOSE_LOC="/usr/local/supose/bin"
SVN_INDEX="/var/lib/supose/index/myindex"
SVN_URL="http://subversionurl/repo"
SVN_USER="username"
SVN_PASS="password"
LASTREV_FILE="/var/lib/supose/index/last.rev"

# Get the last successfully indexed revision
LASTREV=""
read -r LASTREV < "$LASTREV_FILE"
if [ "$LASTREV" = "" ]; then
        echo "Please specify the last successfully indexed revision in $LASTREV_FILE"
        exit 1;
fi

# Get the "to" revision
TOREV=""
SVNINFO_CMD="svn info $SVN_URL"
SVNINFO=`$SVNINFO_CMD`
if [[ "$SVNINFO" =~ 'Revision: ([0-9]+)' ]]; then
        TOREV=${BASH_REMATCH[1]}
fi
if [ "$TOREV" = "" ]; then
        echo "**** ERROR ****"
        echo "Could not read the HEAD revision number from command: $SVNINFO_CMD"
        echo "Has subversion been updated with a different format?"
        echo "Output from command:"
        echo $SVNINFO
        exit 1;
fi

# Print some output
echo "Updating subversion: $SVN_URL"
echo "Last successful revision: $LASTREV"
echo "HEAD revision: $TOREV"
echo "Index location: $SVN_INDEX"
echo "..."

if [ "$LASTREV" -ge "$TOREV" ]; then
        echo "No revisions to update... skipping process"
        exit 0;
fi

# Add one to to get the FROM revision
let FROMREV=$LASTREV+1
if [ "$FROMREV" = "" ]; then
        echo "Error adding one to last successfully indexed revision: $LASTREV"
        exit 1;
fi

# Run the SupoSE command
SUPOSE_CMD="./$SUPOSE_EXE scan \
                --url $SVN_URL \
                --username $SVN_USER \
                --password $SVN_PASS \
                --fromrev $FROMREV \
                --torev $TOREV \
                --index $SVN_INDEX"
pushd $SUPOSE_LOC
echo "Running $SUPOSE_CMD"
$SUPOSE_CMD
popd

# Was there an error running SupoSE?
SUPOSE_STATUS="$?"
if [ "$SUPOSE_STATUS" -gt "0" ]; then
        echo "**** Error ****"
        echo "$SUPOSE_EXE returned status code: $SUPOSE_STATUS (not successful)"
        echo "File $LASTREV_FILE will not be updated with latest revision"
        echo "Command that was run:"
        echo $SUPOSE_CMD
        exit $SUPOSE_STATUS;
fi

# If no error, update last.rev file
echo "**** Operation completed successfully ****"
echo "Updating $LASTREV_FILE with revision: $TOREV"
echo "$TOREV" > "$LASTREV_FILE"
exit 0