Wednesday, April 28, 2010

Importing data with SQL*Loader

Oracle created a tool for loading large amounts of data into an Oracle database. The tool is called SQL*Loader and can be run by using the command sqlldr.

In this example, we load data from a Microsoft Excel sheet. Before we can do that, we have to save the sheet as CSV (Comma Separated Values). Next, we define the structure of the data in a CTL-file, which also contains configuration data for the import process.

An example CTL-file (import.ctl):

options (errors=100, discard='import.discards')
load data
infile 'import.csv'
badfile 'import.errors'
insert
into table import_table
fields terminated by ','
optionally enclosed by '"'
(
COL1,
COL2
)

In the configuration above, we load the data in the table "import_table". The table has two columns: COL1 and COL2. The CSV-file has two values on every line, which are separated by a comma.

This configuration has two options defined:

  • errors=100
  • discard=import.discards

This means that the load is aborted after 100 errors, and the discarded lines are saved in the import.discards.

Other configuration settings:

  • infile: the file to load
  • badfile: the file to save errors when they occur
  • insert: insert data in empty table. Other modes: append, replace, truncate


We can start the load process by executing the following command:

sqlldr <user>/<password>@<host>
control=import.ctl log=import.log

References:

Saturday, April 24, 2010

Using property files in Java web applications

The use of property files avoids hardcoding content in Java classes. One way of using property file is loading it as a normal file with absolute file paths, which is not optimal. The other way, which involves classloaders, we avoid putting environment specific details into our code. This way, we make our code more portable.

Let us create an example property file Resource.properties:

name=John Doe
email=j.doe@company.com
description=John Doe is a \
Java software developer

The property file contains key value pairs separated by '='. When the value is spread among multiple lines we use a backslash to indicate the content continues on the next line. Normally, the property file is put in the CLASS_PATH for the classloader to be found. In Java web applications, the file is stored in WEB-INF/classes. In some cases you want to store the file in the same directory as the class that loads it. In that case, use the relative path (the full package name) to load it. In the example below, the property file is stored in com/package/.

private static final String PROPERTIES_FILE =
"com/package/Resource.properties";

The path to the property file is defined as a static variable in the class that uses it. The class loads the properties in the following way:

Properties properties = new Properties();
properties.load(
this.getClass().getResourceAsStream(PROPERTIES_FILE)
);
String name = props.getProperty("name");
String email = props.getProperty("email");
String description = props.getProperty("description");

Sunday, April 18, 2010

Sending HTML email with images with JavaMail API

In this post, I will build on the previous post about sending attachments with JavaMail. We will send HTML-formatted email with images that we include as attachments with the email. The protocol also allows to link to images on a webserver, but because spammers use this method to validate working email addresses, most email clients block external images.

The main idea is to include images as attachments like we did before, but now we also include a content-id per image we attach. Use HTML-code to format our email and use the cid: prefix along with the content-id in the src-attribute of the img-tag to refer to the image attachment.

The example code:

// Create new message with mail session.
Message message = new MimeMessage(session);

// Create multipart message.
MimeMultipart multipart = new MimeMultipart();

// Create bodypart.
BodyPart bodyPart = new MimeBodyPart();

// Create the HTML with link to image CID.
// Prefix the link with "cid:".
String str = "<html><h1>Hello</h1>" +
"<img src=\"cid:image_cid\"></html>";

// Set the MIME-type to HTML.
bodyPart.setContent(str, "text/html");

// Add the HTML bodypart to the multipart.
multipart.addBodyPart(bodyPart);

// Create another bodypart to include the image attachment.
bodyPart = new MimeBodyPart();

// Read image from file system.
DataSource ds = new FileDataSource("C:\\images\\image.png");
bodyPart.setDataHandler(new DataHandler(ds));

// Set the content-ID of the image attachment.
// Enclose the image CID with the lesser and greater signs.
bodyPart.setHeader("Content-ID", "<image_cid>");

// Add image attachment to multipart.
multipart.addBodyPart(bodyPart);

// Add multipart content to message.
message.setContent(multipart);

// Now set the header and send the email.
...

Saturday, April 17, 2010

Detecting binary data in Java

Sometimes you only want to show data, only when it's printable. I use the following trick to do so.

String value = "a string";
CharsetEncoder encoder =
Charset.forName("ISO-8859-1").newEncoder();

if (encoder.canEncode(value)) {
System.out.println(value);
} else {
System.out.println("<BINARY DATA>");
}

Before I print data, I check if the data can be converted to ISO-8859-1 (Latin-1) encoding, which includes all characters used throughout The Americas, Western Europe, Oceania, and a large part of Africa. When this fails I know there are characters that are not defined in the charset, which implies the data might be binary.

This method works most of the time, but there is no guarantee it works 100% in every situation. Two scenarios where this method fails are when the binary data only includes printable data or when text data is encoded in a different charset.

For printing text in other charsets like Chinese or Arabic, you have to use the corresponding encodings instead of Latin-1 to make this trick work.

Wednesday, April 14, 2010

JAR search engine

The very useful website findJAR.com is a JAR search engine that helps Java developers to find JAR libraries containing required Java classes. The search engine can be integrated into Eclipse and Firefox with available plugins.

http://www.findjar.com

Tuesday, April 13, 2010

Using JavaMail API with Glassfish and GMail

In this post, I'll show you how to configure JavaMail to use the SMTP server of GMail in Glassfish. This way, you avoid hardcoding server addresses in your application and make your application more portable. It also minimalizes the amount of "plumping" code.

Setup Glassfish

First, fire up the admin screen of Glassfish and click on JavaMail Sessions. Then create a new session configuration by clicking "new".

Make sure the following fields are filled in:

  • JNDI name: mail/<name>
  • Mail Host: smtp.gmail.com
  • Default User: <email>
  • Default Return Address: <email>

The JNDI name must be prefixed with "mail/". Use your GMail email address in last two fields.

Skip the Advanced settings and create additional properties at the bottom of the screen:

  • mail.smtp.socketFactory.port: 465
  • mail.smtp.port: 465
  • mail.smtp.socketFactory.fallback: false
  • mail.smtp.auth: true
  • mail.smtp.password: <gmail_password>
  • mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory

Use your valid GMail password in the password field. Save, and your configuration is ready for use.

Example client to send email with attachments

Next, we create a client to use the newly created JavaMail service in Glassfish. Before we can do that, we need the application server libraries: appserv-rt.jar and javaee.jar. You can find them in the lib directory of your Glassfish installation. Make sure all the libraries are in your build/class-path.

If you still get unresolved classes related to JavaMail, then you might also need the JavaMail libraries, which you can download here.

The example client below builds an email with three attachments from three different sources, and sends the email to two recipients. You have to use MIME-types to indicate the type of attachments. Save the code below as Main.java, compile, and run!

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeMessage.RecipientType;
import javax.mail.util.ByteArrayDataSource;
import javax.naming.InitialContext;

public class Main {

public void runTest() throws Exception {
InitialContext ctx = new InitialContext();
Session session =
(Session) ctx.lookup("mail/<name>");
// Or by injection.
//@Resource(name = "mail/<name>")
//private Session session;

// Create email and headers.
Message msg = new MimeMessage(session);
msg.setSubject("My Subject");
msg.setRecipient(RecipientType.TO,
new InternetAddress(
"tony@email.com",
"Tony"));
msg.setRecipient(RecipientType.CC,
new InternetAddress(
"michelle@email.com",
"Michelle"));
msg.setFrom(new InternetAddress(
"jack@email.com",
"Jack"));

// Body text.
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText("Here are the files.");

// Multipart message.
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);

// Attachment file from string.
messageBodyPart = new MimeBodyPart();
messageBodyPart.setFileName("README1.txt");
messageBodyPart.setContent(new String(
"file 1 content"),
"text/plain");
multipart.addBodyPart(messageBodyPart);

// Attachment file from file.
messageBodyPart = new MimeBodyPart();
messageBodyPart.setFileName("README2.txt");
DataSource src = new FileDataSource("file.txt");
messageBodyPart.setDataHandler(new DataHandler(src));
multipart.addBodyPart(messageBodyPart);

// Attachment file from byte array.
messageBodyPart = new MimeBodyPart();
messageBodyPart.setFileName("README3.txt");
src = new ByteArrayDataSource(
"file 3 content".getBytes(),
"text/plain");
messageBodyPart.setDataHandler(new DataHandler(src));
multipart.addBodyPart(messageBodyPart);

// Add multipart message to email.
msg.setContent(multipart);

// Send email.
Transport.send(msg);
}

public static void main(String[] args) {
Main cli = new Main();
try {
cli.runTest();
} catch (Exception e) {
e.printStackTrace();
}
}
}

Monday, April 12, 2010

ANT build file for Java web projects

The ANT build file below can be used to compile and package Java web projects discussed in the previous post. What also can be added are targets to call (unit) tests and automatic application deployment code (copying the *.war file to an autodeploy directory).

The project settings have to be customized for every project. The rest can be reused.

<project name="webproject" basedir="." default="package">
<!-- PROJECT SETTINGS -->
<property name="project.name" value="webproject" />
<property name="project.war"
value="${project.name}.war" />

<!-- FIXED PATHS -->
<property name="path.build" value="build" />
<property name="path.sources" value="src/java" />
<property name="path.classes"
value="build/WEB-INF/classes" />
<property name="path.dist" value="dist" />
<property name="path.lib" value="lib" />
<property name="path.web" value="web" />

<!-- CLEAN -->
<target name="clean">
<echo message="CLEANING PROJECT" />
<delete includeemptydirs="true">
<fileset dir="${path.build}" />
<fileset dir="${path.dist}" />
</delete>
<mkdir dir="${path.classes}" />
<mkdir dir="${path.dist}" />
</target>

<!-- COMPILE -->
<target name="compile" depends="clean">
<echo message="COMPILING PROJECT" />
<path id="lib.path.ref">
<fileset dir="${path.lib}"
includes="*.jar"/>
</path>

<javac srcdir="${path.sources}"
destdir="${path.classes}"
classpathref="lib.path.ref"
debug="true">
</javac>
</target>

<!-- PACKAGE -->
<target name="package" depends="compile">
<echo message="PACKAGING PROJECT" />
<copy todir="${path.build}"
includeEmptyDirs="yes">
<fileset dir="${path.web}" />
</copy>
<copy todir="${path.build}/WEB-INF/classes">
<fileset dir="${path.sources}">
<filename name="**/*.properties" />
</fileset>
</copy>
<copy todir="${path.build}/WEB-INF/lib"
includeEmptyDirs="yes">
<fileset dir="${path.lib}" />
</copy>
<war destfile="${path.dist}/${project.war}"
basedir="${path.build}"/>
</target>
</project>

Saturday, April 10, 2010

Java web application project directory structure

The directory structure I use for Java web projects is based on the Java Blueprints Guidelines recommended by SUN.

/webproject/ (the project root directory)
/webproject/build/ (this directory is packed into a WAR-file)
/webproject/test/ (system wide test files)
/webproject/setup/ (configuration files for container or project)
/webproject/dist/ (contains the WAR file)
/webproject/lib/ (libraries/jars)
/webproject/src/
/webproject/src/java/ (Java sources)
/webproject/src/conf/ (configuration files for build process)
/webproject/src/test/ (unit tests)
/webproject/docs/ (documentation)
/webproject/web/ (the web root starts here)
/webproject/web/WEB-INF/
/webproject/web/WEB-INF/jspf/*.jspf (JSP fragment/include files)
/webproject/web/WEB-INF/lib/
/webproject/web/WEB-INF/tlds/
/webproject/web/WEB-INF/tags/
/webproject/web/WEB-INF/faces-config.xml
/webproject/web/WEB-INF/web.xml
/webproject/web/*.jsp
/webproject/web/*.html
/webproject/web/css/ (CSS-files)
/webproject/web/img/ (images)
/webproject/web/js/ (JavaScript files)
/webproject/LICENSE.txt
/webproject/README.txt
/webproject/build.xml (ANT build file)

In the future, I'll post the ANT build file, which is used to automate build and package processes.

Friday, April 9, 2010

How to use a DataSource

In this post, we'll use the DataSource that is configured in the previous post.

Get the initial JNDI context object, which provides access to the JNDI interface of the application server.

Context ctext = new InitialContext();

Now, use the logical name that is configured in the application server to retrieve the datasource.

DataSource ds =
(DataSource)ctext.lookup("jdbc/<logical_name>");

Get the connection from the pool. The two parameters are optional. The default credentials are used by the application server, when the parameters are omitted.

Connection conn = ds.getConnection("<username>","<password>");

Use the connection.

PreparedStatement stmt = conn.prepareStatement(
"UPDATE table SET int_col=? WHERE varchar_col=?");
stmt.setInt(1, 75);
stmt.setString(2, "condition");
stmt.executeUpdate():

Finally, return the connection to the pool.

conn.close();

Wednesday, April 7, 2010

Configuring an Oracle DataSource on Glassfish

A DataSource connection has important advantages over the use of DriverManager:

- The use of logical names in the application, instead of using hard coded database addresses (in property files)
- Connection pooling managed by the container
- Distributed transactions managed by the container

To configure an Oracle datasource on Glassfish, follow the following steps:

1. Copy the JDBC driver of Oracle to the lib directory of your Glassfish installation directory.

2. Restart Glassfish.

3. Login to the admin page.

4. Browse to the Connection Pools page (Resources -> JDBC -> Connection Pools)

5. Create a new connection pool by clicking on New.

6. Give the pool a name (NOT prefixed with jdbc/), choose oracle.jdbc.pool.OracleDataSource as resource type and Oracle as vendor.

7. Now click next. The driver class is automatically detected, so it's automatically filled in. Next, make sure you fill in the properties: user, password and URL.

Example:

url=jdbc:oracle:thin:@<host>:1521:<sid>
user=<user>
password=<password>

8. Save and ping to see if it works. If so, the pool is ready to be used.

9. Now browse to the JDBC Resources page (Resources -> JDBC -> JDBC Resources).

10. Create a new JDBC resource by clicking on New.

11. Fill in the JDBC resource name (prefixed with jdbc/), and select the newly created connection pool in Pool Name. The DataSource is now ready for use.

Sunday, April 4, 2010

Developing EJB 3.0 in Eclipse

This tutorial will show you how to develop a Java EE Session Bean in Eclipse, and deploy it in on an application server.

Before you begin, you need to have have both the Java Development Kit (JDK) and an application server installed on localhost. In this example I used Glassfish, which has an autodeploy directory. When an EJB jar file is dropped into the autodeploy directory, the application server automatically deploys it. To download the JDK, click here. To download Glassfish, click here.

Step 1: Create new EJB project



Let Eclipse generate the EJB-deployment descriptor.



Include two Java EE jars (appserv-rt.jar and javaee.jar) which is needed to compile the beans. You can find the jars in the lib directory of your Glassfish installation directory. Add the jars to your project build path (Right-click on project, then click Build Path).



Step 3: Create the EJB Stateless Session Bean







When you finish this step, you will find three skeleton class files of your bean. Make sure they look like the code examples below:

ExampleSessionBean source:

package example;

import javax.ejb.Stateless;

@Stateless(name = "ExampleSessionBean",
mappedName = "ejb/ExampleSessionBean")
public class ExampleSessionBean implements
ExampleSessionBeanRemote, ExampleSessionBeanLocal {

public ExampleSessionBean() {
;
}

public int multiply(int a, int b) {
return a * b;
}

public int add(int a, int b) {
return a + b;
}

public int substract(int a, int b) {
return a - b;
}
}


ExampleSessionBeanLocal source:

package example;
import javax.ejb.Local;

@Local
public interface ExampleSessionBeanLocal {
public int multiply(int a, int b);

public int add(int a, int b);

public int substract(int a, int b);
}


ExampleSessionBeanRemote source:

package example;
import javax.ejb.Remote;

@Remote
public interface ExampleSessionBeanRemote {
public int multiply(int a, int b);

public int add(int a, int b);

public int substract(int a, int b);
}


Step 7: Export project as EJB jar

To compile the EJB-jar file, we select the project and do a right-click. Now select Export and then EJB JAR file. Now fill in the next screens:






Step 8: Deploy the EJB-jar
Now drag and drop the exported EJB-jar file to the autodeploy directory of Glassfish. The bean is now ready for use.

Step 9: Create remote test client

The step described next is optional. In this step we create a test client, which is run within Eclipse to test the remote EJB interface we created.

import javax.naming.InitialContext;

import example.ExampleSessionBeanRemote;

public class Main {
public void runTest() throws Exception {
InitialContext ctx = new InitialContext();
ExampleSessionBeanRemote bean =
(ExampleSessionBeanRemote) ctx
.lookup("ejb/ExampleSessionBean");
int result = bean.multiply(3, 4);
System.out.println(result);
}

public static void main(String[] args) {
Main cli = new Main();
try {
cli.runTest();
} catch (Exception e) {
e.printStackTrace();
}
}
}


Compile and run within Eclipse to view the result in the Console tab.