package de.jpaw.bonaparte.hazelcast;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.hazelcast.config.SerializationConfig;
import com.hazelcast.nio.serialization.PortableFactory;
import com.hazelcast.nio.serialization.Portable;
import de.jpaw.bonaparte.core.BonaPortableClass;
/** Class to scan the class path and create factories as required. */
public class PortableFactoryBuilder extends AbstractScanner<BonapartePortable> {
static class BonapartePortableFactory implements PortableFactory {
private final ConcurrentHashMap<Integer, BonaPortableClass<BonapartePortable>> bclasses
= new ConcurrentHashMap<Integer, BonaPortableClass<BonapartePortable>>(256);
@Override
public Portable create(int classId) {
BonaPortableClass<BonapartePortable> bclass = bclasses.get(classId);
return bclass == null ? null : bclass.newInstance();
}
private void addClass(BonaPortableClass<BonapartePortable> bclass) {
BonaPortableClass<BonapartePortable> 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, BonapartePortableFactory> factoryMap
= new ConcurrentHashMap<Integer, BonapartePortableFactory>(16);
@Override
protected void addBClass(BonaPortableClass<BonapartePortable> bclass) {
Integer factoryId = bclass.getFactoryId(); // autobox only once
BonapartePortableFactory myFactory = factoryMap.get(factoryId);
if (myFactory == null) {
// create a new factory, the factoryId occurs the first time now
factoryMap.putIfAbsent(factoryId, new BonapartePortableFactory());
}
factoryMap.get(factoryId).addClass(bclass);
}
public void scanPackage(String packageName) {
scanPackage(packageName, BonapartePortable.class);
}
public void registerFactories(SerializationConfig cfg) {
for (Map.Entry<Integer, BonapartePortableFactory> e : factoryMap.entrySet()) {
LOGGER.info("Registering PortableFactory for Id {} with {} classes", e.getKey(), e.getValue().size());
cfg.addPortableFactory(e.getKey(), e.getValue());
}
}
}