5

In my application, I have two threads. Each thread communicates to different external entities.

Let us say T1 --> N1 & T2 --> N2 (T1 & T2 are two threads. N1 & N2 are external entities. Communications is SOAP over HTTPS.)

The vendor of N1 requested to use key store file UPCC_client.store for authentication and for the same we have used the following code,

System.setProperty("javax.net.ssl.keyStore", "<file path>");
System.setProperty("javax.net.ssl.keyStorePassword", "<password>");
System.setProperty("javax.net.ssl.trustStore","<file path>");
System.setProperty("javax.net.ssl.trustStorePassword", "<password>");

The application has been restarted with the above properties set in T1 thread with no issues. T2 started getting into trouble, since properties set by T1 are getting used by T2. The main reason behind this is System.setProperty is JVM scope. How to resolve this problem?

peterh
  • 11,875
  • 18
  • 85
  • 108
Hari
  • 397
  • 1
  • 9
  • 23

4 Answers4

23

I suspect you have a design issue to have this requirement however.

The only way around this is I can think of is to make your properties ThreadLocal.

public class ThreadLocalProperties extends Properties {
    private final ThreadLocal<Properties> localProperties = new ThreadLocal<Properties>() {
        @Override
        protected Properties initialValue() {
            return new Properties();
        }
    };

    public ThreadLocalProperties(Properties properties) {
        super(properties);
    }

    @Override
    public String getProperty(String key) {
        String localValue = localProperties.get().getProperty(key);
        return localValue == null ? super.getProperty(key) : localValue;
    }

    @Override
    public Object setProperty(String key, String value) {
        return localProperties.get().setProperty(key, value);
    }
}

// Make the properties thread local from here. This to be done globally once.
System.setProperties(new ThreadLocalProperties(System.getProperties()));

// in each thread.
System.setProperty("javax.net.ssl.keyStore", "my-key-store");

Unless there is any confusion, System.setProperties() doesn't just set properties, it replaces the collection, and its implementation.

// From java.lang.System
 * The argument becomes the current set of system properties for use
 * by the {@link #getProperty(String)} method.

public static void setProperties(Properties props) {
    SecurityManager sm = getSecurityManager();
    if (sm != null) {
        sm.checkPropertiesAccess();
    }
    if (props == null) {
        props = new Properties();
        initProperties(props);
    }
    System.props = props;
}

By using this method the behaviour of System Properties changes to being thread local for calls to setProperty() and getProperty()

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • That's not going to do much good by itself unless you synchronize the *use* of these properties. – user207421 Mar 06 '12 at 09:20
  • I assume you are not suggesting we need to synchronized access to thread local values. Can you clarify? – Peter Lawrey Mar 06 '12 at 09:35
  • When you pull the thread local properties into System properties you need to be synchronized so that another thread doesn't do that at the same time. – user207421 Mar 06 '12 at 09:37
  • System.setPropery in the last line of each thread sets the property JVM level. Moreover, it gets overridden also. I don't think this could help us. – Hari Mar 06 '12 at 09:42
  • 1
    @EJP I have edited my answer to explain why I don't think this is required. – Peter Lawrey Mar 06 '12 at 10:04
  • @Hari, Can you explain why setting thread specific properties wouldn't help? – Peter Lawrey Mar 06 '12 at 10:05
  • @Peter System.setProperty is JVM scope. System.setProperty("javax.net.ssl.keyStore", ""); sets the property in JVM level. The lines of code mentioned in my questions belong to same jvm process since T1 & T2 threads below to same instance. – Hari Mar 06 '12 at 10:13
  • 2
    @Hari That is the default behaviour for System Properties. The solution above changes the default behaviour so setting properties is thread local. i.e. if you change the value in one thread it won't change the value in another. – Peter Lawrey Mar 06 '12 at 10:37
  • @EJP, I fear my explanation left a bit too much to the imagination. ;) So thank you for trying to get clarification. – Peter Lawrey Mar 07 '12 at 07:58
5

I arrived here looking for a solution to set system properties per thread. I used @Peter Lawrey's excellent example above and it was just what I needed with one exception - my code needed to be run inside a servlet container (Tomcat), and as such I was obligated to be a good citizen and not alter the expected behavior of setProperty() for any other webapp running within the same JVM instance. To address this, I renamed Peter's setProperty() method to setLocalProperty():

    public Object setThreadLocalProperty(String key, String value) {
        return localProperties.get().setProperty(key, value);
    }

With this one change, the result is that a call to setProperty() will alter the property globally - which will be the desired behavior for other threads within the JVM. To alter the property for just the local thread, the call is instead made to setThreadLocalProperty().

In summary if you have full control over your application instance then Peter's code should work great for you. If however your application lives in a shared JVM - or if you have a need to otherwise "layer" system properties into global and thread-local, the one modification above should work for you.

paulk23
  • 465
  • 3
  • 6
1

There are programmatic ways to set the keystore and truststore, see the JSSE Reference Guide, but why exactly do you think you need different keystores and truststores at all? The truststore is a list of every CA you trust: is that really different in different contexts: and the keystore is your identity: is that really different in different contexts? and if so why?

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 1
    Yes, there are different key stores since there are different vendors. Each vendor has there own key store and it should be loaded into JVM. The property names used in setPropery are same for all vendors and this gets overridden. – Hari Mar 06 '12 at 09:41
0

I tried above threadlocal example and creating seperate keystone to refer in two different thread. But at a time one connection create and other failed with error wrong truststore.

Mpanwar
  • 11
  • 1