/** * <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: * PersistenceMappingBuilder.java,v 1.10 2007/02/08 23:12:35 mtaal Exp $ */ package org.eclipse.emf.teneo.annotations.mapper; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.teneo.PersistenceOptions; import org.eclipse.emf.teneo.annotations.StoreAnnotationsException; import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEAttribute; import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEClass; import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEDataType; import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEPackage; import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedEStructuralFeature; import org.eclipse.emf.teneo.annotations.pamodel.PAnnotatedModel; import org.eclipse.emf.teneo.annotations.parser.EAnnotationParserImporter; import org.eclipse.emf.teneo.annotations.xml.XmlPersistenceMapper; import org.eclipse.emf.teneo.extension.ExtensionManager; import org.eclipse.emf.teneo.extension.ExtensionPoint; import org.eclipse.emf.teneo.util.StoreUtil; /** * Receives a list of ecore files and generates a mapping model using different * strategies. The mapping model is returned. * * @author <a href="mailto:mtaal@elver.org">Martin Taal</a> * @version $Revision: 1.9 $ */ public class PersistenceMappingBuilder implements ExtensionPoint { /** The logger */ protected static final Log log = LogFactory .getLog(PersistenceMappingBuilder.class); /** The instance to use */ public static final PersistenceMappingBuilder INSTANCE = new PersistenceMappingBuilder(); /** * Receives a list of ecore files and returns a Mapping */ public PAnnotatedModel buildMapping(String[] ecoreFiles, PersistenceOptions po, ExtensionManager extensionManager) { return buildMapping(StoreUtil.readEPackages(ecoreFiles), po, extensionManager); } /** * Builds a persistence mapping for one or more epackages * * @Deprecated use the method with the List<EPackage> parameter */ public PAnnotatedModel buildMapping(EPackage[] epackages, PersistenceOptions po, ExtensionManager extensionManager) { return buildMapping(Arrays.asList(epackages), po, extensionManager); } /** * Builds a persistence mapping for one or more epackages */ public PAnnotatedModel buildMapping(List<EPackage> epacks, PersistenceOptions po, ExtensionManager extensionManager) { // read the subepackages final List<EPackage> epackages = new ArrayList<EPackage>(); for (EPackage epack : epacks) { resolveSubPackages(epack, epackages); } // DCB: Introduce indirection so that extensions to annotation // processing mechanism // can provide their own model builder. BasicPamodelBuilder pamodelBuilder = extensionManager .getExtension(BasicPamodelBuilder.class); log.debug("Creating pamodel for the following epackages"); for (EPackage element : epackages) { log.debug(element.getName()); pamodelBuilder.addRecurse(element); } log.debug("Create base pannotated model"); PAnnotatedModel pam = pamodelBuilder.getPAnnotatedModel(); log .debug("Deprecated eannotations with http://annotations.elver.org or http://ejb.elver.org are ignored."); // if (po.isIgnoreEAnnotations()) { // log.debug("Ignoring eannotations"); // } else { // log.debug("Import eannotations"); // // DCB: Introduce indirection so that extensions to annotation // processing mechanism // // can provide their own model builder. // EannotationPamodelBuilder epb = getAnnotationModelBuilder(); // epb.setPAnnotatedModel(pam); // epb.processCurrentPAnnotatedModel(); // } if (po.isIgnoreEAnnotations()) { log.debug("Ignoring annotations"); } else { log.debug("Parse annotations"); extensionManager.getExtension(EAnnotationParserImporter.class) .process(pam); } if (po.getPersistenceXmlPath() != null) { try { final PersistenceFileProvider fileProvider = extensionManager .getExtension(PersistenceFileProvider.class); final InputStream in = fileProvider.getFileContent(null, po .getPersistenceXmlPath()); if (in == null) { throw new RuntimeException( "Could not find persistence XML resource in classpath: \"" + po.getPersistenceXmlPath() + "\"."); } final XmlPersistenceMapper xmlPersistenceMapper = extensionManager .getExtension(XmlPersistenceMapper.class); xmlPersistenceMapper.setXmlMapping(in); xmlPersistenceMapper.applyPersistenceMapping(pam); in.close(); final InputStream[] iss = getAdditionalXMLMappings(); for (InputStream element : iss) { xmlPersistenceMapper.setXmlMapping(element); xmlPersistenceMapper.applyPersistenceMapping(pam); element.close(); } } catch (IOException e) { throw new StoreAnnotationsException( "Exception while loading xml persistence mappings", e); } } // now the annotations on the edatatype should be copied to the // annotations on the // eattribute, overwrite may not occur! processEDataTypeAnnotations(pam); log.debug("Add default annotations"); // DCB: Introduce indirection so that extensions to annotation // processing mechanism // can provide their own default annotation. pam.setInitialized(true); extensionManager.getExtension(AnnotationGenerator.class).map(pam, po); log.debug("Returning created pamodel"); return pam; } private void resolveSubPackages(EPackage epack, List<EPackage> epacks) { if (!epacks.contains(epack)) { epacks.add(epack); } for (EPackage subEPackage : epack.getESubpackages()) { resolveSubPackages(subEPackage, epacks); } } /** * For each pannotated eattribute find the pannotated edatatype and copy the * values of the estructuralfeature if not yet set in the eattribute */ protected void processEDataTypeAnnotations(PAnnotatedModel pam) { log .debug("Copying annotations on edatatypes over eattribute annotations!"); for (PAnnotatedEPackage pep : pam.getPaEPackages()) { for (PAnnotatedEClass pec : pep.getPaEClasses()) { for (PAnnotatedEStructuralFeature pef : pec .getPaEStructuralFeatures()) { if (pef instanceof PAnnotatedEAttribute) { final PAnnotatedEAttribute pea = (PAnnotatedEAttribute) pef; final EDataType et = pea.getModelEAttribute() .getEAttributeType(); final PAnnotatedEDataType ped = pam.getPAnnotated(et); if (ped == null) { continue; // not an explicit modeled edatatype } for (EStructuralFeature esf : ped.eClass() .getEAllStructuralFeatures()) { final EStructuralFeature asf = pea.eClass() .getEStructuralFeature(esf.getName()); if (asf != null && !pea.eIsSet(asf) && ped.eIsSet(esf)) { log.debug("Copying value for feature " + esf.getName() + " from edatatype " + et.getName() + " to " + pea.getModelEAttribute().getName()); final Object obj = ped.eGet(esf); if (obj instanceof Collection) { pea.eSet(asf, EcoreUtil .copyAll((Collection<?>) obj)); } else if (obj instanceof EObject) { pea .eSet(asf, EcoreUtil .copy((EObject) obj)); } else { throw new StoreAnnotationsException( "Class " + obj.getClass().getName() + " not supported should be eobject or collection"); } } } } } } } } /** Additional inputstreams for xml mappings */ protected InputStream[] getAdditionalXMLMappings() { return new InputStream[0]; } }