package org.etk.orm.core; import java.lang.reflect.UndeclaredThrowableException; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.jcr.Node; import javax.jcr.RepositoryException; import org.etk.common.collection.Collections; import org.etk.orm.api.BuilderException; import org.etk.orm.api.format.ObjectFormatter; import org.etk.orm.plugins.bean.mapping.BeanMapping; import org.etk.orm.plugins.common.jcr.Path; import org.etk.orm.plugins.common.jcr.PathException; import org.etk.orm.plugins.instrument.Instrumentor; import org.etk.orm.plugins.instrument.MethodHandler; import org.etk.orm.plugins.instrument.ProxyType; import org.etk.orm.plugins.jcr.type.TypeManager; import org.etk.orm.plugins.mapper.ObjectMapper; import org.etk.orm.plugins.query.QueryManager; public class Domain { /** . */ private static final ProxyType<?> NULL_PROXY_TYPE = new ProxyType<Object>() { public Object createProxy(MethodHandler handler) { throw new UnsupportedOperationException("Cannot create proxy for " + handler); } public Class<?> getType() { throw new UnsupportedOperationException("Cannot get proxy type for NULL_PROXY_TYPE"); } }; /** . */ private static final Instrumentor NULL_INSTRUMENTOR = new Instrumentor() { // This is OK as the class is *stateless* @SuppressWarnings("unchecked") public <O> ProxyType<O> getProxyClass(Class<O> clazz) { return (ProxyType<O>) NULL_PROXY_TYPE; } public MethodHandler getInvoker(Object proxy) { throw new UnsupportedOperationException(); } }; /** . */ public static int LAZY_CREATE_MODE = 0; /** . */ public static int CREATE_MODE = 1; /** . */ public static int NO_CREATE_MODE = 2; /** . */ private static final Set<Integer> CREATE_MODES = Collections.set(LAZY_CREATE_MODE, CREATE_MODE, NO_CREATE_MODE); /** . */ private final Map<String, ObjectMapper> typeMapperByNodeType; /** . */ private final Map<Class<?>, ObjectMapper> typeMapperByClass; /** The default instrumentor */ private final Instrumentor defaultInstrumentor; /** . */ private final Map<Class<?>, Instrumentor> proxyTypeToInstrumentor; /** . */ private final Map<Class<?>, Instrumentor> ormTypeToInstrumentor; /** . */ final ObjectFormatter objectFormatter; /** . */ final boolean propertyCacheEnabled; /** . */ final boolean propertyReadAheadEnabled; /** . */ final boolean hasPropertyOptimized; /** . */ final boolean hasNodeOptimized; /** . */ final String rootNodePath; /** . */ final List<String> rootNodePathSegments; /** . */ final String rootNodeType; /** . */ final int rootCreateMode; /** . */ final TypeManager nodeInfoManager; /** . */ final QueryManager queryManager; public Domain(Collection<ObjectMapper<?>> mappers, Instrumentor defaultInstrumentor, ObjectFormatter objectFormatter, boolean propertyCacheEnabled, boolean propertyReadAheadEnabled, boolean hasPropertyOptimized, boolean hasNodeOptimized, String rootNodePath, int rootCreateMode, String rootNodeType) { // if (!CREATE_MODES.contains(rootCreateMode)) { throw new IllegalArgumentException("Invalid create mode " + rootCreateMode); } // Map<Class<?>, Instrumentor> proxyTypeToInstrumentor = new HashMap<Class<?>, Instrumentor>(); Map<Class<?>, Instrumentor> ormTypeToInstrumentor = new HashMap<Class<?>, Instrumentor>(); for (ObjectMapper<?> mapper : mappers) { BeanMapping beanMapping = mapper.getMapping(); Class<?> clazz = (Class<?>) beanMapping.getBean().getClassType().unwrap(); if (Object.class.equals(clazz)) { proxyTypeToInstrumentor.put(clazz, defaultInstrumentor); ormTypeToInstrumentor.put(clazz, defaultInstrumentor); } else { //wrapper the clazz in the ProxyTypeImpl which supports //to get the MethodHandler to invoke the method in clazz. proxyTypeToInstrumentor.put(defaultInstrumentor.getProxyClass(clazz).getType(), defaultInstrumentor); ormTypeToInstrumentor.put(clazz, defaultInstrumentor); } } // Map<String, ObjectMapper> typeMapperByNodeType = new HashMap<String, ObjectMapper>(); Map<Class<?>, ObjectMapper> typeMapperByClass = new HashMap<Class<?>, ObjectMapper>(); for (ObjectMapper typeMapper : mappers) { if (typeMapperByNodeType.containsKey(typeMapper.getNodeTypeName())) { throw new IllegalStateException("Duplicate node type name " + typeMapper); } typeMapperByNodeType.put(typeMapper.getNodeTypeName(), typeMapper); typeMapperByClass.put(typeMapper.getObjectClass(), typeMapper); } // final List<String> rootNodePathSegments; try { rootNodePathSegments = Path.splitAbsolutePath(Path.normalizeAbsolutePath(rootNodePath)); } catch (PathException e) { throw new BuilderException("Root node path must be valid"); } // this.typeMapperByClass = typeMapperByClass; this.typeMapperByNodeType = typeMapperByNodeType; this.defaultInstrumentor = defaultInstrumentor; this.objectFormatter = objectFormatter; this.propertyCacheEnabled = propertyCacheEnabled; this.propertyReadAheadEnabled = propertyReadAheadEnabled; this.hasPropertyOptimized = hasPropertyOptimized; this.hasNodeOptimized = hasNodeOptimized; this.rootNodePath = rootNodePath; this.rootNodePathSegments = rootNodePathSegments; this.nodeInfoManager = new TypeManager(); this.queryManager = new QueryManager(rootNodePath); this.rootCreateMode = rootCreateMode; this.rootNodeType = rootNodeType; this.proxyTypeToInstrumentor = proxyTypeToInstrumentor; this.ormTypeToInstrumentor = ormTypeToInstrumentor; } public boolean isHasPropertyOptimized() { return hasPropertyOptimized; } public boolean isHasNodeOptimized() { return hasNodeOptimized; } public MethodHandler getHandler(Object o) { Instrumentor instrumentor = proxyTypeToInstrumentor.get(o.getClass()); return instrumentor != null ? instrumentor.getInvoker(o) : null; } public <O> ProxyType<O> getProxyType(Class<O> type) { Instrumentor instrumentor = ormTypeToInstrumentor.get(type); return instrumentor.getProxyClass(type); } public ObjectMapper getTypeMapper(String nodeTypeName) { return typeMapperByNodeType.get(nodeTypeName); } public ObjectMapper getTypeMapper(Class<?> clazz) { return typeMapperByClass.get(clazz); } public QueryManager getQueryManager() { return queryManager; } /** * * * @param ownerNode * @param internal * @param nameKind * @return * @throws NullPointerException * @throws UndeclaredThrowableException * @throws IllegalStateException * @throws RepositoryException */ String decodeName(Node ownerNode, String internal, NameKind nameKind) throws NullPointerException, UndeclaredThrowableException, IllegalStateException, RepositoryException { if (ownerNode == null) { throw new NullPointerException(); } String nodeTypeName = ownerNode.getPrimaryNodeType().getName(); ObjectMapper ownerMapper = getTypeMapper(nodeTypeName); ObjectFormatter formatter = null; if (ownerMapper != null) { formatter = ownerMapper.getFormatter(); } return decodeName(formatter, internal, nameKind); } /** * * * @param ownerCtx * @param internal * @param nameKind * @return * @throws NullPointerException * @throws UndeclaredThrowableException * @throws IllegalStateException * @throws RepositoryException */ String decodeName(ObjectContext ownerCtx, String internal, NameKind nameKind) throws NullPointerException, UndeclaredThrowableException, IllegalStateException, RepositoryException { if (ownerCtx == null) { throw new NullPointerException(); } return decodeName(ownerCtx.getMapper().getFormatter(), internal, nameKind); } private String decodeName(ObjectFormatter formatter, String internal, NameKind nameKind) throws UndeclaredThrowableException, IllegalStateException, RepositoryException { if (nameKind == NameKind.PROPERTY) { return internal; } if (formatter == null) { formatter = objectFormatter; } // String external; try { if (nameKind == NameKind.OBJECT) { external = formatter.decodeNodeName(null, internal); } else { // external = formatter.decodePropertyName(null, internal); throw new UnsupportedOperationException(); } } catch (Exception e) { if (e instanceof IllegalStateException) { throw (IllegalStateException) e; } throw new UndeclaredThrowableException(e); } if (external == null) { if (nameKind == NameKind.OBJECT) { throw new IllegalStateException(); } } return external; } /** * Encodes the name for the specified context. * * @param ownerNode the node * @param externalName the external name * @param nameKind the name kind * @return the encoded name * @throws NullPointerException if the owner context argument is null * @throws UndeclaredThrowableException when the formatter throws an exception * @throws RepositoryException any repository exception */ String encodeName(Node ownerNode, String externalName, NameKind nameKind) throws NullPointerException, UndeclaredThrowableException, RepositoryException { if (ownerNode == null) { throw new NullPointerException(); } String nodeTypeName = ownerNode.getPrimaryNodeType().getName(); ObjectMapper ownerMapper = getTypeMapper(nodeTypeName); ObjectFormatter formatter = null; if (ownerMapper != null) { formatter = ownerMapper.getFormatter(); } return encodeName(formatter, externalName, nameKind); } /** * Encodes the name for the specified context. * * @param ownerCtx the context * @param externalName the external name * @param nameKind the name kind * @return the encoded name * @throws NullPointerException if any argument is null * @throws UndeclaredThrowableException when the formatter throws an exception * @throws RepositoryException any repository exception */ String encodeName(ObjectContext ownerCtx, String externalName, NameKind nameKind) throws NullPointerException, UndeclaredThrowableException, RepositoryException { if (ownerCtx == null) { throw new NullPointerException("No null owner node accepted"); } return encodeName(ownerCtx.getMapper().getFormatter(), externalName, nameKind); } /** * * @param formatter * @param externalName * @param nameKind * @return * @throws UndeclaredThrowableException * @throws NullPointerException * @throws RepositoryException */ private String encodeName(ObjectFormatter formatter, String externalName, NameKind nameKind) throws UndeclaredThrowableException, NullPointerException, RepositoryException { if (externalName == null) { throw new NullPointerException("No null name accepted"); } if (nameKind == null) { throw new NullPointerException("No null name kind accepted"); } if (nameKind == NameKind.PROPERTY) { return externalName; } if (formatter == null) { formatter = objectFormatter; } // String internal; try { if (nameKind == NameKind.OBJECT) { internal = formatter.encodeNodeName(null, externalName); } else { // internal = formatter.encodePropertyName(null, external); throw new UnsupportedOperationException(); } } catch (Exception e) { if (e instanceof NullPointerException) { throw (NullPointerException) e; } if (e instanceof IllegalArgumentException) { throw (IllegalArgumentException) e; } throw new UndeclaredThrowableException(e); } if (internal == null) { throw new IllegalArgumentException("Name " + externalName + " was converted to null"); } Path.validateLocalName(internal); return internal; } }