Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Monday, November 18, 2013

JMeter Tutorial - Writing a Test Plan

In this tutorial, we will write a very simple test plan.

Here are the specs of the Test Application we will run JMeter against:

  • large instance on EC2
  • Ubuntu LTS12.04
  • Tomcat 7
  • Java and Spring


Setting up JMeter on Windows

We will be setting up JMeter on Windows simply because it's easier. Read User Load Testing Simulation - Installing Apache JMeter on Windows 2012 Base.


Creating a Thread Group

Start JMeter by clicking on bin/ApacheJMeter.jar in your install location. You will see in the Tree hierarchy that it has a Test Plan item and a WorkBench item.

Right click on Test Plan -> Add -> Threads (Users) -> Thread Group

The Thread Group tells JMeter how many users and requests it should simulate.

In the Thread Group panel, fill in the following:

Name: Web Users
Number of Threads (users): 10
Ramp-Up Period (in seconds): 0
Loop Count: 5

The above will generate 5 requests for each of the 10 users. Total number of requests is 50.

The Ramp-Up Period defines the time delay which each JMeter will start the user. If Ramp-Up Period is 10 and Number of Threads is 10 then the delay between each user is 1 second. In the above, we have Ramp-Up Period = 0, meaning that all the users will start at the same time.


Add Default HTTP Request Information

Since most requests we are going to make will share some common properties (like IP and port), we will set up some default HTTP Request Information.

Right click on Web Users -> Add -> Config Element -> HTTP Request Defaults.

Fill in your server name (or IP) and port number.


Add Cookies

We will add HTTP Cookies.

Right click on Web Users -> Add -> Config Element -> HTTP Cookie Manager


Adding a HTTP Request

This is where your simulated users will request. We will add a login request. You will need to figure out what are your site's username and password parameters (In my case, it's username and password)

Right click on Web Users -> Add -> Sampler -> HTTP Request

Fill in the following:

Name: Login
Server Name of IP: /
Method: POST

In parameters, click Add.

Add Name=username, Value={your_username}
Add Name=password, Value={your password}

You can add a GET a request similarly as well.


Adding the Graph Results Listener

To observe response time, we can add the Graph Results Listener.

Right click on Web Users -> Add -> Listener -> Graph Results.


Running the Test Plan

In the menu bar, click on Run -> Start

Monday, November 4, 2013

Enable Async Request Processing for Java Spring

Serlvet 3 supports asynchronous request processing which allows the requested operation to be performed on a separate thread, freeing the HTTP request memory.

In Spring, an allocated amount of memory is allocated for request processing. If you are running a long operation (such as uploading a large file, batch mailing, big data analysis), the memory for that request would be blocked until the operation is finished.

A better way of approaching this would be to return the request right away and let the long operation to run in another thread.

In Spring 3.x, it is relatively easy with the @Async support.

Before I dive down into the tutorial, here's my specs:
  • ubuntu 12.04
  • large EC2 instance
  • OpenJDK 1.7
  • Maven 3.0.4
  • Spring 3.2.4
  • CXFServlet 2.5.3 with JAX-RS (This is for Rest API)
This post will be about how to enable @Async in your spring project.


Install the latest version of Spring

At the time of this writing, the stable version is 3.2.4. The following shows how to add the maven dependency in pom.xml



Use Serlvet 3.0 namespace

In web.xml, make sure you use the XML nameplace for version 3.0.

 


Add Async Support in entry servlets in web.xml

If you are writing a normal Spring MVC Web app, you will need to add async-supported in the dispatcher serlvet below. My project only uses the Rest API, so I put the async-supported xml tag in the CXFServlet.



Enable Async in application context

In applicationContext.xml, enable executor and scheduler. If you don't know where is the applicationContext.xml, find it from web.xml's contextConfigLocation context-param field.


Make sure you have the task namespace as above.


Annotate a method as @Async

Below is a quick test of the @Async method. Notice the @Async annotation below.


Try taking out the @Async annotation and execute the program. You should be able to observe the difference.

Wednesday, October 2, 2013

ElasticSearch - Indexing via Java API

There are many ways to populate your data to the ElasticSearch data store. The most primitive way is to populate via the REST API via PUT or POST requests.

In this tutorial, we will be populating via the Java API. I have data in MySQL and my Web application is based on Spring.

Here's my setup:

  • Ubuntu 12.04 Amazon EC2
  • JDK 1.7
  • Spring 3.2
  • MySQL


Install ElasticSearch (ES) via Maven

Put the following into your pom.xml file.

Make sure you also installed the same version of ES on your server. Read How to Install ElasticSearch on EC2.

Let's create a search service called ElasticSearchService:

Interface:



Implementation:

We will be using the ElasticSearch's native Java API. We will connect to the ElasticSearch cluster using the Client object. Using the XContentBuilder, we can construct JSON wrapper of the category objects. The category data is stored in MySQL and retrieved by the categoryDao object. Finally, a HTTP GET request will put the data into the ES cluster.



Let's create the interface that you can invoke the call.

Interface:



Implementation:

Thursday, September 26, 2013

Java reading and writing file line by line

We will be using BufferedReader to read a structured file line by line and then using BufferedWriter to write it out.

The example takes some structured data and creates MySQL insert statements for each dataset and then outputs it as a file.

Wednesday, June 19, 2013

Building a JAR Executable with Maven and Spring

I have a Spring MVC web project. I want to generate some xml files based on some data stored in my database. This program will be run once or a few times everyday. As the data size grows, the program may take longer to run. The best way to do this is to write a JAR executable and feed it to Amazon to Elastic MapReduce.

We will set up a small JAR project with Maven below.

First generate a Maven project called maventest. If you do not have maven set up, read Install Maven 3 on Amazon EC2 Ubuntu.
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=com.mycompany.maventest -DartifactId=maventest
Resources files are located in src/main/resources/.

Spring requires a context xml file that defines how classes are instantiated. Create a file called applicationContext.xml in src/main/resources.

Paste the following into the applicationContext.xml file



Create a file called jdbc.properties in src/main/resources. We will be connecting to a MySQL database.



My whole project is called myproject. It has the Spring MVC web project has the package name   com.mycompany.package1 and artifactId mywebproject. This cron program will have the package name com.mycompany.package2 with artifactId cron.

We will use the maven-jar-plugin to define the location of our main class.

< plugin>
< groupId>org.apache.maven.plugins< /groupId>
< artifactId>maven-jar-plugin< /artifactId>
< configuration>
  < archive>
    < manifest>
      < mainClass>com.mycompany.package2.App< /mainClass>
    < /manifest>
  < /archive>
< /configuration>
< /plugin>

In order to package all the dependencies as one jar file, we will use maven-shade-plugin. Sometimes, spring.schemas and spring.handlers files can be overwritten. Examine the transformers tag below to see that the content of these files will be appended.

We will now include all the dependencies in the pom.xml file.


Package the project (It's useful to understand what's compile, package, install and deploy)
mvn clean package
If the package command fails, it may be complaining that it can't find the com.mycompany.package1.mywebproject project.

You can do a mvn:install for mywebproject. This will install mywebproject to the local maven repository. It is located under /Users/{your_name}/.m2. Remember to compile mywebproject as JAR by setting it in the pom.xml. If you ever suspect that some classes are missing or the build is not quite correct. It's highly likely that mywebproject in the local repository is not up-to-date.

The jar file is located in the target folder. Run the jar
java -jar maventest-1-0-SNAPSHOT

Tuesday, June 18, 2013

Spring component-scan: scanning services from multiple base packages

In your applicationContext.xml, you can specify base packages for scanning by:


<context:component-scan base-package="com.mycompany.package1, com.mycompany.package2"/>

Maven - A sample pom.xml for java jar executable

The following provides a sample JAR executable.

It uses hiberate, spring, mysql.

The class that contains the Main function is specified in the "mainClass" tag.

Sample pom.xml

< ?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.generator</groupId>
  <artifactId>onix-generator</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>onix-generator</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>3.2.1.RELEASE</spring.version>
    <jdbc.groupId>mysql</jdbc.groupId>
        <jdbc.artifactId>mysql-connector-java</jdbc.artifactId>
        <jdbc.version>5.1.14</jdbc.version>
        <hibernate.version>3.6.10.Final</hibernate.version>
        <javamail.version>1.4.1</javamail.version>
        <log4j.version>1.2.16</log4j.version>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>com.mycompany.generator.App</mainClass>
              <packageName>com.mycompany.generator</packageName>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
      <source>1.7</source>
      <target>1.7</target>
      </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>${jdbc.groupId}</groupId>
      <artifactId>${jdbc.artifactId}</artifactId>
      <version>${jdbc.version}</version>
    </dependency>
    <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>mail</artifactId>
                    <groupId>javax.mail</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>jms</artifactId>
                    <groupId>javax.jms</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>jmxtools</artifactId>
                    <groupId>com.sun.jdmk</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>jmxri</artifactId>
                    <groupId>com.sun.jmx</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
        <groupId>com.mycompany.generator</groupId>
        <artifactId>epubserver</artifactId>
        <version>1.0-SNAPSHOT</version>
        <classifier>classes</classifier>
        </dependency>
  </dependencies>

</project>

You can generate an executable by running
mvn clean package
The jar file will be located in the target folder. You can run the executable by:
java -jar {name_of_jar}

Maven javac: invalid target release: 1.7

When I try to compile my maven project by running "mvn package", I get the following error
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project onix-generator: Compilation failure
[ERROR] Failure executing javac, but could not parse the error:
[ERROR] javac: invalid target release: 1.7
[ERROR] Usage: javac
[ERROR] use -help for a list of possible options
1) Check your Java version:

java -version
java version "1.7.0_09"
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode) 
2) Check javac version:

javac -version
javac 1.7.0_09
3) Check $JAVA_HOME

Make sure it points to the java bin directory.

Wednesday, June 12, 2013

Java Spring Profiling with Spring Insight

We will be using Spring Insight to profile a Spring MVC application in Amazon EC2. As long as you are using Ubuntu, you should be able to follow this post.

Specs:
  • Ubuntu Server 12.04.1 LTS
  • m1.small instance
  • a pre-existing Java Spring application deployed on tomcat7
  • Java Open JDK 1.7
Being by connecting to you machine via ssh.

Download Spring Insight. Select the vfabric tc server developer edition instead of the springsource tool suite (STS). You will need to sign on an account in the VMware website. Use wget to fetch the file to your ubuntu instance.
wget {link to vfabric-tc-server-developer-2.9.2.RELEASE.zip}
cd /opt
mkdir /opt/tools
cd /opt/tools
unzip vfabric-tc-server-developer-2.9.2.RELEASE.zip
mv vfabric-tc-server-developer-2.9.2.RELEASE
Inside the vfabric-tc-server-developer-2.9.2.RELEASE folder, run
./tcruntime-instance.sh create insight -t insight
You will see
Creating instance 'insight' ...
  Using separate layout
  Creating bin/setenv.sh
  Applying template 'base'
    Copying template's contents
    Applying fragment 'context-fragment.xml' to 'conf/context.xml'
    Applying fragment 'server-fragment.xml' to 'conf/server.xml'
    Applying fragment 'web-fragment.xml' to 'conf/web.xml'
    Applying fragment 'tomcat-users-fragment.xml' to 'conf/tomcat-users.xml'
    Applying fragment 'catalina-fragment.properties' to 'conf/catalina.properties'
  Applying template 'base-tomcat-7'
    Copying template's contents
    Applying fragment 'server-fragment.xml' to 'conf/server.xml'
    Applying fragment 'web-fragment.xml' to 'conf/web.xml'
    Applying fragment 'catalina-fragment.properties' to 'conf/catalina.properties'
  Applying template 'insight'
    Copying template's contents
    Applying fragment 'server-fragment.xml' to 'conf/server.xml'
  Configuring instance 'insight' to use Tomcat version 7.0.39.B.RELEASE
  Setting permissions
Instance created
Connector summary
  Port: 8080   Type: Auto-Switching HTTP 1.1   Secure: false
A folder called insight is created.

If you change into the insight directory, you will see a folder called webapps (this is almost same as the Tomcat directories). Copy your war file into this directory.
cd insight
cp {your_java_war_file} webapps/
Start the insight instance.
./tcruntime-ctl.sh insight start
You will see
Using CATALINA_BASE:   /opt/tools/vfabric-tc-server-developer-2.9.2.RELEASE/insight
Using CATALINA_HOME:   /opt/tools/vfabric-tc-server-developer-2.9.2.RELEASE/tomcat-7.0.39.B.RELEASE
Using CATALINA_TMPDIR: /opt/tools/vfabric-tc-server-developer-2.9.2.RELEASE/insight/temp
Using JRE_HOME:        /usr/lib/jvm/java-7-openjdk-amd64/jre
Using CLASSPATH:       /opt/tools/vfabric-tc-server-developer-2.9.2.RELEASE/insight/bin/insight-bootstrap-tomcat-extlibs-1.9.2.SR1.jar:/opt/tools/vfabric-tc-server-developer-2.9.2.RELEASE/tomcat-7.0.39.B.RELEASE/bin/bootstrap.jar:/opt/tools/vfabric-tc-server-developer-2.9.2.RELEASE/tomcat-7.0.39.B.RELEASE/bin/tomcat-juli.jar
Using CATALINA_PID:    /opt/tools/vfabric-tc-server-developer-2.9.2.RELEASE/insight/logs/tcserver.pid
Status:                RUNNING as PID=503
Be sure to open port 8080 in your security group.

Now browse to the webpage.
http://{external_ec2_address}:8080/{war_name}

Wednesday, May 8, 2013

Mac Java Could not start Tomcat - Address already in use


Could not start Tomcat: Protocol handler initialization failed: java.net.BindException: Address already in use :8080 -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.codehaus.mojo:tomcat-maven-plugin:1.1:run (default-cli) on project hello: Could not start Tomcat

If you are running on the Mac, try this
pkill -9 java

Tuesday, March 5, 2013

SpringMVC - SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoaderListener

Make sure you have added the following if you are using Maven


< dependency>
      < groupId>org.springframework< /groupId>
      < artifactId>spring-web< /artifactId>
      < version>3.2.1.RELEASE< /version>
< /dependency>

If not, make sure the spring-web jar is in your lib folder and also in the build path (Right click on your project -> properties -> Java Build Path -> Add JARs)

Monday, February 25, 2013

AWS Java - Securing S3 content using query string authentication

Amazon S3 is a highly available and durable hosting environment that can let you serve websites, images, and large files. Sometimes, you may want to secure your contents so only you or your authenticated users can access them. This becomes more important when it's pay content.

This post is about using query string authentication to make the content to be available for a specified period of time.

Specs:
  • Java 1.7
  • Eclipse Juno

Before you begin, make sure you have all the AWS Eclipse tools ready. Read Using Java AWS SDK to upload files to Amazon S3 for how to install the AWS SDK tool and a basic guide on how to upload, delete and retrieve files on S3.

Signing the request will require the following structure:

Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;

Signature = Base64( HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign ) ) );

StringToSign = HTTP-Verb + "\n" +
 Content-MD5 + "\n" +
 Content-Type + "\n" +
 Date + "\n" +
 CanonicalizedAmzHeaders +
 CanonicalizedResource;

CanonicalizedResource = [ "/" + Bucket ] +
  +
 [ sub-resource, if present. For example "?acl", "?location", "?logging", or "?torrent"];

CanonicalizedAmzHeaders = 


Assuming that you either have read the post above or you have implemented upload, upload a file to your Amazon S3 account.

In the AWS Management console, set the file's ACL permissions to your administrative account only (By default, it should be already if you didn't programmatically changed the ACL permission).

We will implement the following function called getS3Url().




We have set the expiration date to be one hour later. You would see the following expiration message an hour later.


< Error>
< Code>AccessDenied</ Code>
< Message>Access Denied</ Message>
< RequestId>8ECB67C2458CE483</ RequestId>
< HostId>
vL6wXNOkvYlpHXbvvlG1SGhy3q/+Ocb3guXtyaDZjmEu24Z4XQpwjfmNAvM+SViz
</ HostId>
</ Error>


Thursday, February 21, 2013

Using Java AWS SDK to upload files to Amazon S3

Amazon S3 is a highly available and durable storage suitable for storage large files that do not change frequently. This post will focus on how to upload files programmatically via the Java Amazon SDK. For an introduction to S3, read What is Amazon Simple Storage Service (Amazon S3)?

My specs:
  • Eclipse Juno
  • SpringMVC 3.1.x
  • Maven 3.0.x

Install AWS Toolkit

In eclipse, click on help in the menu bar and then "Install New Software".

In the "Work with:" input box, put " http://aws.amazon.com/eclipse" and Click Add...

Check on the AWS Toolkit for Eclipse and click Yes to install all the tools.

In the Eclipse toolbar, you will see a red cube icon. Click on the down arrow next to this icon. Click Preference.

Fill in your Access Key ID and Secret Access Key. Give it an Account Name (Ex. use your email). You can find your keys in the Amazon Management Console (My Account/Console -> Security Credentials). Click on Apply and OK.

In the Eclipse menu bar, click on Window -> Preferences. Expand the AWS Toolkit. Right click on your key. Click Select Private Key File. Associate it with your private key. Click OK.

Click on the down arrow next to the Amazon cube icon. Select Show AWS Explorer View. You should be able to see the Amazon S3 service and all your related buckets (if you have any).


Download and Install the AWS SDK for Java

You can download it here. Click on the AWS SDK for Java button.

Extract the file. Code Samples are located in /samples.

If you are using Maven, you can add the AWS SDK as a dependency in the pom.xml file.


< dependency>
< groupId>com.amazonaws</ groupId>
< artifactId>aws-java-sdk</ artifactId>
< version>1.3.32</ version>
< /dependency>


Choose the version you want here.

Alternatively, you can just add it as a library (Right Click on the project -> Java Build Path -> Libraries -> Add External JARs).


Running the default AWS Sample Apps

We will begin by setting up a sample project that you can check out how S3 works.

Click on the down arrow next to the Amazon icon.

Select New AWS Java Project.

Give a Project name.

Select your account.

Select Amazon S3 Sample, Amazon S3 Transfer Progress Sample, and AWS Console Application. Click Next.

Expand the newly created project. Left click on the AwsConsoleApp.java. In the Eclipse menu bar, click on Run -> Run.

You should see output like the following:


===========================================
Welcome to the AWS Java SDK!
===========================================
You have access to 3 Availability Zones.
You have 14 Amazon EC2 instance(s) running.
You have 0 Amazon SimpleDB domain(s)containing a total of 0 items.
You have 8 Amazon S3 bucket(s), containing 71841 objects with a total size of 224551364 bytes.



If you run the S3Sample.java, you will get the following:


===========================================
Getting Started with Amazon S3
===========================================

Creating bucket my-first-s3-bucket-39065c55-2ee5-413a-9de1-6814dbb253c1

Listing buckets
 - my-first-s3-bucket-39065c55-2ee5-413a-9de1-6814dbb253c1

Uploading a new object to S3 from a file

Downloading an object
Content-Type: text/plain
    abcdefghijklmnopqrstuvwxyz
    01234567890112345678901234
    !@#$%^&*()-=[]{};':',.<>/?
    01234567890112345678901234
    abcdefghijklmnopqrstuvwxyz

Listing objects
 - MyObjectKey  (size = 135)

Deleting an object

Deleting bucket my-first-s3-bucket-39065c55-2ee5-413a-9de1-6814dbb253c1


Integrate the S3 SDK

To begin, you need to have the file AwsCredentials.properties at the root of you class path. You can just copy the one generated during the sample project to your project class path. Or you can just create one with the following content:

secretKey=
accessKey=


Create an authenticated S3 object:

AmazonS3 s3 = new AmazonS3Client(new ClasspathPropertiesFileCredentialsProvider());

Objects in S3 are stored in the form of buckets. Each bucket is globally unique. You cannot create a bucket with a name that another user has created. Each bucket contains key and value pairs you can define in any ways you want.


Create a bucket:

String bucketName = "my-s3-bucket-" + UUID.randomUUID();
s3.createBucket(bucketName);

For readability, I have skipped the exception handling, I will come back to it at the end. The name of the bucket must conform to all the DNS rules. I usually name them using my domain name.


Delete a bucket:

s3.deleteBucket(bucketName);


List all buckets:

for (Bucket bucket : s3.listBuckets()) {
    System.out.println(" - " + bucket.getName());
}


Save an object in a bucket:

String key = "myObjectKey";

PutObjectRequest putObject = new PutObjectRequest(bucketName, key, myFile);
s3.putObject(putObject);

myFile is of class File above.


Delete an object:

s3.deleteObject(bucketName, key);


Get/Download an object:

String key = "myObjectKey";
GetObjectRequest getObject = new GetObjectRequest(bucketName, key);
S3Object object = s3.getObject(getObject);


List objects by prefix:

ObjectListing objectListing = s3.listObjects(new ListObjectsRequest()
                    .withBucketName(bucketName)
                    .withPrefix("My"));
for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
    System.out.println(" - " + objectSummary.getKey() + "  " +
                                   "(size = " + objectSummary.getSize() + ")");
}


Uploading large files

Use TransferManager whenever possible. It makes use of S3 multipart uploads to achieve enhanced throughput, performance, and reliability. It uses multiple threads to upload multiple parts of a single upload at once.

AWSCredentials myCredentials = new BasicAWSCredentials(...);
TransferManager tx = new TransferManager(myCredentials);
Upload myUpload = tx.upload(myBucket, myFile.getName(), myFile);

 while (myUpload.isDone() == false) {
     System.out.println("Transfer: " + myUpload.getDescription());
     System.out.println("  - State: " + myUpload.getState());
     System.out.println("  - Progress: " + myUpload.getProgress().getBytesTransfered());
     // Do work while we wait for our upload to complete...
     Thread.sleep(500);
 }


Exceptions

Whenever you call any of the AWS API, you should surround the calls with try and catch clauses like the following:

try{
    // AWS requests here

} catch (AmazonServiceException ase) {
            System.out.println("Caught an AmazonServiceException, which means your request made it "
                    + "to Amazon S3, but was rejected with an error response for some reason.");
            System.out.println("Error Message:    " + ase.getMessage());
            System.out.println("HTTP Status Code: " + ase.getStatusCode());
            System.out.println("AWS Error Code:   " + ase.getErrorCode());
            System.out.println("Error Type:       " + ase.getErrorType());
            System.out.println("Request ID:       " + ase.getRequestId());
        } catch (AmazonClientException ace) {
            System.out.println("Caught an AmazonClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with S3, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message: " + ace.getMessage());
        }
    }


If you interested in securing your S3 contents for your authenticated users only, check out AWS Java - Securing S3 content using query string authentication.

Eclipse this compilation is not on the build path of a java project

This may happen when the project is not recognized as a java project, making the intellisense not working.

My specs are as follow:

  • maven 3.0.x
  • JDK 1.7
  • SpringMVC


What you can do is to make eclipse to know it's a Java project.

Left click on your project in eclipse.
Click Project -> Properties.
Click on Project Facets, select Java.

If the above does not solve your problem, check this post - Eclipse "this compilation unit is not on the build path of a java project".

Friday, February 15, 2013

Java Multipart upload OutOfMemory error - Java heap space

When you are uploading a large file under a low memory machine, you may get an OutOfMemory error - "java.lang.OutOfMemoryError: Java heap space".

When you are using a library that first saves the uploading file to memory, you will need ample amount of RAM to upload it.

For example, if you upload something that is 64MB, the machine will need 64MB of RAM. If two files of 64MB are being uploaded simultaneously, the machine will need 128MB of RAM.

We will present two solutions below:

  1. increase the heap size
  2. read and upload files in chunks


1. Increase the heap size - Temporally Solution

If you have a memory leak, this is just treating the symptom and not curing the disease. RAM will eventually run out.

To give more RAM to Tomcat, put the following in ~/.bashrc.
export CATALINA_OPTS="-Xms512m -Xmx512m"
If you are installing from the Ubuntu distribution, put the following inside /etc/init.d/tomcat7. Use echo to make sure you can
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms512m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+DisableExplicitGC"
Restart Tomcat.


2. Read and upload files in chunks

If you are not doing this already, please do.

Tuesday, February 12, 2013

Spring - Could not open Hibernate Session for transaction

This happens when the Spring application is idle for a while and a user tries to log in to the application.

The message is as follows:
Could not open Hibernate Session for transaction; nested exception is org.hibernate.TransactionException: JDBC begin failed
 Subsequent logins after the first login failure would sucede.

This has to do with stale database connections. There are connections killed by the server that are still considered to be alive by the connection pool.

There are two solutions:

  1. set minimum connection pool size to zero
  2. set "testonborrow"
"testonborrow" will also test if the connection is alive prior to issuing the desired query.

To implement any of the above, you can use c3p0 or Apache's dbcp library.

The following will demonstrate "testonborrow":

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxActive" value="100"/>
        <property name="maxWait" value="1000"/>
        <property name="poolPreparedStatements" value="true"/>
        <property name="defaultAutoCommit" value="true"/>
        <property name="validationQuery" value="SELECT 1" />
        <property name="testOnBorrow" value="true" />
</bean>

Thursday, January 24, 2013

Setting up a Java Tomcat7 Production Server on Amazon EC2

This tutorial will demonstrate how to build a Tomcat7 server running a Java application on Amazon EC2.

Here are the tools we will set up:
  • Apache Tomcat7
  • Open JDK7
  • GitHub
  • Maven 3.0.4
  • MySQL

Creating a EC2 Instance

In the AWS Management Console, begin by creating a t1.micro Ubuntu Server 12.04.1 LTS 64-bit machine. (If you don't know how to create an instance, read Amazon EC2 - Launching Ubuntu SErver 12.04.1 LTS step by step guide.)

Here are some guidelines:
  • Uncheck Delete on Termination for the root volume
  • Add port 22, 80, 443 to the Security Group.

Create a EBS volume

We will create a 20GB volume to store our Java code. The EBS will be formated with XFS.


If the volume kept on getting stuck, keep restarting the EC2 instance until it's attached.


Configure the EC2 instance

ssh into the instance (ssh -i {key} ubuntu@{your_ec2_public_address})

sudo apt-get update -y

My mounting point for /dev/xvdf is called /vol.
cd /vol
mkdir src
mkdir webapps
mkdir war_backups

/vol/src is where we will place the application code. /vol/webapps is where we will deploy the WAR file. /vol/war_backups is for making war backups, as the name implies.


Deploying code from GitHub

Skip this if you are using other source control. The idea is that we will put the Java application code in the /vol/src folder.

sudo apt-get install git -y
mkdir /vol/src
cd /vol/src

git config --global user.name "your_name"
git config --global user.email "your_email"
git config --global github.user "your_github_login"
git clone ssh://git@github.com/username/repo.git

You will want to establish a connection with Github using ssh rather than https because if you are building an image that can be used for auto-scaling you don't want to input the username and password every time. See Generating SSH Keys for more details.

Your project should be located in /vol/src/{your_project}


Set up the Tomcat7 server

Begin by reading Install OpenJDK 7. Read Install Java OpenJDK 7 on Amazon EC2 Ubuntu.

echo $JAVA_HOME to check if it's set.

Install Tomcat 7. Read Install Tomcat 7 on Amazon EC2 Ubuntu.

Remember to change to ports 80, 443, and the root web directory as the Tomcat war root path.

Check http://{your_ec2_public_address} in your browser to make sure Tomcat7 is running.

Make sure Tomcat7 is still up after you reboot the machine.


Generating the war file

We will be using Maven to compile our Spring Java project. If you are using other build frameworks, skip this.

Read Install Maven 3 on Amazon EC2 Ubuntu.

Run "mvn --version" to make sure it's using OpenJDK 7 and running the latest version of Maven.

cd /vol/src/{your_project}
mvn clean install

A WAR file should be built.

Move this WAR file into the Tomcat webapps directory. If you are following this tutorial, it should be at /vol/webapps.

Remember to label this WAR file as ROOT.war

It's easier to do load balancing mapping later.

Browse to check you can access the site.


Using Amazon SES as the SMTP email service

Using SES will increase the likelihood of email delivery. Read Using Amazon SES to send emails.

Recompile your project and test it.


Moving MySQL to Amazon RDS

If you are using MySQL, you should move to Amazon RDS as it simplifies a lot of management, backup operations for you.

Read Using MySQL on Amazon RDS.

To interact with RDS through your EC2 instance, install MySQL Server or just the MySQL client interface.
sudo apt-get install -y mysql-server
Stop the local MySQL server. We won't be using it.
sudo /etc/init.d/mysql stop
Connect to your RDS instance
mysql -h {rds_public_address} -P 3306 -u{username} -p{password}
Do NOT use the following form. You will get a access denied.
mysql -u{username} -p{password} -h {rds_public_address} -P 3306
Update the JDBC settings in your application, recompile and test it.


Load Balancing Tomcat7

If you are planning to run multiple instances, read Setting up Lighttpd Load Balancer on EC2 Ubuntu or Setting up Nginx on EC2 Ubuntu.