Thursday, December 8, 2011

Using Java to access a URL through a proxy

The following code snippet demonstrates how to access a URL through a proxy that requires authentication:


public static String connectToProxy() {

String result = "";
String status = "";

Authenticator.setDefault(new ProxyAuthenticator(username, password));
System.setProperty("http.proxyHost", PROXY_HOST);
System.setProperty("http.proxyPort", PROXY_PORT);

try {
URL url;
url = new URL("http://google.com");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
while ((result = in.readLine()) != null)
status += result;
in.close();
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
return status;
}

class ProxyAuthenticator extends Authenticator {
private String user, password;

public ProxyAuthenticator(String user, String password) {
this.user = user;
this.password = password;
}

protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, password.toCharArray());
}
}

Using Java to Call RESTful web services

The following code snippet demonstrates how to call a RESTful web service that requires BASIC Authentication:



public static String connectToResource() {

String result = "";
String status = "";

try {
URL url = new URL("http://localhost:8080/WEB_APP/RESOURCE/PRODUCT_ID");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic " +
new String(com.sun.jersey.core.util.Base64.encode(username + ":" + password)));
connection.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while ((result = in.readLine()) != null)
status += result;
in.close();
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
return status;
}

Thursday, September 15, 2011

Using Ehcache in a distributed environment

In this blog I will show you how to use Ehcache to share data in a distributed environment. My suggestion is to start with a small app and get it running in a single node environment. Once the correct behavior of your app is verified, you can simply change Ehcache config to use RMI replicated caching and deploy your app to multiple nodes.

Lets start with a simple application in Java.

Class Data.java encapsulates the information we want cached. Notice this class needs to implement java.io.Serializable.


package com.mycompany.myproject.mypackage;

import java.io.Serializable;

public class Data implements Serializable {

private static final long serialVersionUID = 2725776132167576714L;
private String id;
private String name;

public Data(String id, String name) {
this.id = id;
this.name = name;
}

public Data(String name) {
this.name = name;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public int hashCode() {
int result = 0;
/* add code here */
return result;
}

@Override
public boolean equals(Object obj) {
/* add code here */
return true;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Data [id=");
builder.append(id);
builder.append(", name=");
builder.append(name);
builder.append("]");
return builder.toString();
}
}


You need to configure caching and let Ehcache handle your Data cache.

Ehcache works off of a configuration file in XML. By default if ehcache.xml is found on your classpath it will be used. Later on I will show you how to configure Ehcache without using "ehcache.xml".

For now, lets assume you are working with ehcache.xml. If you are using a Maven project, simply place this file in your src/main/resources.

ehcache.xml should look like this:


<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">

<diskStore path="java.io.tmpdir/EhCacheNbWeb" />

<defaultCache eternal="false" maxElementsInMemory="1000"
overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU" statistics="true" />

<cache name="dataCache" eternal="true"
maxElementsInMemory="100" overflowToDisk="false" diskPersistent="false"
timeToIdleSeconds="0" timeToLiveSeconds="300"
memoryStoreEvictionPolicy="LRU" statistics="true" />

</ehcache>



To initialize and start using the cached data, we need to create a class called DataCacheManager.



package com.mycompany.myproject.cache;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

public class DataCacheManager {

private String[] cacheNames;
private CacheManager cacheMgr;
private Cache dataCache;

public DataCacheManager() {
cacheMgr = CacheManager.create();
cacheNames = CacheManager.getInstance().getCacheNames();
dataCache = cacheMgr.getCache("dataCache");
}

public void getCache() {
dataCache = cacheMgr.getCache("dataCache");
}

public void addData(Data data) {
Element dataElement = new Element(data.getId(), data);
dataCache.put(dataElement);
}

public Data getData(String id) {
Element dataElement = dataCache.get(id);
return (Data)dataElement.getValue();
}

public boolean deleteData(String id) {
return dataCache.remove(id);
}

public ArrayList getAllData() {
List keys = dataCache.getKeys();
Iterator iterator = keys.iterator();
ArrayList dataList = new ArrayList();
String key;
while (iterator.hasNext()) {
key = (String) iterator.next();
dataList.add(getData(key));
}
return dataList;
}

public Data addData(String id, String name) {
Data data = new Data(id, name);
addData(data);
return data;
}

public void deleteAllData() {
dataCache.dispose();
}

public String getUniqueDataId() {
UUID uuid = UUID.randomUUID();
return String.valueOf(uuid);
}

public static void main(String args[]) {
DataCacheManager dataCacheMgr = new DataCacheManager();
System.out.print("cacheNames = ");
for (int i = 0; i < dataCacheMgr.cacheNames.length; i++)
System.out.print(" " + dataCacheMgr.cacheNames[i]);
Data data = new Data("myUniqueId_123", "myName");
dataCacheMgr.addData(data);
Data data2 = dataCacheMgr.getData("myUniqueId_123");
dataCacheMgr.deleteData("myUniqueId_123");
}
}



To run your application in a cluster of nodes and distribute it across multiple nodes, follow these steps:

Lets assume there are two nodes in your cluster.
1. Deploy your application to both nodes.
2. Modify your ehcache.xml as in the example below and place is on the classpath of each node.



<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">

<cacheManagerEventListenerFactory class="" properties="" />

<!-- Server 1 -->
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual, rmiUrls=//10.66.77.99:40001/dataCache" />

<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=10.66.77.88, port=40001, socketTimeoutMillis=120000" />

<!-- Server 2 -->
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual, rmiUrls=//10.66.77.88:40001/dataCache" />

<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=10.66.77.99, port=40001, socketTimeoutMillis=120000" />

<defaultCache eternal="true" maxElementsInMemory="100"
overflowToDisk="false" />

<cache name="dataCache" maxElementsInMemory="100"
eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true,
replicateUpdatesViaCopy=false, replicateRemovals=true " />

<bootstrapCacheLoaderFactory class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
</cache>
</ehcache>

Monday, April 25, 2011

Setting up Eclipse for developing web based applications using SVN, Maven and Tomcat.

1. Download "Eclipse IDE for Java EE Developers" from http://www.eclipse.org/downloads/

2. Add subversive:

• On main menu, choose Help > Install New Software. The available Software dialog appears.
• In the Work with list, select Helios - http://download.eclipse.org/releases/helios. A list of software packages appears.
• Expand the Collaboration node.
• Scroll the list and check box for Subversive Team Provider (incubation)
• Check other options in the dialog as desired and click the Next button. The Install Details screen appears in the dialog.
• Click the Next button, accept the license and click Finish. Subversive will download and install.
• It is recommended to accept the option to restart Eclipse.

Once Eclipse is restarted, try to import from SVN. "Subversive Connector Discovery" window will pop up.
Select "SVN Kit 1.3.5" or the latest number. Select Next and accept user agreement.

At this point, the trick is to abort the import process and restart eclipse. You should be able ti import again.

To list the installed plugin: Help>Install New Software, and selected "already installed?"

Eclipse IDE for Java Developers 1.3.2.20110218-0812 epp.package.java
Subversive SVN Connectors 2.2.2.I20110124-1700 org.polarion.eclipse.team.svn.connector.feature.group
Subversive SVN Team Provider (Incubation) 0.7.9.I20110207-1700 org.eclipse.team.svn.feature.group
SVNKit 1.3.5 Implementation (Optional) 2.2.2.I20110124-1700 org.polarion.eclipse.team.svn.connector.svnkit16.feature.group

3. Add m2eclipse

• On main menu, choose Help > Install New Software. The available Software dialog appears.
• In the Work with list, add http://m2eclipse.sonatype.org/sites/m2e
• Select Maven Integration for Eclipse and accept license agreement.
• Maven Maven will download and install. Restart Eclipse.

To list the installed plugin: Help>Install New Software, and selected "already installed?"

Eclipse IDE for Java Developers 1.3.2.20110218-0812 epp.package.java
Maven Integration for Eclipse (Required) 0.12.1.20110112-1712 org.maven.ide.eclipse.feature.feature.group
Subversive SVN Connectors 2.2.2.I20110124-1700 org.polarion.eclipse.team.svn.connector.feature.group
Subversive SVN Team Provider (Incubation) 0.7.9.I20110207-1700 org.eclipse.team.svn.feature.group
SVNKit 1.3.5 Implementation (Optional) 2.2.2.I20110124-1700 org.polarion.eclipse.team.svn.connector.svnkit16.feature.group

4. Download "Tomcat 7" from http://tomcat.apache.org/download-70.cgi

5. In Eclipse, Select Window>Show View>Servers. This will add a new tab to the bottom window. Select "Servers" tab and right click to select New>Server. Select Apache>Tomcat v7.0 Server and provide the required information such as the directory where you installed Tomcat, etc.

At this point, you should be ready to create a new "Dynamic Web Project" that can be added to your Tomcat server or import an existing Maven project from a SVN repository. In order to run an imported Maven project on Tomcat you need to issue the following command from a shell:

mvn eclipse:eclipse -Dwtpversion=1.5

The trick is to go back to eclipse and change the following Project properties:
Java Compiler : Make sure Java version is set to 1.6 or higher
Project Facets : Select Dynamic Web Module to use the appropriate Java version.

Tips

1. If you get a "java.lang.OutOfMemoryError: PermGen space" when running Tomcat in Eclipse, edit eclipse.ini to modify your JVM settings.

On MacOS, you can find eclipse.ini in ~eclipse/Eclipse.app/Contents/MacOS.
Your settings should look something like, making sure each item is on a new line:
-vmargs
-Xms128m
-Xmx512m
-XX:MaxPermSize=512m

To verify your settings in Eclipse, Select About Eclipse>Installation Details>Configuration.

2. You may get a "ClassNotFoundException" when running your web app on a Tomcat server. The exception is in reference to a class in a jar file that is already added as a Maven dependency and exists in target//WEB-INF/lib, however Tomcat still throws the exception when running.

Here is the solution:

Check your "Problems" tab for warnings such as:

"Classpath entry org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER will not be exported or published. Runtime ClassNotFoundExceptions may result. "

You can achieve the same by selecting your project's properties->Deployment Assembly->Add->Java Build Path Entries.

Select the row corresponding to your project and perform a "Quick Fix" by right clicking it. Select "Mark the associated raw classpath entry as a publish/export dependencies."

Tuesday, February 22, 2011

Spring 3 & JMX

In this blog I will show you how to expose your POJOs as Managed Beans using Spring. I am assuming you are somewhat familiar with JMX, Spring, Maven, Tomcat and Java.

To expose your object as a managed bean in Tomcat, you need to register it with a MBeanServer. Spring easily allows you to do so using its config file.

Exposing your POJO as a managed bean

Here is an example of a POJO:

package com.mycompany.myapp.test;

public class TestManagedBean {

private String id;
private String name;

public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Before modifying your Spring context configuration file, edit your pom.xml to include Spring jar files required for JMX.

Here is my sample pom.xml:

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>3.0.0.RELEASE</spring.version>
</properties>

<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>


Modify your Spring context configuration file as follows. My file is called application-context.xml and is in ~myapp/src/main/resources/


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="com.mycompany.myapp"/>

<!-- this bean must not be lazily initialized if the exporting is to happen -->
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="registrationBehaviorName" value="REGISTRATION_REPLACE_EXISTING"/>
</bean>

<bean id="testBean" class="com.mycompany.myapp.test.TestManagedBean">
<property name="id" value="1"/>
<property name="name" value="Abc Def"/>
</bean>

</beans>


Accessing a managed bean

 
package com.mycompany.myapp.testjmx;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mycompany.myapp.test.TestManagedBean;

public class JmxTestClient {

public static void getMBeanServer() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
TestManagedBean service = context.getBean(TestManagedBean.class);

String name = service.getName();
System.out.println("Name = " + name);

}
}


You can now call JmxTestClient.getMBeanServer() to get access to the managed bean.

You can also use "jconsole" to view registered managed beans with Tomcat's MBeanServer. To do so, start Tomcat with "-Dcom.sun.management.jmxremote" option.
Run "jconsole" from command line. When it comes up, select and connect to "org.apache.catalina.startup.Bootstrap start" listed as a "Local Process". Click on the "MBeans" tab. You can find "jmxtest" listed under "Catalina/Manager".