/* * Copyright (c) 2010-2015 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.evolveum.midpoint.repo.sql.query2; import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.Visitor; import com.evolveum.midpoint.repo.sql.data.common.RObject; import com.evolveum.midpoint.repo.sql.data.common.container.RAccessCertificationCase; import com.evolveum.midpoint.repo.sql.data.common.container.RAccessCertificationWorkItem; import com.evolveum.midpoint.repo.sql.data.common.other.RObjectType; import com.evolveum.midpoint.repo.sql.query.QueryException; import com.evolveum.midpoint.repo.sql.query2.definition.ClassDefinitionParser; import com.evolveum.midpoint.repo.sql.query2.definition.JpaEntityDefinition; import com.evolveum.midpoint.repo.sql.query2.definition.JpaEntityPointerDefinition; import com.evolveum.midpoint.repo.sql.util.ClassMapper; import com.evolveum.midpoint.schema.constants.ObjectTypes; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCaseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationWorkItemType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import org.apache.commons.lang.Validate; import javax.xml.namespace.QName; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author lazyman */ public class QueryDefinitionRegistry2 implements DebugDumpable { private static final Trace LOGGER = TraceManager.getTrace(QueryDefinitionRegistry2.class); private static final Map<QName, JpaEntityDefinition> definitions; private static QueryDefinitionRegistry2 registry; static { try { LOGGER.trace("Initializing query definition registry."); ClassDefinitionParser classDefinitionParser = new ClassDefinitionParser(); final Map<QName, JpaEntityDefinition> map = new HashMap<>(); final Map<Class<?>, JpaEntityDefinition> definitionsByClass = new HashMap<>(); Collection<RObjectType> types = ClassMapper.getKnownTypes(); for (RObjectType type : types) { Class clazz = type.getClazz(); if (!RObject.class.isAssignableFrom(clazz)) { continue; } JpaEntityDefinition definition = classDefinitionParser.parseRootClass(clazz); if (definition == null) { continue; } ObjectTypes objectType = ClassMapper.getObjectTypeForHQLType(type); map.put(objectType.getTypeQName(), definition); definitionsByClass.put(definition.getJpaClass(), definition); } // TODO fix this hack JpaEntityDefinition caseDefinition = classDefinitionParser.parseRootClass(RAccessCertificationCase.class); definitionsByClass.put(RAccessCertificationCase.class, caseDefinition); map.put(AccessCertificationCaseType.COMPLEX_TYPE, caseDefinition); JpaEntityDefinition certWorkItemDefinition = classDefinitionParser.parseRootClass(RAccessCertificationWorkItem.class); definitionsByClass.put(RAccessCertificationWorkItem.class, certWorkItemDefinition); map.put(AccessCertificationWorkItemType.COMPLEX_TYPE, certWorkItemDefinition); // link parents (maybe not needed at all, we'll see) and referenced entity definitions // sort definitions for (final JpaEntityDefinition definition : map.values()) { Visitor resolutionVisitor = visitable -> { if (visitable instanceof JpaEntityDefinition) { JpaEntityDefinition entityDef = ((JpaEntityDefinition) visitable); Class superclass = entityDef.getJpaClass().getSuperclass(); if (superclass == null || !RObject.class.isAssignableFrom(superclass)) { return; } JpaEntityDefinition superclassDefinition = definitionsByClass.get(superclass); if (superclassDefinition == null) { throw new IllegalStateException("No definition for superclass " + superclass + " of " + entityDef); } entityDef.setSuperclassDefinition(superclassDefinition); } else if (visitable instanceof JpaEntityPointerDefinition) { JpaEntityPointerDefinition entPtrDef = ((JpaEntityPointerDefinition) visitable); if (!entPtrDef.isResolved()) { Class referencedEntityJpaClass = entPtrDef.getJpaClass(); JpaEntityDefinition realEntDef = definitionsByClass.get(referencedEntityJpaClass); if (realEntDef == null) { throw new IllegalStateException("Couldn't find entity definition for " + referencedEntityJpaClass); } entPtrDef.setResolvedEntityDefinition(realEntDef); } } }; definition.accept(resolutionVisitor); Visitor sortingVisitor = visitable -> { if (visitable instanceof JpaEntityDefinition) { JpaEntityDefinition entityDef = ((JpaEntityDefinition) visitable); entityDef.sortDefinitions(); } }; definition.accept(sortingVisitor); } definitions = Collections.unmodifiableMap(map); } catch (Throwable t) { LOGGER.error("Couldn't initialize query definition registry: {}", t.getMessage(), t); throw t; } } private QueryDefinitionRegistry2() { } public static QueryDefinitionRegistry2 getInstance() { if (registry == null) { registry = new QueryDefinitionRegistry2(); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Registry:\n{}", registry.debugDump()); } } return registry; } @Override public String debugDump() { return debugDump(0); } @Override public String debugDump(int indent) { StringBuilder builder = new StringBuilder(); DebugUtil.indentDebugDump(builder, indent); Collection<JpaEntityDefinition> defCollection = definitions.values(); for (JpaEntityDefinition definition : defCollection) { builder.append(definition.debugDump(indent)).append('\n'); } return builder.toString(); } public JpaEntityDefinition findEntityDefinition(QName typeName) { Validate.notNull(typeName, "Type name must not be null."); JpaEntityDefinition def = QNameUtil.getKey(definitions, typeName); if (def == null) { throw new IllegalStateException("Type " + typeName + " couldn't be found in type registry"); } return def; } // always returns non-null value public <T extends Containerable> JpaEntityDefinition findEntityDefinition(Class<T> type) throws QueryException { Validate.notNull(type, "Type must not be null."); return findEntityDefinition(getQNameForType(type)); } public <T extends Containerable> QName getQNameForType(Class<T> type) throws QueryException { if (ObjectType.class.isAssignableFrom(type)) { return ObjectTypes.getObjectType((Class) type).getTypeQName(); } if (AccessCertificationCaseType.class.equals(type)) { // TODO generalize return AccessCertificationCaseType.COMPLEX_TYPE; } else if (AccessCertificationWorkItemType.class.equals(type)) { // TODO generalize return AccessCertificationWorkItemType.COMPLEX_TYPE; } throw new QueryException("Unsupported type " + type); } /** * Returns possible "children" of a given definition. * More abstract classes are listed first. */ public List<JpaEntityDefinition> getChildrenOf(JpaEntityDefinition entityDefinition) { List<JpaEntityDefinition> retval = new ArrayList<>(); List<JpaEntityDefinition> children = getDirectChildrenOf(entityDefinition); for (JpaEntityDefinition child : children) { retval.add(child); retval.addAll(getChildrenOf(child)); } return retval; } private List<JpaEntityDefinition> getDirectChildrenOf(JpaEntityDefinition parentDefinition) { Class parentClass = parentDefinition.getJpaClass(); List<JpaEntityDefinition> retval = new ArrayList<>(); for (JpaEntityDefinition definition : definitions.values()) { if (parentClass.equals(definition.getJpaClass().getSuperclass())) { retval.add(definition); } } return retval; } }