Samstag, 24. Januar 2015

Working with a transaction in JACIS...

Working with a transaction in JACIS is as simple as follows:

JacisContainer container = new JacisContainer();
JacisObjectTypeSpec<String, Account> objectTypeSpec =  
                 new JacisObjectTypeSpec<>(String.class, Account.class);
JacisStore<String, Account> store = container.createStore(objectTypeSpec);
container.withLocalTx(() -> {
    Account acc = store.get("account1");
    acc.deposit(100);
    store.update("account1", acc);
});

For more details see: https://github.com/JanWiemer/jacis/wiki...

Dienstag, 20. Januar 2015

Freitag, 19. April 2013

Indexable HashMap Implementation

Recently I needed a hash map with some sort of indexed access. I searched for a solution and wondered that I found nothing. Maybe my implementation can save sombody else some work:


import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

public class IndexableHashMap<K, V> extends java.util.HashMap<K, V> {

  private static final long serialVersionUID = 1L;

  public static <K, V> IndexableHashMap<K, V> unmodifiable(IndexableHashMap<K, V> map) {
    return map.setImmutable(true);
  }

  private boolean immutable;
  private Map<MapIndex<?, V>, Multimap<Object, V>> idxMap; // immutable

  public IndexableHashMap(MapIndex<?, V>... indexes) {
    this(Arrays.asList(indexes));
  }

  public IndexableHashMap(Collection<MapIndex<?, V>> indexes) {
    init(indexes);
  }

  private void init(Collection<MapIndex<?, V>> indexes) {
    Map<MapIndex<?, V>, Multimap<Object, V>> newIdxMap = new HashMap<>();
    for (MapIndex<?, V> index : indexes) {
      Multimap<Object, V> idxKey2Val = ArrayListMultimap.create();
      newIdxMap.put(index, idxKey2Val);
    }
    idxMap = Collections.unmodifiableMap(newIdxMap);
  }

  private IndexableHashMap<K, V> setImmutable(boolean immutable) {
    this.immutable = immutable;
    return this;
  }

  private void checkMutable() {
    if (immutable) {
      throw new UnsupportedOperationException("IndexableHashMap " + this + " is immutable!");
    }
  }

  @Override
  public V put(K key, V value) {
    checkMutable();
    for (Map.Entry<MapIndex<?, V>, Multimap<Object, V>> e : idxMap.entrySet()) {
      Object idxKey = e.getKey().val2IdxKey(value);
      e.getValue().put(idxKey, value);
    }
    return super.put(key, value);
  }

  @Override
  public void putAll(Map<? extends K, ? extends V> m) {
    checkMutable();
    // since Java8 we can no no longer delegate to super...
    for (java.util.Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
      put(entry.getKey(), entry.getValue());
    }
  }


  @Override
  public V remove(Object key) {
    checkMutable();
    V removed = super.remove(key);
    for (Map.Entry<MapIndex<?, V>, Multimap<Object, V>> e : idxMap.entrySet()) {
      Object idxKey = e.getKey().val2IdxKey(removed);
      e.getValue().remove(idxKey, removed);
    }
    return removed;
  }

  @Override
  public void clear() {
    checkMutable();
    for (Multimap<Object, V> idxVals : idxMap.values()) {
      idxVals.clear();
    }
    super.clear();
  }

  public Set<MapIndex<?, V>> getIndices() {
    return idxMap.keySet();
  }

  public <IK> Collection<V> getByIdx(MapIndex<?, V> index, IK idxKey) {
    return idxMap.get(index).get(idxKey);
  }

  public <IK> V getByUniqueIdx(MapIndex<?, V> idx, IK idxKey) {
    Collection<V> vals = getByIdx(idx, idxKey);
    if (vals == null || vals.isEmpty()) {
      return null;
    } else if (vals.size() == 1) {
      return vals.iterator().next();
    } else if (!idx.isUnique()) {
      throw new IllegalArgumentException("Index " + idx + " not unique! Values for key " + idxKey + ": " + vals);
    } else {
      throw new IllegalStateException("Multiple values found for unique index " + idx + "! Values for key " + idxKey + ": " + vals);
    }
  }

  public static abstract class MapIndex<IK, V> {
    private final boolean unique;

    public MapIndex(boolean unique) {
      this.unique = unique;
    }

    protected abstract IK val2IdxKey(V value);

    public boolean isUnique() {
      return unique;
    }

    @Override
    public String toString() {
      return getClass().getSimpleName();
    }
  }

}


Usage:

  public static class PrefixIndex extends MapIndex<String, String> {
    private final int prefixLength;

    public PrefixIndex(int prefixLength) {
      super(false);
      this.prefixLength = prefixLength;
    }

    @Override
    protected String val2IdxKey(String value) {
      return value == null ? "" : value.substring(0, Math.min(prefixLength, value.length()));
    }

  }

  @Test
  public void testUsingIndex() {
    PrefixIndex index = new PrefixIndex(1);
    IndexableHashMap<String, String> map = new IndexableHashMap<String, String>(index);
    map.put("Key1", "AX-Val");
    map.put("Key2", "BY-Val");
    map.put("Key3", "BZ-Val");
    assertEquals("AX-Val", map.get("Key1"));
    assertEquals("BY-Val", map.get("Key2"));
    assertEquals("BZ-Val", map.get("Key3"));
    assertEquals(1, map.getByIdx(index, "A").size());
    assertEquals(2, map.getByIdx(index, "B").size());
  }


Freitag, 3. Februar 2012

Hessian Wrapper to Enable Context Propagation

One advantage od the hessian protocol (compared e.g. with pure RMI) is that it is able to propagate implicite context information together with a remote call. However there are a few things to prepare in order to use this feature:

First we need an extension of the HessianProxy passing context information to the request header.

public class HessianProxyWithContext extends HessianProxy {
 private static final long serialVersionUID = 1L;
 private Map context = new HashMap();
 public HessianProxyWithContext(URL url, HessianProxyFactory factory, Class type) {
  super(url, factory, type);
 }
 public HessianProxyWithContext(URL url, HessianProxyFactory factory) {
  super(url, factory);
 }
 void setContext(Map context) {
  this.context = context;
 }
 protected void addRequestHeaders(HessianConnection conn) {
  super.addRequestHeaders(conn);
  for (Entry e : context.entrySet()) {
   conn.addHeader(e.getKey(), e.getValue());
  }
 }
}

Then we need an extension of the factory using our new Proxy class:

public class HessianProxyWithContextFactory extends HessianProxyFactory {
 private Map context = new HashMap();
 public Map getContext() {
  return context;
 }
 public String putContext(String key, String value) {
  return context.put(key, value);
 }
 public Object create(Class api, URL url, ClassLoader loader) {
  if (api == null)
   throw new NullPointerException("api must not be null for HessianProxyFactory.create()");
  HessianProxyWithContext handler = new HessianProxyWithContext(url, this, api);
  handler.setContext(context);
  return Proxy.newProxyInstance(loader, new Class[] { api, HessianRemoteObject.class }, handler);
 }
}

Note that the context information can be set at the factory for the next call.
Finally we have to extract the context information from the request header at the server.
For this purpose we need to access the servlet request.
To achive this we use a little extension of the HessianServlet class:

public class HessianServletWithContext extends HessianServlet {
 private static final long serialVersionUID = 1L;
 private ServletRequest request = null;
 @Override
 public void service(ServletRequest req, ServletResponse response) throws IOException, ServletException {
  request = req;
  super.service(req, response);
 }
 public String getContext(String key) {
  String value = null;
  if(request instanceof HttpServletRequest) {
   value = ((HttpServletRequest) request).getHeader(key);
  }
  return value;
 }
}

Basically this was all we need. The following example shows how to use the little wrapper:
public interface TestInterface {
 public String echoContext(String call);
}
public class TestEndpoint extends HessianServletWithContext implements TestInterface {
 private static final long serialVersionUID = 1L;
 public String echoContext(String contextKey) {
  return contextKey +"="+ getContext(contextKey);
 }
}
public class ClientTest {
    private TestInterface test;
    @Before
    public void initProxy() throws MalformedURLException {
        String url = "http://localhost:8080/test/TestInterface";
        HessianProxyWithContextFactory factory = new HessianProxyWithContextFactory();
        factory.putContext("contextKey", "contextValue"); 
        test = (TestInterface) factory.create(TestInterface.class, url);
    }
    @Test
    public void echoContext() {
      System.out.println(test.echoContext("unknown"));
      System.out.println(test.echoContext("contextKey"));
    }
}

Donnerstag, 2. Februar 2012

Firewall Friendly RMI Port Fixing

Although it probably makes little difference its often required to keep the number of ports allowed by a firewall as small as possible. By default RMI determines dynamically which port to use for communication. One way to define the port that shall be used for communication is to define it when exporting the remote object. Another less invasive way is to set a custom RMISocketFactory like the following one:

public class CustomRmiSocketFactory extends RMISocketFactory {
  private static RMISocketFactory delegate = RMISocketFactory.getDefaultSocketFactory();
  public static void register(int customPort) throws IOException {
     RMISocketFactory.setSocketFactory(new CustomRmiSocketFactory(customPort));
  }
  private final int customPort; 
  private CustomRmiSocketFactory(int customPort) {
    this.customPort = customPort;
  }
  public Socket createSocket(String host, int port) throws IOException {
    return delegate.createSocket(host, port);
  }
  public ServerSocket createServerSocket(int port) throws IOException { // 0 means arbitrary port
    return delegate.createServerSocket(port!=0 ? port : customPort); 
  }
  public int hashCode() {
    return customServerSocketPort;
  }
  public boolean equals(Object obj) {
    return (getClass() == obj.getClass() && customPort == ((CustomRmiSocketFactory) obj).customPort);
  }
}


As fas as you ensure the register method is calles as early as possible in your application (e.g. in an static initializer in your main class) this works quite well. All RMI communication uses the predefined (server) port.

One unexpected and nasty thing happens when you use this in connection with JMX. If you start your application with the usual JMX options the JMX agent already initializes RMI and chooses a port befor any class of your application is loaded. In order to keep RMI only taking the defined port you either have to provice jour own JMX agent (wich first sets the factory) or start the JMX agent programatically in jour application (after setting the RMISocketFactory).

Dienstag, 13. Dezember 2011

When the timeout fails in Thread.join

There is a little danger using the join with a timeout. The implementation will call a wait on the thread instance. For this purpose the calling thread A has to get the monitor on the thread B he wants to join. During the wait this monitor is suspended, but after the wait the thread has to enter the monitor again. If now the thread B obtains the monitor itself and holds it for a long time (forever), the timeout of the wait method (inside the join) may be finished, but the monitor can not be regained after the wait. Therefore the thread A will stuck in the join method for a long time (forever) even with the timeout...

public class Test {

  private static final String DATE_PATTERN = "HH:mm:ss.SSS";
  public static FastDateFormat DATE_FORMAT = FastDateFormat.getInstance(DATE_PATTERN);

  public static String time() {
    return DATE_FORMAT.format(new Date());
  }

  public static void doSleep(long ms) {
    try {
      Thread.sleep(ms);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
  }

  public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread() {
      @Override
      public void run() {
        System.out.println(time() + " T: sleep(2000)");
        doSleep(2000);
        System.out.println(time() + " T: sleep(2000) finished");
        System.out.println(time() + " T: sync");
        synchronized (this) {
          System.out.println(time() + " T: sleep(60000)");
          doSleep(60000);
          System.out.println(time() + " T: sleep(60000) finished");
        }
        System.out.println(time() + " T: finished");
      }
    };
    System.out.println(time() + " M: t.start()");
    t.start();
    System.out.println(time() + " M: t.join(5000)");
    t.join(5000);
    System.out.println(time() + " M: finished");
  }
}

Mittwoch, 25. Mai 2011

Configuration Parameter Injection with CDi

CDI Based Configuration

I experimented with a simple possibility to inject parameter values, that can easily configured by external configuration providers.
At the injection point it should be possible to provide default values used if the parameters are not set.
All parameters are referenced by names. The default name of a parameter is the simple class name followed by a dot and the name of the injection point.
It should be possible to overwrite the name of the parameter.
The usage of the parameters should look like the following example:

@Named @RequestScoped public class ExampleBean {

 @Inject @StringParameter("Default Title") String title;
 @Inject @IntParameter(42) int value;
 @Inject @IntParameter(4711) int valueWithDefault;
 @Inject @StringParameter(name="customParamName",value="Default Value") String namedParameter;
 
 //... getters omitted
} 
  

The definition of the parameter uses one of the following qualifier annotations:

@Inherited
@Qualifier
@Target({java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.FIELD })
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
public @interface StringParameter {
 @Nonbinding String name() default "";
 @Nonbinding String value() default ""; // parameter default value
}
  

@Inherited
@Qualifier
@Target({java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.FIELD })
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
public @interface IntParameter {
 @Nonbinding String name() default "";
 @Nonbinding int value() default 0; // parameter default value
}
  

Both qualifiers provide an optional default value and an optional custom name.
The producer method for the injected parameters accesses the injection point to
read the default value and the name from the qualifier annotation of the parameter:


  @javax.inject.Singleton public class ParameterProducer {
 
   private Map<String, Integer> paramMapInt;
 private Map<String, String> paramMapString;
 
   @SuppressWarnings("unchecked") private <T extends Annotation> T getQualifier(Set<Annotation> annotations, Class<T> clazz) {
  for (Annotation qualifier : annotations) {
   if (qualifier.annotationType().equals(clazz)) {
    return (T) qualifier;
   }
  }
  return null;
 }

 @Produces @IntParameter public int createIntegerParameter(InjectionPoint ip) {
  IntParameter qualifier = getQualifier(ip.getQualifiers(), IntParameter.class);
  String parameterName = qualifier.name();
  if (parameterName == null || parameterName.isEmpty()) {
   parameterName = ip.getMember().getDeclaringClass().getSimpleName() + "." + ip.getMember().getName();
  }
  Integer configuredValue = paramMapInt.get(parameterName);
  if (configuredValue != null) {
   return configuredValue;
  } else {
   return qualifier.value();
  }
 }

 @Produces @StringParameter public String createStringParameter(InjectionPoint ip) {
  StringParameter qualifier = getQualifier(ip.getQualifiers(), StringParameter.class);
  String parameterName = qualifier.name();
  if (parameterName == null || parameterName.isEmpty()) {
   parameterName = ip.getMember().getDeclaringClass().getSimpleName() + "." + ip.getMember().getName();
  }
  String configuredValue = paramMapString.get(parameterName);
  if (configuredValue != null) {
   return configuredValue;
  } else {
   return qualifier.value();
  }
 }

  }
  

The configured parameters shall be configured by configuration providers implementing the following interface:


public interface ParameterProvider {
 
 public Map<String, Integer> getIntParameters();

 public Map<String, String> getStringParameters();

}
  

An example of a configuration provider using some hard coded values could be:


public class HardCodedParameterProvider implements ParameterProvider {

 
 @Override public Map<String, Integer> getIntParameters() {
  Map<String, Integer> params = new HashMap<String, Integer>();
  params.put("ExampleBean.value", 4711007);
  return params;
 }

 @Override public Map<String, String> getStringParameters() {
  Map<String, String> params = new HashMap<String, String>();
  params.put("ExampleBean.title", "Hello from Configuration Provider: "+this.getClass().getSimpleName());
  params.put("customParamName", "Configured-Parameter-Value");
  return params;
 }

}
  


To add the values of all found parameter providers we have to add some lines to the parameter producer:


  @javax.inject.Singleton public class ParameterProducer {
   
     @Inject Instance<ParameterProvider> parameterProviders;
   
     //...
     
 @PostConstruct public void init() {
  initParameters();
 }

 private void initParameters() {
  paramMapInt = new HashMap<String, Integer>();
  paramMapString = new HashMap<String, String>();
  for (ParameterProvider provider : parameterProviders) {
   Map<String, Integer> intParams = provider.getIntParameters();
   if (intParams != null) {
    paramMapInt.putAll(intParams);
   }
   Map<String, String> stringParams = provider.getStringParameters();
   if (stringParams != null) {
    paramMapString.putAll(stringParams);
   }
  }
 }

  }
  

To further play around with the system we add the possibility to maintain the configuration via JMX.
Therefore we make the parameter provider a managed bean by implementing the interface:


public interface ParameterMonitoringMXBean {

 public Map getIntegerParameters();

 public Map getStringParameters();

 public Integer getIntegerParameter(String parameterName);
 
 public String getStringParameter(String parameterName) ;
 
 public void setIntegerParameter(String parameterName, Integer value);
 
 public void setStringParameter(String parameterName, String value);

 public void resetIntegerParameter(String parameterName);
 
 public void resetStringParameter(String parameterName);

}
  

Furthermore we have to register the managed bean at the managed bean server:


@javax.inject.Singleton public class ParameterProducer implements ParameterMonitoringMXBean {

 @PostConstruct public void init() {
  initParameters();
  registerMxBean();
 }

 protected void registerMxBean() {
  try {
   MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
   ObjectName name = new ObjectName("com.jaw.cfg:type=Configuration");
   if (mbs.isRegistered(name)) {
    mbs.unregisterMBean(name);
   }
  } catch (Exception e) {
   throw new RuntimeException(e);
  }
 }

}
  

Of course the managed bean interface has to be implemented. Here we show only two methods as examples:


@javax.inject.Singleton public class ParameterProducer implements ParameterMonitoringMXBean {

 public Map<String, String> getStringParameters() {
  return paramMapString;
 }

 public void setStringParameter(String parameterName, String value) {
  paramMapString.put(parameterName, value);
 }

}
  

Now its possible to view and manipulate the configuration of the parameters e.g. using the MBeans view in the jConsole.
One last step is to provide the possibility to observe an event indicating a parameter changed via JMX:


public class ParameterChanged {

 private String parameterName;
 private Object oldValue;
 private Object newValue;

 public ParameterChanged(String parameterName, Object oldValue, Object newValue) {
  this.parameterName = parameterName;
  this.oldValue = oldValue;
  this.newValue = newValue;
 }

   // ... getters and setters omitted...

}
  

All JMX methods changing an parameter have to fire the event:


@javax.inject.Singleton public class ParameterProducer implements ParameterMonitoringMXBean {

 @Inject Event<ParameterChanged> parameterChangedEvent;

 public void sendParameterChanged(String parameterName, Object oldValue, Object newValue) {
  Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
  parameterChangedEvent.fire(new ParameterChanged(parameterName, oldValue, newValue));
 }


 public void setStringParameter(String parameterName, String value) {
  sendParameterChanged(parameterName, paramMapString.get(parameterName), value);
  paramMapString.put(parameterName, value);
 }

}
  

Note that setting the context class loader before sending the event is needed, because by default JMX uses another class loader than the application.
An example client observing the fired event may look like:


  @Singleton public class ParameterChangeListener {

 @Inject Logger log; // from somewhere...
 
 public void onParameterChange(@Observes ParameterChanged pc) {
  log.info("parameter "+pc.getParameterName()+" changed from "+pc.getOldValue()+" to "+pc.getNewValue());
 }
  

Note that the observer method must not be defined at session or request scope since JMX calls do not create a
context for these scopes.