org.eclipse.emf.teneo.annotations.mapper.AbstractProcessingContext.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.teneo.annotations.mapper.AbstractProcessingContext.java

Source

/**
 * <copyright>
 *
 * Copyright (c) 2005, 2006, 2007, 2008 Springsite BV (The Netherlands) and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Martin Taal
 * </copyright>
 *
 * $Id: AbstractProcessingContext.java,v 1.10 2010/04/22 17:57:24 mtaal Exp $
 */

package org.eclipse.emf.teneo.annotations.mapper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEReference;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature;
import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel;
import org.eclipse.emf.teneo.annotations.pannotation.AssociationOverride;
import org.eclipse.emf.teneo.annotations.pannotation.AttributeOverride;
import org.eclipse.emf.teneo.annotations.pannotation.Column;
import org.eclipse.emf.teneo.annotations.pannotation.JoinColumn;
import org.eclipse.emf.teneo.mapping.strategy.SQLNameStrategy;

/**
 * ProcessingContext which handles attributes overrides.
 * 
 * @author <a href="mailto:mtaal@elver.org">Martin Taal</a>
 * @version $Revision: 1.10 $
 */

public class AbstractProcessingContext {

    /** The logger for all these exceptions */
    protected static final Log log = LogFactory.getLog(AbstractProcessingContext.class);

    /** The current list of overrides */
    private Map<String, Object> currentOverrides = new HashMap<String, Object>();

    /**
     * Pushes the current overrides on the stack, to be popped later, this is to
     * handle nested components
     */
    private Stack<Map<String, Object>> overrideStack = new Stack<Map<String, Object>>();

    /**
     * Pushes the current embedding feature on the stack, to be popped later,
     * this is to handle nested components and automatic renaming of props
     */
    private Stack<PAnnotatedEStructuralFeature> embeddingFeatureStack = new Stack<PAnnotatedEStructuralFeature>();

    /**
     * Add attribute overrides, happens for each mapped superclass and each
     * embedded component
     */
    public void addAttributeOverrides(EList<AttributeOverride> aos) {
        if (aos != null) {
            for (AttributeOverride override : aos) {
                currentOverrides.put(override.getName(), override.getColumn());
            }
        }
    }

    /** Add association overrides, for each mapped subclass */
    public void addAssociationOverrides(EList<AssociationOverride> overrides) {
        if (overrides != null) {
            for (AssociationOverride override : overrides) {
                currentOverrides.put(override.getName(), override);
            }
        }
    }

    /**
     * Pushes the current overrides on the stack, to be popped later, this is to
     * handle nested components
     */
    public void pushOverrideOnStack() {
        overrideStack.push(new HashMap<String, Object>(currentOverrides));
    }

    /** Pop the current overrides on the stack */
    public void popOverrideStack() {
        currentOverrides = overrideStack.pop();
    }

    /** Pushes the current embedding feature on the stack */
    public void pushEmbeddingFeature(PAnnotatedEStructuralFeature er) {
        embeddingFeatureStack.push(er);
    }

    /** Pops the current embedding feature from the stack */
    public void popEmbeddingFeature() {
        embeddingFeatureStack.pop();
    }

    /** Peeks for the current embedding feature */
    public PAnnotatedEStructuralFeature getEmbeddingFeature() {
        if (embeddingFeatureStack.isEmpty()) {
            return null;
        }
        return embeddingFeatureStack.peek();
    }

    /** Clear the override is done before an entity is processed */
    public void clearOverrides() {
        currentOverrides.clear();
    }

    /** Return the overridden column for the passed attribute */
    public Column getAttributeOverride(PAnnotatedEStructuralFeature paFeature) {
        return getAttributeOverride(paFeature.getModelElement().getName());
    }

    public Column getAttributeOverride(String featureName) {
        return getAttributeOverride(featureName, -1);
    }

    /** Return the overridden columns for the indicated featureName */
    public Column getAttributeOverride(String featureName, int embeddingFeatureIndex) {
        final Column c = (Column) currentOverrides.get(featureName);
        if (c == null) {
            final Object o = getFromStack(featureName);
            if (o != null && o instanceof Column) {
                return (Column) o;
            }
            // o == null, try one level deeper
            if (embeddingFeatureIndex == -1 && !embeddingFeatureStack.isEmpty()) {
                String newFeatureName = embeddingFeatureStack.peek().getModelElement().getName() + "."
                        + featureName;
                return getAttributeOverride(newFeatureName, embeddingFeatureStack.size() - 1);
            } else if (embeddingFeatureIndex > 0) {
                String newFeatureName = embeddingFeatureStack.get(embeddingFeatureIndex - 1).getModelElement()
                        .getName() + "." + featureName;
                return getAttributeOverride(newFeatureName, embeddingFeatureIndex - 1);
            }
        }
        return c;
    }

    /** Return the overridden JoinColumns for this reference */
    public AssociationOverride getAssociationOverrides(PAnnotatedEReference paReference) {
        return getAssociationOverrides(paReference.getModelEReference().getName());
    }

    public AssociationOverride getAssociationOverrides(String featureName) {
        return getAssociationOverrides(featureName, -1);
    }

    public AssociationOverride getAssociationOverrides(String featureName, int embeddingFeatureIndex) {
        final AssociationOverride jcs = (AssociationOverride) currentOverrides.get(featureName);
        if (jcs == null) {
            final Object o = getFromStack(featureName);
            if (o instanceof List<?>) {
                return (AssociationOverride) o;
            }
            // o == null, try one level deeper
            if (embeddingFeatureIndex == -1 && !embeddingFeatureStack.isEmpty()) {
                String newFeatureName = embeddingFeatureStack.peek().getModelElement().getName() + "."
                        + featureName;
                return getAssociationOverrides(newFeatureName, embeddingFeatureStack.size() - 1);
            } else if (embeddingFeatureIndex > 0) {
                String newFeatureName = embeddingFeatureStack.get(embeddingFeatureIndex - 1).getModelElement()
                        .getName() + "." + featureName;
                return getAssociationOverrides(newFeatureName, embeddingFeatureIndex - 1);
            }
        }
        return jcs;
    }

    private Object getFromStack(String name) {
        for (int i = (overrideStack.size() - 1); i >= 0; i--) {
            final Map<String, Object> checkOverride = overrideStack.get(i);
            final Object o = checkOverride.get(name);
            if (o != null) {
                return o;
            }
        }
        return null;
    }

    /**
     * This method returns all inherited features which need to be added to the
     * mapping of the aclass itself. The method makes a distinction makes a
     * distinction between the first supertype (the first one in the list) and
     * later ones. The features of the first type are only added to the mapping
     * if the first type is a mappedsuperclass, in all other cases the features
     * of the first type are not mapped in the aclass itself because they are
     * inherited (the mapping describes the inheritance relation). For the other
     * supertypes (located at index 1 and up in getESuperTypes) the features are
     * mapped as properties in the class itself. The superEntity is the super
     * aclass denoted as the real supertype extended by teneo.
     */
    public List<PAnnotatedEStructuralFeature> getInheritedFeatures(PAnnotatedEClass aClass) {
        // if no supertypes then there are no inherited features
        final EClass eclass = aClass.getModelEClass();
        if (eclass.getESuperTypes().size() == 0) {
            return new ArrayList<PAnnotatedEStructuralFeature>();
        }
        if (log.isDebugEnabled()) {
            log.debug("Determining inherited features which are mapped locally for "
                    + aClass.getModelEClass().getName());
        }
        final List<EStructuralFeature> inheritedFeatures = new ArrayList<EStructuralFeature>(
                eclass.getEAllStructuralFeatures());

        // remove all the features of the eclass itself
        inheritedFeatures.removeAll(eclass.getEStructuralFeatures());

        // check if the type has a supertype (a non-transient,
        // non-mappedsuperclass, if so then
        // remove all features inherited from the first supertype
        // as this inheritance is done in the mapping file
        if (aClass.getPaSuperEntity() != null) {
            inheritedFeatures.removeAll(aClass.getPaSuperEntity().getModelEClass().getEAllStructuralFeatures());
        }

        // get all efeatures from direct mappedsuperclasses
        // the id feature inherited from a direct mappedsuperclass should be
        // maintained in other cases the id features are not mapped locally.
        // The system can also ignore this and let the user be more carefull not
        // to
        // add id features here and there in the inheritance structure but this
        // is
        // more robust
        removeIdFeatures(aClass, inheritedFeatures);

        // convert the result
        final PAnnotatedModel paModel = aClass.getPaModel();
        final ArrayList<PAnnotatedEStructuralFeature> result = new ArrayList<PAnnotatedEStructuralFeature>();
        for (EStructuralFeature esf : inheritedFeatures) {
            result.add(paModel.getPAnnotated(esf));
        }

        // solve: https://issues.openbravo.com/view.php?id=19236
        for (PAnnotatedEStructuralFeature paFeature : result) {
            if (paFeature.getForeignKey() != null && paFeature.getForeignKey().isGenerated()) {
                paFeature.getForeignKey().setName(getSqlNameStrategy().getForeignKeyName(aClass, paFeature));
            }
        }

        return result;
    }

    public SQLNameStrategy getSqlNameStrategy() {
        // needs to be implemented by subclass
        throw new UnsupportedOperationException();
    }

    /**
     * Remove all id-features not inherited from a direct mapped superclass, and
     * add the features from the mapped superclass
     */
    private void removeIdFeatures(PAnnotatedEClass aClass, List<EStructuralFeature> inheritedFeatures) {
        // first get all the mapped superclasses
        final ArrayList<EClass> mappedSuperEClasses = new ArrayList<EClass>();
        for (EClass superEClass : aClass.getModelEClass().getESuperTypes()) {
            final PAnnotatedEClass superPAClass = aClass.getPaModel().getPAnnotated(superEClass);
            if (superPAClass != null && superPAClass.getMappedSuperclass() != null) {
                mappedSuperEClasses.add(superPAClass.getModelEClass());
            }
        }

        // now get all the efeatures of the mappedsuperclasses to prevent any id
        // features from them being removed, only do that when the aclass does
        // not
        // have a real super type, in that case the id can be inherited from the
        // mappedsuperclass
        final ArrayList<EStructuralFeature> mappedSuperFeatures = new ArrayList<EStructuralFeature>();
        if (aClass.getPaSuperEntity() == null || aClass.getPaSuperEntity().getMappedSuperclass() != null) {
            for (EClass mappedSuperEClass : mappedSuperEClasses) {
                mappedSuperFeatures.removeAll(mappedSuperEClass.getEAllStructuralFeatures());
                mappedSuperFeatures.addAll(mappedSuperEClass.getEAllStructuralFeatures());
            }
        }

        // now remove all id features not coming from a direct mapped superclass
        final ArrayList<EStructuralFeature> toRemove = new ArrayList<EStructuralFeature>();
        for (EStructuralFeature esf : inheritedFeatures) {
            final PAnnotatedEStructuralFeature pef = aClass.getPaModel().getPAnnotated(esf);

            if (pef instanceof PAnnotatedEAttribute && ((PAnnotatedEAttribute) pef).getId() != null
                    && !mappedSuperFeatures.contains(esf)) {
                toRemove.add(esf);
            }
        }
        inheritedFeatures.removeAll(toRemove);
    }

    //
    // /** Returns all mapped super classes */
    // public List<PAnnotatedEClass> getMappedSuperClasses(PAnnotatedEClass
    // entity) {
    // final List<PAnnotatedEClass> result = new ArrayList<PAnnotatedEClass>();
    // for (EClass superEClass : entity.getAnnotatedEClass().getESuperTypes()) {
    // final PAnnotatedEClass superPAClass = entity.getPaModel()
    // .getPAnnotated(superEClass);
    // if (superPAClass != null
    // && superPAClass.getMappedSuperclass() != null) {
    // result.add(superPAClass);
    // // and add the mapped super classes of the mapped superclass
    // // note that only the unbroken chain of mappedsuperclasses is
    // // added to the result, if there
    // // is a non-mappedsuperclass in the inheritance then it stops
    // // there
    // // issue also identified by Douglas Bitting
    // result.addAll(getMappedSuperClasses(superPAClass));
    // }
    // }
    //
    // return result;
    // }

    /**
     * Returns true if the eclass only has mappedsuperclasses without id
     * annotated property
     */
    public boolean mustAddSyntheticID(PAnnotatedEClass entity) {
        if (entity.hasIdAnnotatedFeature()) {
            return false;
        }
        for (EClass superEClass : entity.getModelEClass().getEAllSuperTypes()) {
            final PAnnotatedEClass superPAClass = entity.getPaModel().getPAnnotated(superEClass);
            if (superPAClass != null && superPAClass.getMappedSuperclass() == null) {
                return false;
            } else if (superPAClass != null && superPAClass.getMappedSuperclass() != null) {
                if (superPAClass.hasIdAnnotatedFeature()) {
                    return false;
                }
            }
        }

        return true;
    }
}