de.iteratec.iteraplan.businesslogic.exchange.xmi.exporter.EObjectCreatorImpl.java Source code

Java tutorial

Introduction

Here is the source code for de.iteratec.iteraplan.businesslogic.exchange.xmi.exporter.EObjectCreatorImpl.java

Source

/*
 * iteraplan is an IT Governance web application developed by iteratec, GmbH
 * Copyright (C) 2004 - 2014 iteratec, GmbH
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY ITERATEC, ITERATEC DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact iteratec GmbH headquarters at Inselkammerstr. 4
 * 82008 Munich - Unterhaching, Germany, or at email address info@iteratec.de.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "iteraplan" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by iteraplan".
 */
package de.iteratec.iteraplan.businesslogic.exchange.xmi.exporter;

import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Clob;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import de.iteratec.iteraplan.businesslogic.exchange.xmi.exporter.ecore.EntityBeanIntrospectionServiceBean;
import de.iteratec.iteraplan.businesslogic.exchange.xmi.exporter.ecore.Iteraplan2EMFHelper;
import de.iteratec.iteraplan.common.Logger;

public class EObjectCreatorImpl implements EObjectCreator {
    private static final Logger LOGGER = Logger.getIteraplanLogger(EObjectCreatorImpl.class);
    private static final Set<String> SYSTEM_PACKAGE_NAMES = Sets.newHashSet("java.lang", "java.util", "java.math");

    private final SessionFactory sessionFactory;
    private final EntityBeanIntrospectionServiceBean introspectionBean;

    private final Map<Object, EObject> objectToEObject = Maps.newHashMap();

    public EObjectCreatorImpl(SessionFactory sessionFactory, EntityBeanIntrospectionServiceBean introspectionBean) {
        this.sessionFactory = sessionFactory;
        this.introspectionBean = introspectionBean;
    }

    /**
     * {@inheritDoc}
     */
    public EObject getXmiExportObject() {
        objectToEObject.clear();

        Map<String, EClass> eClasses = collectEClasses();
        Collection<EObject> allEInstances = collectAllEInstances(eClasses);

        EClass eClass = eClasses.get(Iteraplan2EMFHelper.CLASS_NAME);
        EPackage ePackage = eClass.getEPackage();
        EObject eContainer = ePackage.getEFactoryInstance().create(eClass);
        EStructuralFeature eStructuralFeature = eContainer.eClass()
                .getEStructuralFeature(Iteraplan2EMFHelper.EREFERENCE_NAME);
        eContainer.eSet(eStructuralFeature, allEInstances);
        objectToEObject.clear();
        return eContainer;
    }

    private Map<String, EClass> collectEClasses() {
        Map<String, EClass> eClasses = Maps.newLinkedHashMap();

        for (EPackage ePackage : introspectionBean.getEPackages()) {
            for (EClassifier eClassifier : ePackage.getEClassifiers()) {
                if (eClassifier instanceof EClass) {
                    eClasses.put(eClassifier.getName(), (EClass) eClassifier);
                }
            }
        }

        return eClasses;
    }

    /**
     * Method which creates EObject instances for all iteraplan-entity-instances
     */
    private Collection<EObject> collectAllEInstances(Map<String, EClass> eClasses) {
        Map<EObject, Object> allEObjects = Maps.newLinkedHashMap();
        Session session = sessionFactory.getCurrentSession();

        for (Entry<String, EClass> entry : eClasses.entrySet()) {
            Map<EObject, Object> eObjects = createInstancesForEClass(entry.getValue(), session);
            allEObjects.putAll(eObjects);
        }

        List<EObject> components = Lists.newArrayList();
        for (Entry<EObject, Object> entry : allEObjects.entrySet()) {
            Collection<EObject> referenceComponents = setEReferences(entry.getKey(), entry.getValue(), eClasses);
            components.addAll(referenceComponents);
        }

        return Lists.newArrayList(Iterables.concat(allEObjects.keySet(), components));
    }

    @SuppressWarnings("unchecked")
    private Map<EObject, Object> createInstancesForEClass(EClass eClassifier, Session session) {
        Map<EObject, Object> result = Maps.newLinkedHashMap();

        String name = eClassifier.getName();
        boolean canBeExported = !(eClassifier.isAbstract() || Iteraplan2EMFHelper.CLASS_NAME.equals(name)
                || "RuntimePeriod".equals(name));

        if (canBeExported) {
            final Query query = session.createQuery("select xx from " + name + " xx");
            Iterator<Object> iterator = query.iterate();
            while (iterator.hasNext()) {
                Object instance = iterator.next();
                EObject eObject = createEObject(eClassifier, instance);
                result.put(eObject, instance);
                objectToEObject.put(instance, eObject);
            }
        }

        return result;
    }

    /**
     * Method to create an EObject for the actual instance and sets all EAttributes of the
     * corresponding EClass
     * 
     * @param eClass
     *          The corresponding {@link EClass} of the instanceClass
     * @param instanceClass
     *          The {@link Class} of the instance
     * @param instance
     *          The corresponding {@link Object} of the created EObject
     */
    private EObject createEObject(EClass eClass, Object instance) {
        Class<?> instanceClass = instance.getClass();
        EFactory eFactory = eClass.getEPackage().getEFactoryInstance();
        EObject eInstance = eFactory.create(eClass);

        for (EAttribute eAttribute : eClass.getEAllAttributes()) {
            try {
                String prefix = "get";
                if (eAttribute.getEType().getName().startsWith("EBoolean")) {
                    prefix = "is";
                }

                final Method method = instanceClass.getMethod(prefix + capitalize(eAttribute.getName()));

                if (eAttribute.getEType() instanceof EEnum) {
                    ensureEEnum(eAttribute);
                }
                if (eAttribute.isID()) {
                    eInstance.eSet(eAttribute, eClass.getName() + "_" + method.invoke(instance));
                } else {
                    Object eObjectFor = eObjectFor(method.invoke(instance));
                    eInstance.eSet(eAttribute, eObjectFor);
                }

            } catch (IllegalArgumentException e) {
                LOGGER.error("IllegalArgumentException thrown by gettingMethod for " + eClass.getName() + "."
                        + eAttribute.getName());
            } catch (SecurityException e) {
                LOGGER.error("SecurityException caused by " + eClass.getName() + "." + eAttribute.getName());
            } catch (NoSuchMethodException e) {
                LOGGER.error("No getter-method for " + eClass.getName() + "." + eAttribute.getName() + " found!");
            } catch (IllegalAccessException e) {
                LOGGER.error("IllegalAccessException caused by " + eClass.getName() + "." + eAttribute.getName());
            } catch (InvocationTargetException e) {
                LOGGER.error("InocationTargetException caused by " + eClass.getName() + "." + eAttribute.getName());
            }
        }

        return eInstance;
    }

    /**
     * Method to set all eReferences of the actual eInstance
     * 
     * @param eClass
     *          The corresponding {@link EClass} of the instanceClass
     * @param eInstance
     *          The eObject instance which will be edited
     * @param instanceClass
     *          The {@link Class} of the instance
     * @param instance
     *          The corresponding {@link Object} of the edited EObject
     */
    private Collection<EObject> setEReferences(EObject eInstance, Object instance, Map<String, EClass> eClasses) {
        Collection<EObject> result = Lists.newArrayList();
        EClass eClass = eInstance.eClass();
        Class<?> instanceClass = instance.getClass();

        for (EReference eReference : eClass.getEAllReferences()) {
            String referenceName = eReference.getName();
            try {
                Method method = instanceClass.getMethod("get" + capitalize(referenceName));
                if ((!StringUtils.equals(eClass.getName(), "AttributeValue")
                        && !StringUtils.equals(referenceName, "attributeValueAssignments"))) {
                    if (isComponent(eReference)) {
                        Object invoke = method.invoke(instance);

                        if (invoke != null) {
                            EObject componentEObject = createEObjectForComponent(invoke, eClasses);
                            result.add(componentEObject);
                            eInstance.eSet(eReference, componentEObject);
                        }
                    } else {
                        eInstance.eSet(eReference, eObjectFor(method.invoke(instance)));
                    }
                }
            } catch (NoSuchMethodException e) {
                LOGGER.error(
                        "no getter-Method for Reference " + eClass.getName() + "." + referenceName + " found!");
            } catch (IllegalArgumentException e) {
                LOGGER.error("getter-Method for Reference " + eClass.getName() + "." + referenceName
                        + " used with IllegalArgument!");
            } catch (IllegalAccessException e) {
                LOGGER.error("IllegalAccessException caused by " + eClass.getName() + "." + referenceName);
            } catch (InvocationTargetException e) {
                LOGGER.error("InvocationTargetException caused by getter-Method for " + eClass.getName() + "."
                        + referenceName);
            }
        }

        return result;
    }

    private boolean isComponent(EReference eReference) {
        return capitalize(eReference.getName()).equals("RuntimePeriod");
    }

    /**
     * Creates an {@link EObject} for a component-entity (at the moment only for
     * {@link de.iteratec.iteraplan.model.RuntimePeriod RuntimePeriod}-instances
     * 
     * @param component
     *          The Component instance
     * @return The corresponding EObjectInstance
     */
    private EObject createEObjectForComponent(Object component, Map<String, EClass> eClasses) {
        String simpleName = component.getClass().getSimpleName();
        EPackage ePackage = eClasses.get(simpleName).getEPackage();
        EFactory eFactoryInstance = ePackage.getEFactoryInstance();
        EClass eClass = eClasses.get(simpleName);
        EObject result = eFactoryInstance.create(eClass);

        for (EStructuralFeature esf : eClasses.get(component.getClass().getSimpleName())
                .getEAllStructuralFeatures()) {
            if (StringUtils.equals(esf.getName(), "id")) {
                result.eSet(esf, EcoreUtil.generateUUID());
                continue;
            }

            try {
                Method componentMethod = component.getClass().getMethod("get" + capitalize(esf.getName()));
                Object value = componentMethod.invoke(component);
                result.eSet(esf, value);
            } catch (IllegalArgumentException e) {
                LOGGER.error("getting-Method for Reference " + component.getClass().getSimpleName() + "."
                        + esf.getName() + " used with IllegalArgument!");
            } catch (SecurityException e) {
                LOGGER.error("SecurityException caused by " + component.getClass().getSimpleName() + "."
                        + esf.getName());
            } catch (NoSuchMethodException e) {
                LOGGER.error("no getting-Method for Reference " + component.getClass().getSimpleName() + "."
                        + esf.getName() + " found!");
            } catch (IllegalAccessException e) {
                LOGGER.error("IllegalAccessException caused by " + component.getClass().getSimpleName() + "."
                        + esf.getName());
            } catch (InvocationTargetException e) {
                LOGGER.error("InvocationTargetException caused by " + component.getClass().getSimpleName() + "."
                        + esf.getName());
            }
        }

        return result;
    }

    /**
     * Method which returns the emf-value for the given Object
     * 
     * @return The emf-value for the given object
     */
    private Object eObjectFor(Object object) {
        Object value = object;
        if (value == null) {
            return null;
        }

        if (value instanceof Iterable) {
            EList<Object> result = new UniqueEList<Object>();
            for (Object entry : (Iterable<?>) value) {
                if (entry != null) {
                    result.add(eObjectFor(entry));
                }
            }
            return result;
        }

        if (value instanceof Clob) {
            return getClobContent((Clob) value);
        }

        String packageName = value.getClass().getPackage().getName();
        if (SYSTEM_PACKAGE_NAMES.contains(packageName)) {
            return value;
        }

        // the Date stored in the DateAV-instances retrieved from the database is of type java.sql.Date
        // and is therefore skipped when looking for java.util in SYSTEM_PACKAGE_NAMES 
        if (value instanceof java.sql.Date) {
            return new java.util.Date(((java.sql.Date) value).getTime());
        }

        if (value.getClass().equals(Timestamp.class)) {
            return value;
        }

        if (value.getClass().isEnum()) {
            value = value.toString();
        }

        return objectToEObject.get(value);
    }

    /**
     * Returns the content of the specified {@code clob} and returns it. 
     * 
     * @param clob the clob object
     * @return the content or {@code null}, if the content cannot be read
     */
    private Object getClobContent(Clob clob) {
        try {
            Reader characterStream = clob.getCharacterStream();
            return IOUtils.toString(characterStream);
        } catch (IOException e) {
            LOGGER.error("An unexpected error occurred reading the clob", e);
        } catch (SQLException e) {
            LOGGER.error("An unexpected error occurred reading the clob", e);
        }

        return null;
    }

    /**
     * Method which ensures that the eObject for the given enumeration-value is available
     * 
     * @param eAttribute
     *          The {@link EAttribute }
     */
    @SuppressWarnings("cast")
    private void ensureEEnum(EAttribute eAttribute) {
        if (!objectToEObject.containsKey((EEnum) (eAttribute.getEType()))) {
            EEnum eEnum = (EEnum) eAttribute.getEType();
            objectToEObject.put(eEnum.getName(), eEnum);

            for (EEnumLiteral eLiteral : eEnum.getELiterals()) {
                objectToEObject.put(eLiteral.getLiteral(), eLiteral);
            }
        }
    }

    /**
     * Returns the captialized String for the given attributeName used to concatenate method-names
     * (e.g. "get" + capitalize(attributeName))
     * 
     * @param attributeName
     *          a string
     * @return the capitalized String
     */
    private String capitalize(String attributeName) {
        return StringUtils.capitalize(attributeName);
    }
}