com.evolveum.midpoint.repo.sql.query2.definition.JpaEntityDefinition.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.repo.sql.query2.definition.JpaEntityDefinition.java

Source

/*
 * 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.definition;

import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.Visitable;
import com.evolveum.midpoint.prism.Visitor;
import com.evolveum.midpoint.prism.path.IdItemPathSegment;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.ItemPathSegment;
import com.evolveum.midpoint.prism.path.ObjectReferencePathSegment;
import com.evolveum.midpoint.repo.sql.query.QueryException;
import com.evolveum.midpoint.repo.sql.query2.resolution.DataSearchResult;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import org.apache.commons.lang.Validate;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author lazyman
 * @author mederly
 */
public class JpaEntityDefinition extends JpaDataNodeDefinition implements DebugDumpable, Visitable {

    private static final Trace LOGGER = TraceManager.getTrace(JpaEntityDefinition.class);

    /**
     * child definitions of this entity
     */
    private List<JpaLinkDefinition> definitions = new ArrayList<>();
    private JpaEntityDefinition superclassDefinition;

    public JpaEntityDefinition(Class jpaClass, Class jaxbClass) {
        super(jpaClass, jaxbClass);
    }

    public void addDefinition(JpaLinkDefinition definition) {
        JpaLinkDefinition oldDef = findRawLinkDefinition(definition.getItemPath(), JpaDataNodeDefinition.class,
                true);
        if (oldDef != null) {
            definitions.remove(oldDef);
        }
        definitions.add(definition);
    }

    public void sortDefinitions() {
        Collections.sort(definitions, new LinkDefinitionComparator());
    }

    private <D extends JpaDataNodeDefinition> JpaLinkDefinition<D> findRawLinkDefinition(ItemPath itemPath,
            Class<D> type, boolean exact) {
        Validate.notNull(itemPath, "ItemPath must not be null.");
        Validate.notNull(type, "Definition type must not be null.");

        for (JpaLinkDefinition definition : definitions) {
            if (exact) {
                if (!definition.matchesExactly(itemPath)) {
                    continue;
                }
            } else {
                if (!definition.matchesStartOf(itemPath)) {
                    continue;
                }
            }
            if (type.isAssignableFrom(definition.getTargetClass())) {
                return definition;
            }
        }
        return null;
    }

    public interface LinkDefinitionHandler {
        void handle(JpaLinkDefinition linkDefinition);
    }

    /**
     * Resolves the whole ItemPath
     *
     * @param path ItemPath to resolve. Non-empty!
     * @param itemDefinition Definition of the final path segment, if it's "any" property.
     * @param type Type of definition to be found
     * @return
     *
     * If successful, returns correct definition + empty path.
     * If unsuccessful, return null.
     */
    public <D extends JpaDataNodeDefinition> DataSearchResult<D> findDataNodeDefinition(ItemPath path,
            ItemDefinition itemDefinition, Class<D> type) throws QueryException {
        return findDataNodeDefinition(path, itemDefinition, type, null);
    }

    public <D extends JpaDataNodeDefinition> DataSearchResult<D> findDataNodeDefinition(ItemPath path,
            ItemDefinition itemDefinition, Class<D> type, LinkDefinitionHandler handler) throws QueryException {
        JpaDataNodeDefinition currentDefinition = this;
        for (;;) {
            DataSearchResult<JpaDataNodeDefinition> result = currentDefinition.nextLinkDefinition(path,
                    itemDefinition);
            if (result == null) { // oops
                return null;
            }
            if (handler != null) {
                handler.handle(result.getLinkDefinition());
            }
            JpaLinkDefinition linkDefinition = result.getLinkDefinition();
            JpaDataNodeDefinition targetDefinition = linkDefinition.getTargetDefinition();

            if (result.isComplete()) {
                if (type.isAssignableFrom(targetDefinition.getClass())) {
                    return (DataSearchResult<D>) result;
                } else {
                    return null;
                }
            }

            path = result.getRemainder();
            currentDefinition = targetDefinition;
        }
    }

    public void setSuperclassDefinition(JpaEntityDefinition superclassDefinition) {
        this.superclassDefinition = superclassDefinition;
    }

    public JpaEntityDefinition getSuperclassDefinition() {
        return superclassDefinition;
    }

    @Override
    public DataSearchResult nextLinkDefinition(ItemPath path, ItemDefinition itemDefinition) throws QueryException {

        if (ItemPath.isNullOrEmpty(path)) { // doesn't fulfill precondition
            return null;
        }

        ItemPathSegment first = path.first();
        if (first instanceof IdItemPathSegment) {
            throw new QueryException("ID item path segments are not allowed in query: " + path);
        } else if (first instanceof ObjectReferencePathSegment) {
            throw new QueryException("'@' path segment cannot be used in the context of an entity " + this);
        }

        JpaLinkDefinition link = findRawLinkDefinition(path, JpaDataNodeDefinition.class, false);
        if (link == null) {
            return null;
        } else {
            link.resolveEntityPointer();
            return new DataSearchResult(link, path.tail(link.getItemPath().size()));
        }
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
        for (JpaLinkDefinition definition : definitions) {
            definition.accept(visitor);
        }
    }

    @Override
    protected String getDebugDumpClassName() {
        return "Ent";
    }

    @Override
    public String debugDump() {
        return debugDump(0);
    }

    public boolean isAssignableFrom(JpaEntityDefinition specificEntityDefinition) {
        return getJpaClass().isAssignableFrom(specificEntityDefinition.getJpaClass());
    }

    public boolean isAbstract() {
        return Modifier.isAbstract(getJpaClass().getModifiers());
    }

    @Override
    public String debugDump(int indent) {
        StringBuilder sb = new StringBuilder();
        sb.append(super.getShortInfo());
        if (superclassDefinition != null) {
            sb.append(" extends ").append(superclassDefinition);
        }
        for (JpaLinkDefinition definition : definitions) {
            sb.append("\n");
            sb.append(definition.debugDump(indent + 1));
        }
        return sb.toString();
    }
}