package org.openntf.domino.graph2.impl; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.openntf.domino.Document; //import javolution.util.FastMap; import org.openntf.domino.graph2.DElementStore; import org.openntf.domino.graph2.DKeyResolver; import org.openntf.domino.graph2.annotations.AdjacencyUnique; import org.openntf.domino.graph2.annotations.AnnotationUtilities; import org.openntf.domino.graph2.annotations.IncidenceUnique; import org.openntf.domino.graph2.annotations.Shardable; import org.openntf.domino.graph2.annotations.TypedProperty; import org.openntf.domino.graph2.builtin.CategoryVertex; import org.openntf.domino.graph2.builtin.DEdgeFrame; import org.openntf.domino.graph2.builtin.DVertexFrame; import org.openntf.domino.graph2.builtin.ViewVertex; import org.openntf.domino.types.CaseInsensitiveString; import org.openntf.domino.utils.TypeUtils; import com.tinkerpop.blueprints.Edge; import com.tinkerpop.blueprints.Element; import com.tinkerpop.blueprints.Vertex; import com.tinkerpop.frames.Adjacency; import com.tinkerpop.frames.ClassUtilities; import com.tinkerpop.frames.EdgeFrame; import com.tinkerpop.frames.FrameInitializer; import com.tinkerpop.frames.FramedGraph; import com.tinkerpop.frames.FramedGraphConfiguration; import com.tinkerpop.frames.InVertex; import com.tinkerpop.frames.Incidence; import com.tinkerpop.frames.OutVertex; import com.tinkerpop.frames.Property; import com.tinkerpop.frames.VertexFrame; import com.tinkerpop.frames.modules.AbstractModule; import com.tinkerpop.frames.modules.Module; import com.tinkerpop.frames.modules.typedgraph.TypeField; import com.tinkerpop.frames.modules.typedgraph.TypeManager; import com.tinkerpop.frames.modules.typedgraph.TypeRegistry; import com.tinkerpop.frames.modules.typedgraph.TypeValue; import com.tinkerpop.frames.modules.typedgraph.TypedGraphModuleBuilder; import com.tinkerpop.frames.util.Validate; public class DConfiguration extends FramedGraphConfiguration implements org.openntf.domino.graph2.DConfiguration { @SuppressWarnings("unused") private static final Logger log_ = Logger.getLogger(DConfiguration.class.getName()); public static class DTypedGraphModuleBuilder extends TypedGraphModuleBuilder { private DTypeRegistry localTypeRegistry_; private DTypeManager localManager_; private DConfiguration config_; public DTypedGraphModuleBuilder(final DConfiguration config) { config_ = config; getTypeRegistry().add(DEdgeFrame.class); getTypeRegistry().add(DVertexFrame.class); } @Override public TypedGraphModuleBuilder withClass(final Class<?> type) { getTypeRegistry().add(type); return this; } @Override public Module build() { return new AbstractModule() { @Override public void doConfigure(final FramedGraphConfiguration config) { config.addTypeResolver(getTypeManager()); } }; } public DTypeRegistry getTypeRegistry() { if (localTypeRegistry_ == null) { localTypeRegistry_ = new DTypeRegistry(config_); } return localTypeRegistry_; } public DTypeManager getTypeManager() { if (localManager_ == null) { localManager_ = new DTypeManager(getTypeRegistry()); } return localManager_; } } public static class DTypeRegistry extends TypeRegistry { private Map<Class<?>, Map<CaseInsensitiveString, Method>> getterMap_ = new LinkedHashMap<Class<?>, Map<CaseInsensitiveString, Method>>(); private Map<Class<?>, Map<CaseInsensitiveString, Method>> counterMap_ = new LinkedHashMap<Class<?>, Map<CaseInsensitiveString, Method>>(); private Map<Class<?>, Map<CaseInsensitiveString, Method>> finderMap_ = new LinkedHashMap<Class<?>, Map<CaseInsensitiveString, Method>>(); private Map<Class<?>, Map<CaseInsensitiveString, Method>> adderMap_ = new LinkedHashMap<Class<?>, Map<CaseInsensitiveString, Method>>(); private Map<Class<?>, Map<CaseInsensitiveString, Method>> removerMap_ = new LinkedHashMap<Class<?>, Map<CaseInsensitiveString, Method>>(); private Map<Class<?>, Map<CaseInsensitiveString, Method>> setterMap_ = new LinkedHashMap<Class<?>, Map<CaseInsensitiveString, Method>>(); private Map<Class<?>, Map<CaseInsensitiveString, Method>> incidenceMap_ = new LinkedHashMap<Class<?>, Map<CaseInsensitiveString, Method>>(); private Map<Class<?>, Method> inMap_ = new LinkedHashMap<Class<?>, Method>(); private Map<Class<?>, Method> outMap_ = new LinkedHashMap<Class<?>, Method>(); private Map<String, String> simpleNameMap_ = new HashMap<String, String>(); private Map<String, Class<?>> localTypeMap_ = new HashMap<String, Class<?>>(); private Map<DElementStore, TypeRegistry> storeTypeMap_ = new HashMap<DElementStore, TypeRegistry>(); private DConfiguration config_; public DTypeRegistry(final DConfiguration config) { config_ = config; } @Override public Class<?> getType(final Class<?> typeHoldingTypeField, final String typeValue) { // System.out.println("TEMP DEBUG Attempting to resolve type name " + typeValue); Class<?> result = super.getType(typeHoldingTypeField, typeValue); if (result == null) { result = findClassByName(typeValue); // System.out.println("TEMP DEBUG Falling back to local map for typeValue " + typeValue + " resulting in " // + String.valueOf(result)); } return result; } public Class<?> getType(final Class<?> typeHoldingTypeField, final String typeValue, final Element elem) { Class<?> result = null; DGraph graph = config_.getGraph(); DElementStore store = graph.findElementStore(elem); TypeRegistry reg = storeTypeMap_.get(store); // System.out.println("TEMP DEBUG Attempting to resolve type name " + typeValue + " with an element"); if (reg == null) { result = getType(typeHoldingTypeField, typeValue); } else { // System.out.println("TEMP DEBUG Using local element store registry " + reg.toString()); result = reg.getType(typeHoldingTypeField, typeValue); } if (result == null) { result = findClassByName(typeValue); } return result; } @Override public Class<?> getTypeHoldingTypeField(final Class<?> type) { if (type == null) { throw new IllegalArgumentException("Cannot pass a null type to getTypeHoldingTypeField"); } Class<?> result = super.getTypeHoldingTypeField(type); if (result == null) { Class<?> doublechk = findTypeHoldingTypeField(type); if (doublechk != null) { result = doublechk; } else { // System.out.println("TEMP DEBUG: Double check failed too?"); } } return result; } public Class<?> findClassByName(final String name) { if (name == null || name.length() < 1) return null; for (Class<?> klazz : typeDiscriminators.values()) { if (klazz.getName().equals(name) || klazz.getSimpleName().equalsIgnoreCase(name)) return klazz; } Class<?> result = localTypeMap_.get(name); if (result != null) { return result; } String fullName = simpleNameMap_.get(name); if (fullName != null) { result = localTypeMap_.get(fullName); if (result != null) { return result; } } throw new IllegalArgumentException("No class for " + name + " found in TypeRegistry"); } @Override protected Class<?> findTypeHoldingTypeField(final Class<?> type) { Class<?> typeHoldingTypeField = type.getAnnotation(TypeField.class) == null ? null : type; for (Class<?> parentType : type.getInterfaces()) { Class<?> parentTypeHoldingTypeField = findTypeHoldingTypeField(parentType); Validate.assertArgument(parentTypeHoldingTypeField == null || typeHoldingTypeField == null || parentTypeHoldingTypeField == typeHoldingTypeField, "You have multiple TypeField annotations in your class-hierarchy for %s", type.getName()); if (typeHoldingTypeField == null) typeHoldingTypeField = parentTypeHoldingTypeField; } return typeHoldingTypeField; } @Override public TypeRegistry add(final Class<?> type) { Validate.assertArgument(type.isInterface(), "Not an interface: %s", type.getName()); Class<?> typeHoldingTypeField = findTypeHoldingTypeField(type); try { super.add(type); String simpleName = type.getSimpleName(); if (!simpleNameMap_.containsKey(simpleName)) { simpleNameMap_.put(simpleName, type.getName()); } localTypeMap_.put(type.getName(), type); addProperties(type); // System.out.println("TEMP DEBUG Adding type " + type.getName() + " to registry"); } catch (Throwable t) { t.printStackTrace(); } for (Class<?> subtype : type.getClasses()) { Annotation annChk = subtype.getAnnotation(TypeValue.class); if (annChk != null && subtype.isInterface()) { add(subtype); // System.out.println("TEMP DEBUG: TypeHoldingField from " + this.getTypeHoldingTypeField(subtype)); } } return this; } public TypeRegistry add(final Class<?> type, final DElementStore store) { Validate.assertArgument(type.isInterface(), "Not an interface: %s", type.getName()); Class<?> typeHoldingTypeField = findTypeHoldingTypeField(type); TypeRegistry reg = storeTypeMap_.get(store); if (reg == null) { reg = new TypeRegistry(); storeTypeMap_.put(store, reg); } try { reg.add(type); String simpleName = type.getSimpleName(); if (!simpleNameMap_.containsKey(simpleName)) { simpleNameMap_.put(simpleName, type.getName()); } localTypeMap_.put(type.getName(), type); addProperties(type); // System.out.println("TEMP DEBUG Adding type " + type.getName() + " to registry"); } catch (Throwable t) { t.printStackTrace(); } for (Class<?> subtype : type.getClasses()) { Annotation annChk = subtype.getAnnotation(TypeValue.class); if (annChk != null && subtype.isInterface()) { add(subtype); } } return reg; } // public String getTypeNamesForFrame(final Object element) { // StringBuilder sb = new StringBuilder(); // for (Class<?> klazz : getTypesForFrame(element)) { // sb.append(klazz.getSimpleName()); // sb.append(','); // } // return sb.toString(); // } public Class<?>[] getTypesForFrame(final Object element) { return element.getClass().getInterfaces(); } public Class<?> getInType(final Class<?> type) { Method crystal = getIn(type); if (crystal != null) { return crystal.getReturnType(); } return null; } public Class<?> getOutType(final Class<?> type) { Method crystal = getOut(type); if (crystal != null) { return crystal.getReturnType(); } return null; } public Method getIn(final Class<?> type) { return inMap_.get(type); } public Method getOut(final Class<?> type) { return outMap_.get(type); } public Map<CaseInsensitiveString, Method> getPropertiesGetters(final Class<?> type) { Map<CaseInsensitiveString, Method> result = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> crystals = getterMap_.get(type); if (crystals != null) { result.putAll(crystals); } Class<?>[] inters = type.getInterfaces(); for (Class<?> inter : inters) { crystals = getterMap_.get(inter); if (crystals != null) { result.putAll(crystals); } } return result; } public Map<CaseInsensitiveString, Method> getCounters(final Class<?> type) { Map<CaseInsensitiveString, Method> result = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> crystals = counterMap_.get(type); if (crystals != null) { result.putAll(crystals); } Class<?>[] inters = type.getInterfaces(); for (Class<?> inter : inters) { crystals = counterMap_.get(inter); if (crystals != null) { result.putAll(crystals); } } return Collections.unmodifiableMap(result); } public Map<CaseInsensitiveString, Method> getIncidences(final Class<?> type) { Map<CaseInsensitiveString, Method> result = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> crystals = incidenceMap_.get(type); if (crystals != null) { result.putAll(crystals); } Class<?>[] inters = type.getInterfaces(); for (Class<?> inter : inters) { crystals = incidenceMap_.get(inter); if (crystals != null) { result.putAll(crystals); } } return Collections.unmodifiableMap(result); } public Map<CaseInsensitiveString, Method> getAdders(final Class<?> type) { Map<CaseInsensitiveString, Method> result = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> crystals = adderMap_.get(type); if (crystals != null) { result.putAll(crystals); } Class<?>[] inters = type.getInterfaces(); for (Class<?> inter : inters) { crystals = adderMap_.get(inter); if (crystals != null) { result.putAll(crystals); } } return Collections.unmodifiableMap(result); } public Map<CaseInsensitiveString, Method> getPropertiesSetters(final Class<?> type) { Map<CaseInsensitiveString, Method> result = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> crystals = setterMap_.get(type); if (crystals != null) { result.putAll(crystals); } Class<?>[] inters = type.getInterfaces(); for (Class<?> inter : inters) { crystals = setterMap_.get(inter); if (crystals != null) { result.putAll(crystals); } } return Collections.unmodifiableMap(result); } public void addProperties(final Class<?> type) { Map<CaseInsensitiveString, Method> getters = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> setters = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> counters = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> finders = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> adders = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> removers = new LinkedHashMap<CaseInsensitiveString, Method>(); Map<CaseInsensitiveString, Method> incidences = new LinkedHashMap<CaseInsensitiveString, Method>(); Method in = null; Method out = null; Method[] methods = type.getMethods(); for (Method method : methods) { if (EdgeFrame.class.isAssignableFrom(type)) { Annotation inA = method.getAnnotation(InVertex.class); if (inA != null) { in = method; } Annotation outA = method.getAnnotation(OutVertex.class); if (outA != null) { out = method; } } CaseInsensitiveString key = null; boolean derived = false; Annotation typed = method.getAnnotation(TypedProperty.class); if (typed != null) { key = new CaseInsensitiveString(((TypedProperty) typed).value()); derived = ((TypedProperty) typed).derived(); } else { Annotation property = method.getAnnotation(Property.class); if (property != null) { key = new CaseInsensitiveString(((Property) property).value()); } } if (key != null) { if (ClassUtilities.isGetMethod(method)) { getters.put(key, method); } if (ClassUtilities.isSetMethod(method) && !derived) { setters.put(key, method); } } else { Annotation incidenceUnique = method.getAnnotation(IncidenceUnique.class); if (incidenceUnique != null) { key = new CaseInsensitiveString(((IncidenceUnique) incidenceUnique).label()); if (ClassUtilities.isGetMethod(method)) { incidences.put(key, method); // System.out // .println("Added incidence " + key + " for method " + method.getName() + " in class " + type.getName()); } } Annotation incidence = method.getAnnotation(Incidence.class); if (incidence != null) { key = new CaseInsensitiveString(((Incidence) incidence).label()); if (ClassUtilities.isGetMethod(method)) { incidences.put(key, method); // System.out // .println("Added incidence " + key + " for method " + method.getName() + " in class " + type.getName()); } } Annotation adjacencyUnique = method.getAnnotation(AdjacencyUnique.class); if (adjacencyUnique != null) { key = new CaseInsensitiveString(((AdjacencyUnique) adjacencyUnique).label()); } Annotation adjacency = method.getAnnotation(Adjacency.class); if (adjacency != null) { key = new CaseInsensitiveString(((Adjacency) adjacency).label()); } } if (key != null) { if (AnnotationUtilities.isCountMethod(method)) { counters.put(key, method); } if (AnnotationUtilities.isFindMethod(method)) { finders.put(key, method); } if (ClassUtilities.isAddMethod(method)) { // if (type.getSimpleName().equals("User")) { // System.out.println("Registering add method for " + type.getName() + ": " + method.getName() + " with key " // + key); // } adders.put(key, method); } if (ClassUtilities.isRemoveMethod(method)) { removers.put(key, method); } } } getterMap_.put(type, getters); setterMap_.put(type, setters); counterMap_.put(type, counters); finderMap_.put(type, finders); adderMap_.put(type, adders); removerMap_.put(type, removers); if (in != null) { inMap_.put(type, in); // System.out.println("TEMP DEBUG: registering InVertex method " + in.getName() + " for class " + type.getName()); } if (out != null) { outMap_.put(type, out); } incidenceMap_.put(type, incidences); } } public static class DTypeManager extends TypeManager { private DTypeRegistry typeRegistry_; public DTypeManager(final DTypeRegistry typeRegistry) { super(typeRegistry); typeRegistry_ = typeRegistry; } private Class<?> getDefaultType(final Vertex v) { if (v instanceof DVertex) { if ("1".equals(((DVertex) v).getProperty("$FormulaClass", String.class))) return ViewVertex.class; if (v instanceof DCategoryVertex) return CategoryVertex.class; } return DVertexFrame.class; } private Class<?> getDefaultType(final Edge e) { if (e instanceof DEdge) { if (((DEdge) e).getDelegateType() == org.openntf.domino.ViewEntry.class) { return ViewVertex.Contains.class; } } return DEdgeFrame.class; } @Override public Class<?>[] resolveTypes(final Vertex v, final Class<?> defaultType) { Class<?>[] result = new Class<?>[] { resolve(v, getDefaultType(v)) }; return result; } @Override public Class<?>[] resolveTypes(final Edge e, final Class<?> defaultType) { return new Class<?>[] { resolve(e, getDefaultType(e)) }; } public Class<?> resolve(final Element e, final Class<?> defaultType) { // System.out.println("Resolving element with default type " + defaultType.getName()); Class<?> typeHoldingTypeField = typeRegistry_.getTypeHoldingTypeField(defaultType); if (typeHoldingTypeField != null) { String value = ((DElement) e).getProperty(typeHoldingTypeField.getAnnotation(TypeField.class).value(), String.class); // System.out.println("TEMP DEBUG: Found type value: " + (value == null ? "null" : value)); Class<?> type = value == null ? null : typeRegistry_.getType(typeHoldingTypeField, value, e); if (type != null) { // System.out.println("TEMP DEBUG: Returning type: " + type.getName()); return type; } } return defaultType; } @Override public void initElement(Class<?> kind, final FramedGraph<?> framedGraph, final Element element) { if (kind == null) { if (element instanceof Edge) { kind = getDefaultType((Edge) element); } else if (element instanceof Vertex) { kind = getDefaultType((Vertex) element); } else { throw new IllegalArgumentException("element parameter is a " + (element == null ? "null" : element.getClass().getName())); } } // System.out.println("TEMP DEBUG: Initing an element with kind: " + kind.getName()); Class<?> typeHoldingTypeField = typeRegistry_.getTypeHoldingTypeField(kind); if (typeHoldingTypeField != null) { TypeValue typeValue = kind.getAnnotation(TypeValue.class); if (typeValue != null) { String field = typeHoldingTypeField.getAnnotation(TypeField.class).value(); Object current = element.getProperty(field); String currentVal = null; boolean update = true; if (current != null) { currentVal = TypeUtils.toString(current); // System.out.println("TEMP DEBUG: existing type value " + currentVal); // System.out.println("TEMP DEBUG: current value is " + currentVal + " in field " + field + " while typeValue is " // + typeValue.value()); if (currentVal.equals(typeValue.value())) { update = false; } else { Class<?> classChk = typeRegistry_.getType(typeHoldingTypeField, currentVal); // System.out.println("TEMP DEBUG: Registry returned " + (classChk == null ? "null" : classChk.getName()) // + " for name of " + currentVal); if (classChk == null) { if (field.equalsIgnoreCase("form") && currentVal != null && currentVal.length() > 0 && !(element instanceof DProxyVertex)) { // System.out.print("TEMP DEBUG Not changing a form value of " + currentVal // + " even though we're looking for type " + typeValue.value() + " on an Element of type " // + element.getClass().getName()); update = false; } } else if (!kind.isAssignableFrom(classChk)) { update = !(currentVal).equals(typeValue.value()); if (!update) { // System.out.println("TEMP DEBUG Not updating form because value is already " + currentVal); } } else if (kind.isAssignableFrom(classChk)) { } else { update = false; // System.out.println("TEMP DEBUG: existing type value " + classChk.getName() + " extends requested type value " // + kind.getName()); } } } else { // System.out.println("TEMP DEBUG: current value is null in field " + field); } if (update) { if (kind == DEdgeFrame.class || kind == DVertexFrame.class || kind == ViewVertex.class || kind == ViewVertex.Contains.class) { // System.out.println("TEMP DEBUG not setting form value because kind is excluded"); } else { // element.setProperty(field, typeValue.value()); if (element instanceof DElement) { Document doc = ((DElement) element).asDocument(); doc.replaceItemValue(field, typeValue.value()); doc.save(); element.setProperty(field, typeValue.value()); if (currentVal != null && currentVal.length() > 0) { System.out.println("TEMP DEBUG Forcing type on document id " + doc.getMetaversalID() + " to " + typeValue.value() + ". Was previously " + String.valueOf(currentVal)); } } // if (framedGraph instanceof TransactionalGraph) { // ((TransactionalGraph) framedGraph).commit(); // } } } } else { // System.out.println("TEMP DEBUG: type value annotation is null"); } } else { // System.out.println("TEMP DEBUG: TypeHoldingTypeField is null for type " + kind.getName()); } } public Class<?> resolve(final VertexFrame vertex, final Class<?> defaultType) { return resolve(vertex.asVertex(), defaultType); } public Class<?> resolve(final EdgeFrame edge, final Class<?> defaultType) { return resolve(edge.asEdge(), defaultType); } public Class<?> resolve(final VertexFrame vertex) { return resolve(vertex.asVertex(), getDefaultType(vertex.asVertex())); } public Class<?> resolve(final EdgeFrame edge) { return resolve(edge.asEdge(), getDefaultType(edge.asEdge())); } } private Long defaultElementStoreKey_ = null; private DElementStore defaultElementStore_; private Map<Long, DElementStore> elementStoreMap_; private Map<Class<?>, Long> typeMap_; private transient DGraph graph_; private transient Module module_; private DTypedGraphModuleBuilder builder_; // private DTypeRegistry typeRegistry_; // private DTypeManager typeManager_; public DConfiguration() { getTypedBuilder(); } @Override public DGraph getGraph() { return graph_; } @Override public DGraph setGraph(final DGraph graph) { graph_ = graph; return graph; } @Override public Map<Class<?>, Long> getTypeMap() { if (typeMap_ == null) { typeMap_ = new HashMap<Class<?>, Long>(); } return typeMap_; } @Override public void setDefaultElementStore(final Long key) { defaultElementStoreKey_ = key; } @Override public void setDefaultElementStore(final DElementStore store) { defaultElementStore_ = store; } @Override public DElementStore getDefaultElementStore() { if (defaultElementStore_ == null) { defaultElementStore_ = getElementStores().get(defaultElementStoreKey_); } return defaultElementStore_; } @Override public Map<Long, DElementStore> getElementStores() { if (elementStoreMap_ == null) { elementStoreMap_ = new HashMap<Long, DElementStore>(); } return elementStoreMap_; } @Override public List<FrameInitializer> getFrameInitializers() { List<FrameInitializer> result = super.getFrameInitializers(); // System.out.println("FrameInitializers requested. Result has " + result.size() + " elements"); return result; } @Override public DElementStore addElementStore(final DElementStore store) { store.setConfiguration(this); Long key = store.getStoreKey(); DElementStore schk = getElementStores().get(key); if (schk == null) { getElementStores().put(key, store); } Long pkey = store.getProxyStoreKey(); if (pkey != null) { DElementStore pchk = getElementStores().get(pkey); if (pchk == null) { getElementStores().put(pkey, store); } } List<Class<?>> types = store.getTypes(); for (Class<?> type : types) { getTypeRegistry().add(type, store); Long chk = getTypeMap().get(type); if (chk != null) { if (!chk.equals(key)) { Shardable s = type.getAnnotation(Shardable.class); if (s == null) { throw new IllegalStateException("Element store has already been registered for type " + type.getName()); } else { getTypeMap().put(type, key); } } } else { getTypeMap().put(type, key); } } return store; } private DTypedGraphModuleBuilder getTypedBuilder() { if (builder_ == null) { builder_ = new DTypedGraphModuleBuilder(this); for (DElementStore store : getElementStores().values()) { for (Class<?> klazz : store.getTypes()) { builder_.withClass(klazz); } } } return builder_; } @Override public Module getModule() { if (module_ == null) { module_ = getTypedBuilder().build(); } return module_; } @Override public DTypeRegistry getTypeRegistry() { return getTypedBuilder().getTypeRegistry(); } @Override public DTypeManager getTypeManager() { return getTypedBuilder().getTypeManager(); } @Override public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { defaultElementStoreKey_ = in.readLong(); int count = in.readInt(); for (int i = 0; i < count; i++) { DElementStore store = (DElementStore) in.readObject(); addElementStore(store); store.setConfiguration(this); } } @Override public void writeExternal(final ObjectOutput out) throws IOException { out.writeLong(defaultElementStoreKey_); out.writeInt(getElementStores().size()); for (DElementStore store : getElementStores().values()) { out.writeObject(store); } } private Map<Class<?>, DKeyResolver> keyResolverMap_; protected Map<Class<?>, DKeyResolver> getResolverMap() { if (keyResolverMap_ == null) { keyResolverMap_ = new HashMap<Class<?>, DKeyResolver>(); } return keyResolverMap_; } @Override public void addKeyResolver(final DKeyResolver resolver) { for (Class<?> type : resolver.getTypes()) { getResolverMap().put(type, resolver); } } @Override public DKeyResolver getKeyResolver(final Class<?> type) { return getResolverMap().get(type); } }