Thursday, September 27, 2012

java's double checked idiom


Ever since Josh Bloch's Effective Java book everyone has constantly been bring up Java memory model as something that doesn't work when trying to do double check. Example:

  public Helper getHelper() {
    if (helper == null) {
      synchronized(this) {
        if (helper == null) {
          helper = new Helper();
        }
      }
    }


There are lot's of entries saying that this test will only work if you use "volatile" when defining helper in the above example. Well I decided to try and get the concurrent error to actually occur. It appears that with Java 6 that this problem doesn't exist and that the double idiom check really does work. Here is my code example:



import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

public class ConcurrencyTest {
static class Lock {
private AtomicInteger ai = new AtomicInteger(0);
private Integer mutex;

public void reset() {
ai = new AtomicInteger(0);
mutex = null;
}

public Integer getMutex() {
if (mutex == null) {
synchronized (this) {
if (mutex == null) {
mutex = ai.getAndIncrement();
}
}
}
return mutex;
}

}

public static void main(String[] args) {
final AtomicInteger counter = new AtomicInteger(1);

final Lock key = new Lock();
final CyclicBarrier barrier = new CyclicBarrier(8, new Runnable() {

@Override
public void run() {
key.reset();
if (counter.getAndIncrement() % 10000 == 0) {
System.out.println("Reset Lock");
}
}
});

Thread[] threads = new Thread[8];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
barrier.await();
Integer i = key.getMutex();
if (i != 0) throw new IllegalStateException("Value was: " + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
}

for (Thread thread : threads) {
thread.start();
}

}
}

Tuesday, April 20, 2010

The Joys of Importing Data

In high school I had the worst job ever! A data entry job for some no-name company. It didn't take long for me to realize that I needed good grades because I didn't want to be doing data entry for the rest of my life.

When shopping for an online SaaS tool the important thing to look for is options. It is helpful to have different solutions to solve the same problem. One of the most painful parts of implementing a new system is migrating the data from the old to the new system. If you were asked to preform this migration, how would you do it? The last thing I would want to do is manually type in the data. There isn't always a perfect solution. What you choose today might not be feasible tomorrow. A coworker might want to take a completely different approach. A SaaS tool should support several ways to import data. Including:
  1. An API suite. If a SaaS tool doesn't have an API to their system then don't buy it. An API will allow a user to important anything and everything. It is the first thing a developer is going to look for data migration. It is the only way to reliably import terabytes of data.
  2. A toolbox full of tools. I'm comparing a toolbox to a host of different options for importing data into the system. An array of many one-off file import options. They allow a user to upload data using a comma separated value (CSV), spreadsheets, MS Project, and zip files. Tools are now integrating with email servers. Just email a document to an email address and it will be added to the system. Having a toolbox full of options to import data can turn a expensive data migration problem into a simple copy and paste. It's game over once you can reduce a complex operations into simple steps that you already know how to solve. The next time you are faced with the problem of trying to import data, ask yourself the question: Would you rather be looking for a developer or opening up an excel spreadsheet?
When you have a lot of options for importing data it allows you to streamline the process. Importing data will always be tedious and boring. Don't make it harder then it should be. When shopping for an online SaaS tool first look for an API and then look for a toolbox full of different options.

Monday, January 18, 2010

Connecting to a secure LDAP or Active Directory.

There are hundreds of blogs on how to connect to an AD/LDAP directory service, but there aren't a lot on how to connect to a secure one. Java's method for connecting to a secure directory services involves uses a keystore. If your requirements won't allow you to add the certifcate to your keystore then you'll need to dynamically create one using Java Code.

In my application I need authenticate against a user's directory service. It's a shared database setup and we need to be able to connect to hundreds of directory services. Because of this requirement it is impossible to manage the keystore on the app server and constantly add new certificates to them. You can dynamically use keystores; however, must customers don't know how to create them. Below are sudo instructions on how to create a tool that will allow you connect to a secure directory service when you are only given the certificate.



Let's get started...

You will need to implement your own SocketFactory and set it in the environment properties before you call "new InitialLdapContext".


environment.put("java.naming.ldap.factory.socket", "ldap.TestSocketFactory");

To create your "ldap.TestSocketFactory" you'll want to extend SocketFactory and implement the abstract methods. You'll also need to override the public static javax.net.SocketFactory getDefault() and have it return itself.

Example:
Public class TestSocketFactory extends SocketFactory{
private javax.net.SocketFactory _socketFactory;
public static javax.net.SocketFactory getDefault() {
return new TestSocketFactory();
}
public java.net.Socket createSocket() throws java.io.IOException {
return _socketFactory.createSocket();
}

public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
return _socketFactory.createSocket(s, i);
}

public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
return _socketFactory.createSocket(s, i, inetAddress, i1);
}

public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
return _socketFactory.createSocket(inetAddress, i);
}

public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
return _socketFactory.createSocket(inetAddress, i, inetAddress1, i1);
}
}

In your constructor you will need to do the following:

  • Initialize a new KeyStore and CertificateFactory objects
KeyStore store = KeyStore.getInstance("JKS");
store.load(null, "changeit".toCharArray());
CertificateFactory cf = CertificateFactory.getInstance("X.509");
  • Load the Certificate
String fileName = You'll need to load this from a property, or theadLocalVariable.
X509Certificate cert = (X509Certificate) cf.generateCertificate(new FileInputStream(new File(fileName)));
  • Convert the certificate to a KeyStore
File tempFile = File.createTempFile("certKey", null);
OutputStream out = new FileOutputStream(tempFile);
store.store(out, "changeit".toCharArray());
store.setCertificateEntry("alias", cert);
out.close();
  • Load the KeyStore
InputStream in = new FileInputStream(tempFile);
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(in, "changeit".toCharArray());
in.close();
  • Create the SocketFactory
TrustManagerFactory trustMnagerFactory = TrustManagerFactory.getInstance(SECURE_ALGORITHM);
trustMnagerFactory.init(keyStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(SECURE_ALGORITHM);
keyManagerFactory.init(keyStore, SSODelegate.CERTIFICATE_PASSWORD.toCharArray());
SSLContext sslc = SSLContext.getInstance(SECURE_PROTOCOL);
sslc.init(keyManagerFactory.getKeyManagers(), trustMnagerFactory.getTrustManagers(), new SecureRandom());
_socketFactory = sslc.getSocketFactory();
If you want to ignore validation on the certificate you can do the follow when you are creating the SocketFactory
sslc.init(keyManagerFactory.getKeyManagers(), getOverrideTrustManager(), new SecureRandom());

public static TrustManager[] getOverrideTrustManager() {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}

public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}

public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
return trustAllCerts;
}

Saturday, November 14, 2009

JBoss 5

I've recently migrated AtTask from JBoss 4 to JBoss 5. We've were running on JBoss 4 for the past 2 years and we want to take advantage of the new rewrite of JBoss Messaging, JBossMQ has problems and we are hoping JBoss Messaging solves these problems. What I can't figure out is why in JBoss 5 the server peer id must be set for every node. Why can't JBoss automatically generate a unique id. I know in JBoss 4 I didn't have the set the server peer id. The other thing that is frustrating is this unique server peer id has to been queue across the LAN. We have two clusters on the same LAN with different cluster partitions and they won't work unless every node has a unique server peer id.