package de.jpaw.bonaparte.hazelcast;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.reflections.Reflections;
import com.hazelcast.config.SerializationConfig;
import com.hazelcast.nio.serialization.DataSerializableFactory;
import com.hazelcast.nio.serialization.IdentifiedDataSerializable;
import de.jpaw.bonaparte.core.BonaPortableClass;
/** Class to scan the class path and create factories as required. */
public class IdentifiedDataSerializableFactoryBuilder extends AbstractScanner<BonaparteIdentifiedDataSerializable> {
static class BonaparteIdentifiedDataSerializableFactory implements DataSerializableFactory {
private final ConcurrentHashMap<Integer, BonaPortableClass<BonaparteIdentifiedDataSerializable>> bclasses
= new ConcurrentHashMap<Integer, BonaPortableClass<BonaparteIdentifiedDataSerializable>>(256);
@Override
public IdentifiedDataSerializable create(int classId) {
BonaPortableClass<BonaparteIdentifiedDataSerializable> bclass = bclasses.get(classId);
return bclass == null ? null : bclass.newInstance();
}
private void addClass(BonaPortableClass<BonaparteIdentifiedDataSerializable> bclass) {
BonaPortableClass<BonaparteIdentifiedDataSerializable> old = bclasses.putIfAbsent(bclass.getId(), bclass);
if (old != null && old != bclass) {
LOGGER.error("duplicate factoryId {} / classId {} for {} and {}", bclass.getFactoryId(), bclass.getId(), old.getPqon(), bclass.getPqon());
throw new RuntimeException("Duplicate factory / class ID");
}
}
private int size() {
return bclasses.size();
}
}
private final ConcurrentHashMap<Integer, BonaparteIdentifiedDataSerializableFactory> factoryMap
= new ConcurrentHashMap<Integer, BonaparteIdentifiedDataSerializableFactory>(16);
@Override
protected void addBClass(BonaPortableClass<BonaparteIdentifiedDataSerializable> bclass) {
Integer factoryId = bclass.getFactoryId(); // autobox only once
BonaparteIdentifiedDataSerializableFactory myFactory = factoryMap.get(factoryId);
if (myFactory == null) {
// create a new factory, the factoryId occurs the first time now
factoryMap.putIfAbsent(factoryId, new BonaparteIdentifiedDataSerializableFactory());
}
factoryMap.get(factoryId).addClass(bclass);
}
public void scanPackage(String packageName) {
scanPackage(packageName, BonaparteIdentifiedDataSerializable.class);
}
public void scanPackage(Reflections ... reflections) {
scanPackage(BonaparteIdentifiedDataSerializable.class, reflections);
}
public void registerFactories(SerializationConfig cfg) {
for (Map.Entry<Integer, BonaparteIdentifiedDataSerializableFactory> e : factoryMap.entrySet()) {
LOGGER.info("Registering DataSerializableFactory for Id {} with {} classes", e.getKey(), e.getValue().size());
cfg.addDataSerializableFactory(e.getKey(), e.getValue());
}
}
}