All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.cayenne.dbsync.naming.DeduplicationVisitor Maven / Gradle / Ivy

There is a newer version: 5.0-M1
Show newest version
/*
 *    Licensed to the Apache Software Foundation (ASF) under one
 *    or more contributor license agreements.  See the NOTICE file
 *    distributed with this work for additional information
 *    regarding copyright ownership.  The ASF licenses this file
 *    to you 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 org.apache.cayenne.dbsync.naming;

import org.apache.cayenne.configuration.ConfigurationNode;
import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
import org.apache.cayenne.configuration.DataChannelDescriptor;
import org.apache.cayenne.configuration.DataNodeDescriptor;
import org.apache.cayenne.map.DataMap;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.DbRelationship;
import org.apache.cayenne.map.Embeddable;
import org.apache.cayenne.map.EmbeddableAttribute;
import org.apache.cayenne.map.ObjAttribute;
import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.map.ObjRelationship;
import org.apache.cayenne.map.Procedure;
import org.apache.cayenne.map.ProcedureParameter;
import org.apache.cayenne.map.QueryDescriptor;

import java.util.Objects;
import java.util.function.Predicate;

/**
 * @since 4.0
 */
class DeduplicationVisitor implements ConfigurationNodeVisitor {

    private ConfigurationNode parent;
    private String baseName;
    private String dupesPattern;

    DeduplicationVisitor(ConfigurationNode parent, String baseName, String dupesPattern) {
        this.parent = parent;
        this.baseName = Objects.requireNonNull(baseName);
        this.dupesPattern = Objects.requireNonNull(dupesPattern);
    }

    @Override
    public String visitDataChannelDescriptor(DataChannelDescriptor channelDescriptor) {
        // DataChannelDescriptor is top-level. No context or naming conflicts are expected...
        return baseName;
    }

    @Override
    public String visitDataNodeDescriptor(DataNodeDescriptor nodeDescriptor) {
        return resolve(name -> {
            DataChannelDescriptor dataChannelDescriptor = (DataChannelDescriptor) parent;
            for (DataNodeDescriptor dataNodeDescriptor : dataChannelDescriptor.getNodeDescriptors()) {
                if (dataNodeDescriptor.getName().equals(name)) {
                    return true;
                }
            }

            return false;
        });
    }

    @Override
    public String visitDataMap(DataMap dataMap) {
        return resolve(name -> {
            // null context is a situation when DataMap is a
            // top level object of the project
            if (parent == null) {
                return false;
            }

            if (parent instanceof DataChannelDescriptor) {
                DataChannelDescriptor domain = (DataChannelDescriptor) parent;
                return domain.getDataMap(name) != null;
            }
            return false;
        });
    }

    @Override
    public String visitObjEntity(ObjEntity entity) {
        return resolve(name -> ((DataMap) parent).getObjEntity(name) != null);
    }

    @Override
    public String visitDbEntity(DbEntity entity) {
        return resolve(name -> ((DataMap) parent).getDbEntity(name) != null);
    }

    @Override
    public String visitEmbeddable(Embeddable embeddable) {
        return resolve(name -> {
            DataMap map = (DataMap) parent;
            return map.getEmbeddable(map.getNameWithDefaultPackage(name)) != null;
        });
    }

    @Override
    public String visitEmbeddableAttribute(EmbeddableAttribute attribute) {
        return resolve(name -> ((Embeddable) parent).getAttribute(name) != null);
    }

    @Override
    public String visitObjAttribute(ObjAttribute attribute) {
        return resolveObjEntityProperty();
    }

    @Override
    public String visitDbAttribute(DbAttribute attribute) {
        return resolveDbEntityProperty();
    }

    @Override
    public String visitObjRelationship(ObjRelationship relationship) {
        return resolveObjEntityProperty();
    }

    @Override
    public String visitDbRelationship(DbRelationship relationship) {
        return resolveDbEntityProperty();
    }

    @Override
    public String visitProcedure(Procedure procedure) {
        return resolve(name -> ((DataMap) parent).getProcedure(name) != null);
    }

    @Override
    public String visitProcedureParameter(ProcedureParameter parameter) {
        return resolve(name -> {

            // it doesn't matter if we create a parameter with a duplicate name.. parameters are positional anyway..
            // still try to use unique names for visual consistency

            Procedure procedure = (Procedure) parent;
            for (ProcedureParameter parameter1 : procedure.getCallParameters()) {
                if (name.equals(parameter1.getName())) {
                    return true;
                }
            }

            return false;
        });
    }

    @Override
    public String visitQuery(QueryDescriptor query) {
        return resolve(name -> ((DataMap) parent).getQueryDescriptor(name) != null);
    }

    String resolve(Predicate nameChecker) {
        int c = 1;
        String name = baseName;
        while (nameChecker.test(name)) {
            name = String.format(dupesPattern, baseName, c++);
        }

        return name;
    }

    private String resolveDbEntityProperty() {
        return resolve(name -> {
            DbEntity entity = (DbEntity) parent;
            // check if either attribute or relationship name matches...
            return entity.getAttribute(name) != null || entity.getRelationship(name) != null;
        });
    }

    private String resolveObjEntityProperty() {
        return resolve(name -> {
            ObjEntity entity = (ObjEntity) parent;

            // check if either attribute or relationship name matches...
            if (entity.getAttribute(name) != null || entity.getRelationship(name) != null) {
                return true;
            }

            //  check if there's a callback method that shadows attribute getter (unlikely, but still)
            String conflictingCallback = "get" + NameUtil.capitalize(name);
            return entity.getCallbackMethods().contains(conflictingCallback);
        });
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy