Friday, November 26, 2010

Plug-ins for Eclipse

Eclipse is my favorite Java IDE (Integrated Development Environment). One of the best functionality offered by Eclipse, is the possibility of adding (free) third-party plug-ins, which makes Eclipse flexible, and customizable to satisfy your requirements. Here is a list of plug-ins I installed in Eclipse:

Subclipse
Integrate SVN in Eclipse with this tool. This tool makes it effortless to keep your project files in sync with your SVN repository.
http://subclipse.tigris.org/

PHPEclipse
If you PHP for development, then this tool is useful. It provides stuff like: syntax high-lighting, code-completion, and integrated manual.
http://www.phpeclipse.com

JSEclipse
If you use JavaScript, you can use this tool to make the coding experience better. It provides similar functionality like PHPEclipse, but for JavaScript instead of PHP.
http://www.interaktonline.com/products/eclipse/jseclipse/overview/

Checkstyle
This plug-in forces you to write Java code that adheres to a coding standard. Checkstyle also checks class design problems, duplicate code, and bugs.
http://checkstyle.sourceforge.net

Findbugs
This tool, well, finds bugs in your Java code. It uses static analysis on Java bytecode to detect bug patterns.
http://findbugs.sourceforge.net

UMLet
This is definitely my favorite tool to draw UML diagrams. Very easy to use, and it's free!
http://www.umlet.com

Friday, November 19, 2010

XML Document validation with XML Schema

In todays blogpost, I will show you how to validate an XML-document to its XSD-schema. Before we begin, create an example XML-schema:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://javaeenotes.blogspot.com/schema"
xmlns:tns="http://javaeenotes.blogspot.com/schema"
elementFormDefault="qualified">
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="age" type="xs:integer"/>
<xs:element name="birthdate" type="xs:date"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

You can use this schema to generate an XML-document with Eclipse:

<?xml version="1.0" encoding="UTF-8"?>
<tns:person
xmlns:tns="http://javaeenotes.blogspot.com/schema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://javaeenotes.blogspot.com/schema schema.xsd">
<tns:name>Albert</tns:name>
<tns:age>29s</tns:age>
<tns:birthdate>1981-11-19</tns:birthdate>
</tns:person>

Now, the last thing we need to do, is to build the validator:

package com.javaeenotes;

import java.io.File;
import java.io.IOException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

public class Main {
private static final String SCHEMA = "schema.xsd";
private static final String DOCUMENT = "document.xml";

public static void main(String[] args) {
Main m = new Main();
m.validate();
}

public void validate() {
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);

try {
DocumentBuilder parser = dbf.newDocumentBuilder();
Document document = parser.parse(new File(DOCUMENT));
SchemaFactory factory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

Schema schema = null;
schema = factory.newSchema(new File(SCHEMA));
Validator validator = schema.newValidator();
validator.validate(new DOMSource(document));
} catch (SAXException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
}

The validator will throw an exception if the validation process fails. Based on the specific type of error, the following exceptions could be thrown:

  • SAXException: XML-document not valid.

  • IllegalArgumentException: XML-artifact/instruction not supported.

  • IOException: document/schema file read error.

  • ParserConfigurationException: parser could not be configured.

Saturday, November 13, 2010

Saving large XMLTypes in Oracle databases

If you try to save a large XMLType that is over 4k characters long, you'll get this error:

ORA-01461:
can bind a LONG value only for insert into a LONG column

Oracle database has troubles binding large strings. One solution is to use a temporary clob to store the XML data, and bind that to the SQL-statement.

Connection con = ...
String xml = "<test>test</test>";
oracle.sql.CLOB clob = null;

clob = CLOB.createTemporary(con, true,
CLOB.DURATION_SESSION);
clob.open(CLOB.MODE_READWRITE);
clob.setString(1, xml);
clob.close();
clob.freeTemporary();

PrepareStatement s = con.prepareStatement(
"INSERT INTO table (xml) VALUES(XMLType(?))"
);

s.setObject(1, clob);

Using this method, you can store large XML-documents as XMLType in the Oracle database. But there is still a limitation with the XMLType. The XMLType cannot store any text-nodes and attributes values larger than 64k. Oracle suggests to use a XMLType CLOB-storage column to store really large XML-documents. But then, we cannot use native XML-parsing functions, which defeats the purpose of the XMLType column...

In newer versions of Oracle XML DB, this limit has been lifted.

References:

Thursday, November 11, 2010

Retrieve remote web service client host and IP

If you've created a web service, and you want to find out what the host or IP-address of the remote client is? The following code will be useful.

@WebService
public class WebService {
@Resource
WebServiceContext wsc;

@WebMethod
public String webMethod() {
MessageContext mc = wsc.getMessageContext();
HttpServletRequest req = (HttpServletRequest)
mc.get(MessageContext.SERVLET_REQUEST);
return "Client: " +
req.getRemoteHost() + " (" +
req.getRemoteAddr() + ").";
}
}

The code above will return the host and IP-address of the remote web service client back to the client.

Saturday, November 6, 2010

Using Oracle WebLogic deployment plans

As a developer, I often develop applications that have to be deployed and run in different execution environments. Initially, I start out developing for a development environment. Application tests are executed on a testing environment. The end-users can test and accept the system in the acceptance environment. The final environment is the production environment, where the application is actually used by end-users. This software development cycle is called a DTAP-street.

This has consequences on the Java development, configuration, and deployment process. On every execution environment, there are: different systems we have to connect to, different database/JDBC names we have to use, different IP-addresses/ports we can use, etcetera. This affects the way we package our application (WAR, JAR, and EAR). We want to avoid changing code or annotations for every execution environment. This way we don't need a specific tailor made package for every execution environment.

This blogpost is about how to deal with environment dependent parameters like: IP-addresses and JDBC-names. when you use Oracle WebLogic as your application server. We put these parameters in the deployment plan. For every execution environment, we create a specific deployment plan for it. The parameters in the deployment plan will override the default parameters in the application when deployed. This enables us to use the same application package (WAR, JAR, and EAR) for all the different execution environments.

An example application EAR file is created in this blogpost to illustrate the use of a deployment plan. It consists of the following steps:

  1. Create an EJB project, a web project, and an EAR project that contains the first two projects
  2. Use JNDI lookup and resource injection to read out or inject environment parameters from deployment descriptors
  3. Create an Oracle WebLogic deployment plan to override the parameters in the standard deployment descriptors


First, we create an EJB project with the following stateless session bean:

package com.javaeenotes;

import javax.annotation.Resource;
import javax.ejb.Stateless;

@Stateless(mappedName = "ejb/ejbEnv")
public class EjbEnv implements EjbEnvRemote, EjbEnvLocal {
@Resource
private String var1;

@Resource
private int var2;

public String getVar1() {
return var1;
}

public int getVar2() {
return var2;
}
}

Make sure you also implement the local and remote interfaces to expose the "getter" methods. We have two @Resource annotations to mark the variables we are going to inject with parameters in the ejb-jar.xml deployment descriptor.

Now, create the ejb-jar.xml deployment descriptor:

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:ejb="http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
version="3.0">

<display-name>env_ejb</display-name>
<enterprise-beans>
<session>
<ejb-name>EjbEnv</ejb-name>

<env-entry>
<env-entry-name>
com.javaeenotes.EjbEnv/var1
</env-entry-name>
<env-entry-type>
java.lang.String
</env-entry-type>
<env-entry-value>
Environment variables from ejb-jar.xml
</env-entry-value>
</env-entry>

<env-entry>
<env-entry-name>
com.javaeenotes.EjbEnv/var2
</env-entry-name>
<env-entry-type>
java.lang.Integer
</env-entry-type>
<env-entry-value>
999
</env-entry-value>
</env-entry>

</session>
</enterprise-beans>
</ejb-jar>

When the stateless session bean is loaded, both parameters will be injected into the attributes of the bean. Notice that we don't need "setter" methods to do this.

Next, create a web project with a simple servlet:

package com.javaeenotes;

import java.io.IOException;

import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class WebEnv extends HttpServlet {
@EJB(name="ejb/ejbEnv")
private EjbEnvRemote ejbEnv;

protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {

try {
Context env = (Context) new InitialContext()
.lookup("java:comp/env");

String s = (String) env.lookup("webVar1");
int i = ((Integer) env.lookup("webVar2")).intValue();

response.getWriter().write(
"webVar1: " + s + "\n");
response.getWriter().write(
"webVar2: " + i + "\n");

response.getWriter().write(
"ejbVar1: " + ejbEnv.getVar1() + "\n");
response.getWriter().write(
"ejbVar2: " + ejbEnv.getVar2() + "\n");
} catch (NamingException e) {
response.getWriter().write("NamingException");
}
}
}

This servlet uses JNDI-lookup to read parameters defined in the web.xml deployment descriptor. You can also see that the stateless session bean we created earlier is injected as attribute when this class is instantiated. When this servlet is called, it will print the environment parameters defined in both the ejb-jar.xml and web.xml.

The web.xml deployment descriptor looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="env_web" version="2.5">

<display-name>env_web</display-name>

<servlet>
<description></description>
<display-name>WebEnv</display-name>
<servlet-name>WebEnv</servlet-name>
<servlet-class>com.javaeenotes.WebEnv</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>WebEnv</servlet-name>
<url-pattern>/WebEnv</url-pattern>
</servlet-mapping>

<env-entry>
<env-entry-name>webVar1</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>
Environment variables from web.xml
</env-entry-value>
</env-entry>

<env-entry>
<env-entry-name>webVar2</env-entry-name>
<env-entry-type>java.lang.Integer</env-entry-type>
<env-entry-value>888</env-entry-value>
</env-entry>
</web-app>

Finally, package both projects in an EAR file, and deploy it on the Oracle WebLogic application server. Use the browser to view the output of the servlet. It will print:

webVar1: Environment variables from web.xml
webVar2: 888
ejbVar1: Environment variables from ejb-jar.xml
ejbVar2: 999

Viewing the output, we can verify that it works!

The last step is to create a deployment plan "Plan.xml", which we use to override the parameters defined in both deployment descriptors. The example contents of the deployment plan:

<?xml version='1.0' encoding='UTF-8'?>
<deployment-plan xmlns="http://xmlns.oracle.com/weblogic/deployment-plan"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://xmlns.oracle.com/weblogic/deployment-plan
http://xmlns.oracle.com/weblogic/deployment-plan/1.0/deployment-plan.xsd"
global-variables="false">
<application-name>env_ear</application-name>

<variable-definition>
<variable>
<name>WebEnv_Var1</name>
<value>NEW environment variables from web.xml</value>
</variable>
<variable>
<name>WebEnv_Var2</name>
<value>800</value>
</variable>
<variable>
<name>EjbEnv_Var1</name>
<value>NEW environment variables from ejb-jar.xml</value>
</variable>
<variable>
<name>EjbEnv_Var2</name>
<value>900</value>
</variable>
</variable-definition>

<module-override>
<module-name>env_ear.ear</module-name>
<module-type>ear</module-type>
<module-descriptor external="false">
<root-element>weblogic-application</root-element>
<uri>META-INF/weblogic-application.xml</uri>
</module-descriptor>
<module-descriptor external="false">
<root-element>application</root-element>
<uri>META-INF/application.xml</uri>
</module-descriptor>
<module-descriptor external="true">
<root-element>wldf-resource</root-element>
<uri>META-INF/weblogic-diagnostics.xml</uri>
</module-descriptor>
</module-override>
<module-override>
<module-name>env_ejb.jar</module-name>
<module-type>ejb</module-type>
<module-descriptor external="false">
<root-element>weblogic-ejb-jar</root-element>
<uri>META-INF/weblogic-ejb-jar.xml</uri>
</module-descriptor>
<module-descriptor external="false">
<root-element>ejb-jar</root-element>
<uri>META-INF/ejb-jar.xml</uri>

<variable-assignment>
<name>EjbEnv_Var1</name>
<xpath>/ejb-jar/enterprise-beans/session/
[ejb-name="EjbEnv"]/env-entry/
[env-entry-name="com.javaeenotes.EjbEnv/var1"]/
env-entry-value</xpath>
<operation>replace</operation>
</variable-assignment>

<variable-assignment>
<name>EjbEnv_Var2</name>
<xpath>/ejb-jar/enterprise-beans/session/
[ejb-name="EjbEnv"]/env-entry/
[env-entry-name="com.javaeenotes.EjbEnv/var2"]/
env-entry-value</xpath>
<operation>replace</operation>
</variable-assignment>

</module-descriptor>
</module-override>
<module-override>
<module-name>env_web.war</module-name>
<module-type>war</module-type>
<module-descriptor external="false">
<root-element>weblogic-web-app</root-element>
<uri>WEB-INF/weblogic.xml</uri>
</module-descriptor>
<module-descriptor external="false">
<root-element>web-app</root-element>
<uri>WEB-INF/web.xml</uri>

<variable-assignment>
<name>WebEnv_Var1</name>
<xpath>/web-app/env-entry/
[env-entry-name="webVar1"]/
env-entry-value</xpath>
<operation>replace</operation>
</variable-assignment>

<variable-assignment>
<name>WebEnv_Var2</name>
<xpath>/web-app/env-entry/
[env-entry-name="webVar2"]/
env-entry-value</xpath>
<operation>replace</operation>
</variable-assignment>

</module-descriptor>
</module-override>
<config-root></config-root>
</deployment-plan>

At the top we define the variables we want to use to override parameters:

<variable-definition>
<variable>
<name>WebEnv_Var1</name>
<value>NEW environment variables from web.xml</value>
</variable>
<variable>
<name>WebEnv_Var2</name>
<value>800</value>
</variable>
<variable>
<name>EjbEnv_Var1</name>
<value>NEW environment variables from ejb-jar.xml</value>
</variable>
<variable>
<name>EjbEnv_Var2</name>
<value>900</value>
</variable>
</variable-definition>

Then we use the <variable-assignment>-element to specify what we want to override with XPath. If you're not familiar with XPath, you should find a tutorial for explanation. Simply said, XPath makes it possible to "walk" to the element you want to override. The value string between the <xpath>-elements is actually one line. But for this blogpost, I need to split up the string, because otherwise it won't fit the blog.

<variable-assignment>
<name>WebEnv_Var2</name>
<xpath>/web-app/env-entry/
[env-entry-name="webVar2"]/
env-entry-value</xpath>
<operation>replace</operation>
</variable-assignment>

This actually means: replace the content of the <env-entry-value>-element where the <env-entry-name> equals "WebVar2", with the value specified as "WebEnv_Var2" in the variable definitions.

If we deploy the same EAR-file, but this time with the deployment plan, the servlet will output:

webVar1: NEW environment variables from web.xml
webVar2: 800
ejbVar1: NEW environment variables from ejb-jar.xml
ejbVar2: 900

The environment parameters defined in the deployment plan successfully override the parameters defined in the deployment descriptors.

References: