Wednesday, December 9, 2009

Object instantiation with JSTL and JSP

Have you ever wanted to instantiate an object and use them in your JSTL expressions? In my case, I wanted to surround an object with a wrapper class that provided extra functionality to the objected being wrapped, and be able to access the wrapped object from within JSTL expressions.

To do this I used a combination of JSP and JSTL. I used JSP tags to instantiate the wrapper class and JSTL to assign the object being wrapped as follows:


                <jsp:useBean id="strainWrapper" class="au.edu.apf.phenomebank.strain.StrainHelperWrapper" />                    
                <c:set target="${strainWrapper}" property="strain" value="${mouse.strain}" />
                
                ${strainWrapper.genotypingAssays}




public class StrainHelperWrapper {

    private Strain strain; 
    
    public StrainHelperWrapper() {}
    
    public StrainHelperWrapper(Strain strain) {
        this.strain = strain;
    }
    
    public Strain getStrain() {
        return strain;
    }
    public void setStrain(Strain strain) {
        this.strain = strain;
    }

    
    
    /**
     * Returns a list of Amplifluor requirements for the Genotyping Assays
     * @return
     */
    public String getAmplifluors() {
        StringBuilder sb = new StringBuilder();
        
        if (strain != null) {
            List<Genotype> genotyping = strain.getGenotypes();
            if (genotyping != null) {
                int counter = 0;
                for (Genotype genotype: genotyping) {
                    if (counter > 0)
                        sb.append(", ");
                    String yesNo = genotype.getAmplifluor() ? "Yes" : "No";
                    sb.append(yesNo);
                    counter++;
                }                
            }
        }
        return sb.toString();
        
        
    }

Sunday, December 6, 2009

Hibernate: Deleting element from a Collection doesn't get deleted in database

In Hibernate we are able to remove an element from a java.util.Collection by invoking Iterator.remove() on the Iterator object. When the collection is saved, Hibernate will automatically delete the element that was removed from the database. Below is an example of removing the element from the Collection:

            for (Iterator<StoragePosition> it = mouse.getPositions().iterator(); it.hasNext() ;) {
                StoragePosition sp = it.next();
                
                if (! Util.isValid(sp.getPosition())) {        
                    it.remove();
                }
            }

The "cascade" attribute configured in the Hibernate configuration file (hbm.xml) plays an important role in how it will behave when handling elements that have been removed from a Collection. In order for this to work the cascade attribute should have the following value: all-delete-orphan. A cascade value of save-update will not work. Below is a segment of the configuration file:


    <set name="positions" inverse="true" table="mouse_storage_positions" cascade="all-delete-orphan" lazy="true" batch-size="8">
             <key column="mouse_id" />                      
             <one-to-many class="au.edu.apf.phenomebank.inventory.StoragePosition" />     
         </set>    

Thursday, November 26, 2009

Tomcat PermGenSpace on several redeployments

The PermGenSpace bug has been an issue for a long time. Several people have diagnosed this bug in ClassLoader of the JVM and there are several posts which can easily be searched on google.

This issue typically occurs after several reployments to Tomcat. However there are ways to relieve or extend the number of redeployments you can do without having to do full Tomcat restart everytime. You can add the following options to your JAVA_OPTS environment variable in the catalina.bat or catalina.sh file in the bin folder of tomcat:

-Xmx768m -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m

Windows 7 as a Java, Tomcat, Postgres developer

I've been given a new computer at work on the (ANU campus) just yesterday and it came preinstalled with the new Windows 7. I've been told I am probably the first person at the college to be using Windows 7 so I almost felt like a guinea pig and seeing if it has any compatibility issues especially for my development environment. But after spending some time on it, I can tell you it really wasn't that painful to make the transition.

Java 6

Since I was running a 64 bit machine I needed to download the Windows x64 option when loading from the sun webite:

Download Java 6

Eclipse

Since I was running the 64bit version of Java, I needed to download the 64bit version of eclipse for Windows. I had downloaded version 3.5.1

Eclipse Download page

The direct download for the 64 bit version on windows is here
Direct eclipse download 64bit Windows

The eclipse that was downloaded was not the Java EE bundle. So it was missing a lot of the functionality that I was used to such as HTML editors, JSP editors etc.... To download the plugins for that kind of support,
In Eclipse goto: Help - Install new software
and supply the following URL: http://download.eclipse.org/releases/galileo
Then select the "Web, XML and Java EE Development" package.
Now eclipse is ready to go.

Postgres

Initially I attempted to install the latest Postgres binary Version 8.4 for windows and it immediately came back with an installation error. I followed up on some forums and many others had encountered similar issues. I was told that people had better luck with version 8.3 which I downloaded from here:

Download postgres 8.3

In the default installation I still encountered some errors. In this case, it complained something about a 'Secondary Logon service'. To enable this service I did the following:

I went to the 'Services' windows doing the following: Start - Control Panel - System and Security - Administrative tools - Services


In the services window, search for the 'Secondary Logon service' and enable it.





 I also disabled User Access control (UAC) which seemed to cause problems for other people by following the steps outlined here

Once the above steps were completed I was able to continue with the normal installation procedure for Postgres 8.3.

Wednesday, November 18, 2009

JSTL test condition and trailing spaces

Took me a few minutes to track this one down, but it did catch me by surprise. The trailing spaces in the test conditions for JSTL tags do make a difference. For those that are interested I was using Tomcat 6.

I was getting the following errors in my stacktrace:


An error occurred at line: 40 in the jsp file: /WEB-INF/jsp/genotypingInventory.jsp
The method setTest(boolean) in the type IfTag is not applicable for the arguments (String)
37:                     <td class="right-col">${sp.box.box }</td>
38:                     <td class="right-col">${sp.position }</td>
39:                     <td class="right-col">
40:                             <c:if test="${not empty sp.mouse.strain} ">
41:
42:                             </c:if>
43:                     </td>      


The error was in the line:


<c:if test="${not empty sp.mouse.strain} ">


The problem is the extra space after the end curly bracket. After changing it to the following it worked fine:



<c:if test="${not empty sp.mouse.strain}">

Monday, November 16, 2009

Migration from Tomcat 5.5 to Tomcat 6.0.20

The migration from Tomcat 5.5 to Tomcat 6.0.20 was relatively painless except for the 3 following issues I encountered.


Issue #1: Unable to read TLD issue

Turns out that I was including a copy of jsp-api-2.0.jar in the build of my WEB-INF/lib directory, and Tomcat already had it in its lib folder. Deleting the jar from my WEB-INF/lib directory fixed the problem.

Reference:
http://forums.sun.com/thread.jspa?threadID=580206&am

Issue #2: Missing mail.jar
Add the mail.jar to lib folder of Tomcat 6





Issue #3: Different Enum behaviour with JSTL


Don't use enum values directly in JSTL. Instead provide a getter method to retrieve the value such as getValue() and invoke ${enum.value} rather than just ${enum}. In Tomcat 5.5 the behaviour was if you had ${enum} internally it would return enum.toString(). Now with Tomcat 6 and as per section 1.18.2 of the 2.1 JSP-EL spec, the behaviour now returns enum.name(). So if you want the return the toString() value create and invoke getValue().

Reference:
https://issues.apache.org/bugzilla/show_bug.cgi?id=46920

Wednesday, November 11, 2009

Sharing your Vodafone Mobile Connect internet with Linux

This article will describe the details on how to setup your linux machine to share its internet connection with users connected to a router through your Vodafone Mobile Connection internet connection.

Vodafone Mobile Connect Card driver for Linux is a tool that allows you to establish a connection to the Internet using 3G cards. Details on installing the driver for your Vodafone Mobile connect onto your linux machine click here.

To find your driver click here.

I did have issues with the default DNS server configuration provided by the drivers. If you experience something similar try the following IP addresses for your DNS configuration:

  • 208.67.220.220 
  • 208.67.222.222
Once you have got your internet connection working on the linux machine, set the default gateway to point to your internet connection that will probably have an alias of ppp0. In Fedora linux I would type the following:

route add default gw 0.0.0.0 ppp0
If you type 'route' at the command-line you should see something similar to this:

[root@localhost ~]# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.64.64.64     *               255.255.255.255 UH    0      0        0 ppp0
192.168.1.0     *               255.255.255.0   U     0      0        0 eth0
link-local      *               255.255.0.0     U     0      0        0 eth0
default         *               0.0.0.0         U     0      0        0 ppp0

You also want to give your linux machine a static IP so that users on the router can point to your machine as their gateway. This is the following configuration I used:

IP: 192.168.1.105
subnet mask: 255.255.255.0
gateway: 0.0.0.0
 Now on the client computer that's connected to the router, configure their network settings to have the following:

Gateway: 192.168.1.105
subnet mask: 255.255.255.0
Now you can have multiple computers all sharing the same internet connection going through the Vodafone Mobile Connect card.

Cheers,
Phil

Apache Jetspeed 2.2.0 with Postgres installation

I attempted my first installation of the binary download of JetSpeed 2.2.0. Using the installer I chose postgres as my choice of database. However, during installation I encountered the following error:

Error running the install,The following error occurred while executing this line:
C:\Apache\Jetspeed-2.2\database\bulid.xml:126;Source file does not exist!

In order to get it working I had to edit the following file:

C:\Apache\Jetspeed-2.2.0\database\database.properties

And change the property value from
db.type=postgres
to
db.type=postgresql

Then in the directory C:\Apache\Jetspeed-2.2.0\database\
type ant

Now you can startup the server and verify it works.

Tuesday, November 10, 2009

HSSF Helper classes for producing simple Excel Documents with Enum types

I've created some classes to abstract Excel document creation away from HSSF api and reduce the amount of code needed.

The Enum class will represent the columns headers and the column index for which
data should be allocated. Adding a data to an Excel spreadsheet is as simple as the following:

session.addColumn(EnumClass.EnumConstant, "your data");

The session class will automatically figure out the column index based on the order of the enum constants defined in the enum class. The beauty of this is if you decide to rearrange the order of the columns, then all you have to do is rearrange the order of the enum constants defined in the enum class.

Here are the classes:

This is an example class using the ExcelSession. See how simple it is to use?


package au.edu.apf.phenomebank.report;

import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.web.servlet.view.document.AbstractExcelView;

import au.edu.apf.phenomebank.appservice.InventoryAppService;
import au.edu.apf.phenomebank.db.StrainFacilityCount;
import au.edu.apf.phenomebank.helper.ExcelSession;
import au.edu.apf.phenomebank.inventory.StorageFacility;
import au.edu.apf.phenomebank.inventory.Technician;
import au.edu.apf.phenomebank.web.ExcelReportingController;
import au.edu.apf.phenomebank.web.ParamNames;
import au.edu.apf.phenomebank.web.Util;

/**
 * Produces an Excel Document for reporting the number of mice frozen down for each Strain
 * at a particular facility
 *
 *
 * @author Philip Wu
 */
public class NumFrozenStrainFacilityExcelView extends AbstractExcelView {

    private InventoryAppService inventoryService;
    
    public InventoryAppService getInventoryService() {
        return inventoryService;
    }
    public void setInventoryService(InventoryAppService inventoryService) {
        this.inventoryService = inventoryService;
    }
    
    @Override
    protected void buildExcelDocument(Map map, HSSFWorkbook workbook,
            HttpServletRequest req, HttpServletResponse resp) throws Exception {

        // Create the Excel session
        ExcelSession session = new ExcelSession(workbook, FrozenColumn.class);

        // create the table headers
        session.nextRow();
        session.createHeaders();

        // Add the results
        SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yyyy");        
        for (StorageFacility facility : StorageFacility.values()) {
            List<StrainFacilityCount> results = inventoryService.findNumFrozernByStrainFacility(facility);
                        
            for (StrainFacilityCount result : results) {    
                session.nextRow();
                session.addColumn(FrozenColumn.STRAIN_ID, result.getStrainId());
                session.addColumn(FrozenColumn.STRAIN_NAME, result.getStrainName());
                session.addColumn(FrozenColumn.NUM_MICE, result.getNumFrozen());
                if (result.getDateOfFreezing() != null)
                    session.addColumn(FrozenColumn.DATE_OF_FREEZING, dateFormatter.format(result.getDateOfFreezing()));
                session.addColumn(FrozenColumn.FACILITY, facility);                
            }
            
        }
        
        Util.setAttachmentResponse(resp, ExcelReportingController.excelViews.get(EnumReportType.STRAIN_INVENTORY));
    }

}

enum FrozenColumn {

    STRAIN_ID("Strain ID"),
    STRAIN_NAME("Strain name"),
    NUM_MICE("# Mice"),
    DATE_OF_FREEZING("Date of Freezing"),
    FACILITY("Facility")
    ;
    
    private String value;
    private FrozenColumn(String value) {
        this.value = value;
    }
    
    public String toString() {
        return value;
    }
}



This is the ExcelSession class:


package au.edu.apf.phenomebank.helper;

import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

/**
 * Excel session as a framework for simplifying Excel document creation
 *
 *
 * @author Philip Wu
 */
public class ExcelSession {

    /**
     * Excel workbook
     */
    private HSSFWorkbook workbook;
    private HSSFSheet sheet;
    /**
     * The enum class
     */
    private Class enumClass;
    /**
     * The column index location for each enum value
     */
    private Map<Object, Integer> indexMap;
    
    /**
     * The current row
     */
    private HSSFRow curRow;
    /**
     * The current row number
     */
    private int rowNum;
    
    public ExcelSession (HSSFWorkbook workbook, Class enumClass, String worksheet) {
        
        if (worksheet == null || worksheet.length() == 0)
            worksheet = "worksheet";
        
        this.enumClass = enumClass;
        
        this.workbook = workbook;
        this.sheet = workbook.createSheet(worksheet);
        
        indexMap = EnumHelper.createIndexMap(enumClass);
        
    }
    
    public ExcelSession (HSSFWorkbook workbook, Class enumClass) {
        this(workbook, enumClass, null);
    }
    
    /**
     * Creates the headers for this Excel document based on the enum class
     */
    public void createHeaders() {
        // Create the headers        
        //HSSFRow row = sheet.createRow(rowNum);
        if (curRow == null) {
            nextRow();
        }
        
        ExcelHelper.createHeaders(workbook, curRow, enumClass.getEnumConstants());
        
    }
    
    /**
     * Moves down to the next row
     */
    public void nextRow() {        
        curRow = sheet.createRow(rowNum);
        rowNum++;
    }
    
    /**
     * Adds a column to the current row
     * @param row
     * @param enumColumn
     * @param value
     */
    public void addColumn(Object enumColumn, Object value) {
        if (value != null)
            ExcelHelper.addColumnDefault(curRow, indexMap.get(enumColumn), value.toString() , "");
    }
    
    /**
     * Provide the ability specify the column index of where to add the value
     * @param columnIndex
     * @param value
     */
    public void addColumn(int columnIndex, Object value, HSSFFont font) {
        if (value != null)
            ExcelHelper.addColumn(curRow, columnIndex, value.toString() , font);
        
    }
    
}



Here is the ExcelHelper class:


package au.edu.apf.phenomebank.helper;

import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

/**
 * Helper for Excel objects
 *
 *
 * @author Philip Wu
 */
public class ExcelHelper {

    /**
     * A Helper method to create an excel worksheet
     * @param workbook
     * @param sheetName
     * @param columns
     * @return
     */
    public static HSSFSheet createSheet(HSSFWorkbook workbook, String sheetName, String[] columns) {
        
        HSSFSheet sheet = workbook.createSheet(sheetName);
        
        HSSFRow row = sheet.createRow(0);
        
        createHeaders(workbook, row, columns);
        
        return sheet;
    }
    
    /**
     * Creates headers for the row using the following columns
     * @param workbook
     * @param row
     * @param columns
     */
    public static void createHeaders(HSSFWorkbook workbook, HSSFRow row, Object[] columns) {
        
        HSSFFont bold = workbook.createFont();
        bold.setBoldweight(org.apache.poi.hssf.usermodel.HSSFFont.BOLDWEIGHT_BOLD);
        
        for (int i=0 ; i < columns.length; i++) {
            Object fieldHeader = columns[i];
            HSSFRichTextString headerFieldValue = new HSSFRichTextString(fieldHeader.toString());
            headerFieldValue.applyFont(bold);
            
            row.createCell(i).setCellValue(headerFieldValue);
        }
    }
    
    public static void addColumn(HSSFRow row, int index, String value) {
        
        addColumn(row, index, value, null);
    }    
    
    /**
     * Helper method to add a column
     * @param row
     * @param index
     * @param value
     * @param defaultValue    The default value to use if value is null
     */
    public static void addColumnDefault(HSSFRow row, int index, String value, String defaultValue) {
        String setValue = defaultValue;
        if (value != null)
            setValue = value;
        addColumn(row, index, setValue);
    }
    
    /**
     * Adds a column to the row at the specified index with the given value applying
     * a font to the text if it exists.
     * @param row
     * @param index
     * @param value
     * @param font
     */
    public static void addColumn(HSSFRow row, int index, String value, HSSFFont font) {
        
        if (value == null)
            return;
        
        // Without replacing \r characters, excel produces square boxes
        value = value.replaceAll("\r", "");
        value = value.replaceAll("\n", "");
        
        HSSFRichTextString excelValue = new HSSFRichTextString(value);    
        if (font != null)
            excelValue.applyFont(font);
        
        row.createCell(index).setCellValue(excelValue);
    }        
    
}


The EnumHelper class:


package au.edu.apf.phenomebank.helper;

import java.util.HashMap;
import java.util.Map;

/**
 * Helper class for Enum types
 *
 *
 * @author Philip Wu
 */
public class EnumHelper {

    // The index position of the ExcelColumn in the enumerated constants
    public static int indexOf(Object enumType) {
        int index = 0;
        for (Object constant :  enumType.getClass().getEnumConstants()) {
            if (constant.equals(enumType))
                return index;
            index++;
        }
        
        return -1; // not found
    }
    
    /**
     * Creates a map mapping the Enum constant to its index position
     * @param enumClass
     * @return
     */
    public static Map<Object, Integer> createIndexMap(Class enumClass) {
        HashMap<Object, Integer> map = new HashMap<Object, Integer>();
        
        int index = 0;
        for (Object constant :  enumClass.getEnumConstants()) {
            map.put(constant, index);
            index++;
        }
        return map;
        
    }
    
}

Using Jericho HTML Parser to convert relative paths to absolute paths

Here is some sample Java code for converting all the 'src' attributes in elements from a relative path to an absolute path. It is easy to extend this to 'href' elements as well.



package au.edu.apf.phenomebank.web;

import java.io.IOException;
import java.net.URL;
import java.util.List;

import net.htmlparser.jericho.Attribute;
import net.htmlparser.jericho.Attributes;
import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.MicrosoftTagTypes;
import net.htmlparser.jericho.OutputDocument;
import net.htmlparser.jericho.Source;

/**
 * Handles a Foreign HTML page
 *
 *
 * @author Philip Wu
 */
public class ForeignHtmlParser {

    public static String convertRelativeToAbsolutePaths(String absoluteBasePath, String urlString) throws IOException {
        
        MicrosoftTagTypes.register();
        
        Source source=new Source(new URL(urlString));
        
        OutputDocument outDoc = new OutputDocument(source);
        
        
        List<Element> elementList=source.getAllElements();
        for (Element element : elementList) {
            if (element.getAttributes()!=null) { 
                
                Attributes attributes = element.getAttributes();
                                
                for (Attribute att  : attributes) {
                    if (att.getName().toLowerCase().equals("src")) {
                        // Convert relative paths to absolute paths
                        if (! att.getValue().startsWith("http")) {
                            
                            // Build the Absolute path 
                            StringBuilder sb = new StringBuilder();
                            sb.append(absoluteBasePath);                            
                            if (! att.getValue().startsWith("/"))
                                sb.append("/");
                            sb.append(att.getValue());
                            
                            // Replace the attribute with the new one
                            outDoc.replace(att, "src='"+sb.toString()+"'");                                                         
                        }
 
                    }
                }
                
            }
            
        }

        //System.out.println("outDoc="+outDoc);
        return outDoc.toString();
    }
    
}

Monday, October 19, 2009

CXF JAX-RS IllegalAnnotationException - Class has two properties of the same name

I am currently using Apache CXF to provide RESTful web services for the Australian PhenomeBank.

I was attempting to assign annotations of private field members of a class as follows:

    @XmlElement(name="mutationType")
    @XmlElementWrapper(name="mutationTypes")
    private Set<MutationType> mutationTypes  = EnumSet.noneOf(MutationType.class);

What I had forgot to do was assign the XmlAccessorType as follows:

@XmlRootElement(name="SearchCriteria")
@XmlAccessorType(XmlAccessType.FIELD)
public class SearchCriteria

Thursday, October 15, 2009

Ant OutOfMemoryException

Currently where I work we use Ant to deploy our application to a Tomcat server. Recently, I integrated several new libraries for Apache's CXF web services and reran my ant script to do the deployment and encountered this:

deploy:
[echo] Deploying to 150.203.7.14:8080 ...

BUILD FAILED
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2786)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:94)
at sun.net.www.http.PosterOutputStream.write(PosterOutputStream.java:61)

at java.io.BufferedOutputStream.write(BufferedOutputStream.java:105)


To resolve this I ended up setting the ANT_OPTS environment variable on my Windows machine as follows:

C:\workspace\PhenomeBank>set ANT_OPTS=-Xmx500m

Sunday, September 27, 2009

Searching and Displaying Terms OBO

Here is some sample code on how to search for a term and display its properties:



package au.edu.apf.phenomebank.ontology;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Collection;
import java.util.LinkedList;

import org.obo.dataadapter.DefaultOBOParser;
import org.obo.dataadapter.OBOParseEngine;
import org.obo.datamodel.Dbxref;
import org.obo.datamodel.IdentifiedObject;
import org.obo.datamodel.Link;
import org.obo.datamodel.LinkDatabase;
import org.obo.datamodel.NestedValue;
import org.obo.datamodel.OBOObject;
import org.obo.datamodel.OBOSession;
import org.obo.datamodel.PropertyValue;
import org.obo.datamodel.Synonym;
import org.obo.util.TextUtil;

/**
* Testing ontology parsing
*
*
* @author Philip Wu
*/
public class OntologyTest {

public static void main (String[] args) throws Exception {
System.out.println("Start");


DefaultOBOParser parser = new DefaultOBOParser();
OBOParseEngine engine = new OBOParseEngine(parser);

String path = "C:/Documents and Settings/a295029/Desktop/latest_MPheno_OBO.ontology";
Collection paths = new LinkedList();
paths.add(path);
engine.setPaths(paths);

engine.parse();

OBOSession session = parser.getSession();


// Using the Ontology
IdentifiedObject obj = session.getObject("MP:0009788");
if (obj != null) {
if (obj instanceof OBOObject) {
OBOObject term = (OBOObject) obj;
dumpTerm(System.out, term);
}
}


System.out.println("Finished");
}

public static void dumpNestedValue(PrintStream ps, NestedValue nv) {
if (nv!= null) {
ps.print(" Name: "+nv.getName());
if (nv.getPropertyValues() != null) {
for (PropertyValue pv : nv.getPropertyValues()) {
ps.println("Property: "+pv.getProperty()+"="+pv.getValue());
}
}
}
}

public static void dumpTerm(PrintStream ps, OBOObject term) {
String id = term.getID();

ps.println("ID:"+id);
ps.println("Name: "+term.getName());

if (term.getIDExtension() != null) {
ps.println("ID Extension: ");
dumpNestedValue(ps, term.getIDExtension());
}

if (term.getPropertyValues() != null && term.getPropertyValues().size() > 0) {
ps.println("Property values");
dumpPropertyValues(ps, term.getPropertyValues());
}

ps.println("Definition: "+term.getDefinition());
if (term.getDefinitionExtension() != null) {
dumpNestedValue(ps, term.getDefinitionExtension());
}

for (Dbxref dbxref : TextUtil.getAllDbxrefs(term)) {
ps.println("Def dbxref. ID: "+dbxref.getID()+ " DatabaseID: "+dbxref.getDatabaseID()+" Database: "+ dbxref.getDatabase()+" Desc: "+dbxref.getDesc());

}

for (Synonym syn : term.getSynonyms()) {
ps.println("Synonym. ID: "+syn.getID()+ " Text:"+syn.getText());
}

for (Link link : term.getParents()) {
ps.println("Parent. ID: "+ link.getParent().getID());
}
}

public static void dumpPropertyValues(PrintStream ps, Collection<PropertyValue> propertyValues) {
if (propertyValues != null) {
for (PropertyValue pv : propertyValues) {
ps.println("Property: "+pv.getProperty()+"="+pv.getValue());
}
}
}

}

Thursday, September 24, 2009

Java OBO Parser

I've been task with importing a large OBO file into a database. However, I had trouble finding a parser pre-bundled as a set of JAR files. There is one Java OBO parser that exists but it lives within a much larger application found here:

http://www.geneontology.org/GO.java.obo.parser.shtml

He goes into some details about the writing some code, but isn't clear about which JAR files from the SVN source that are needed to get it working. Here I will provide the list of 3 JARs needed for a Java OBO parser:

For some sample code see below:


DefaultOBOParser parser = new DefaultOBOParser();
OBOParseEngine engine = new OBOParseEngine(parser);

String path = "C:/MPheno_OBO.ontology";
Collection paths = new LinkedList();
paths.add(path);
engine.setPaths(paths);

engine.parse();
To import the OBO file, I plan writing my own implementation of OBOParser for better memory usage.

Cheers,
Phil

Wednesday, August 5, 2009

Javascript Array from getElementsByTagName is LIVE!

The array returned by getElementsByTagName() function is LIVE!

What I mean by LIVE is that as you traverse the array and invoke changes to the DOM, the items in the array itself can change automatically! Here's an example:

var inputEls = divEl.getElementsByTagName('input');
for (var j=0; j < inputEls.length; j++) {
alert('inputEls length='+inputEls.length);
var inputEl = inputEls[j];
inputEl.parentNode.removeChild(inputEl);
}

What you'll actually see is that the length of the array automatically decreases with each iteration because I am removing those elements from the DOM.

To work around this issue I had to traverse the array backwards:

for(var i=inputEls.length-1;i>=0; i--) {

}

Tuesday, August 4, 2009

Java TreeSet missing elements

If you notice that some elements may be missing after having added them to a TreeSet then it is probably because your implementation of Comparator or Comparable is incorrect.

This is the key note to remember:

"If two elements are different but compareTo returns 0, then TreeSet will consider them equal, and the newly added element replaces the old one".

Wednesday, July 22, 2009

HibernateSystemException: attempted to assign id from null one-to-one property

I had a bidirectional relationship in my one-to-one mapping, however I had forgotten to set the objects in my Java code to reference each other. Once I had done that, the problem was resolved.

SpermAnalysis sa = new SpermAnalysis();
cryoSession.getControlMouse().setSpermAnalysis(sa);
// Bidirectional relationship
sa.setMouse(cryoSession.getControlMouse());

Determine Mime type from bytes

If you have an image file stored in the database but don't have the extension of the file, then you may not know what the mime type should be.

There is a handy Java library that will inspect the bytes to determine the Mime type. The library can be found here:

MimeUtil

It's fairly easy to use. An example code is shown below:

byte[] bytes;
MimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MimeMagicMimeDetector");
MimeUtil.getMimeTypes(bytes);
MimeUtil.unregisterMimeDetector("eu.medsea.mimeutil.detector.MimeMagicMimeDetector");


Tuesday, April 14, 2009

Java Bean validation using reflection


public static boolean validateBeanFields(Object obj) {

if (obj == null)
return false;

Class objClass = obj.getClass();
Method[] methods = objClass.getMethods();
for (Method aMethod : methods) {
String methodName = aMethod.getName();
if (methodName.startsWith("get")) {
try {
Object retObj = aMethod.invoke(obj, null);

if (retObj == null)
return false;
else if (retObj instanceof Enum) // skip enum values
continue;
else if (retObj instanceof String) {
if (((String)retObj).length() == 0)
return false;
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
return true;
}