/* * Copyright (c) 2008-2012, 2015, 2016 Eike Stepper (Berlin, Germany) 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 - initial API and implementation * Eike Stepper - maintenance */ package org.eclipse.emf.cdo.server.hibernate.internal.teneo; import org.eclipse.emf.cdo.eresource.EresourcePackage; import org.eclipse.emf.cdo.etypes.EtypesPackage; import org.eclipse.emf.cdo.security.SecurityPackage; import org.eclipse.emf.cdo.server.hibernate.internal.teneo.bundle.OM; import org.eclipse.emf.cdo.server.hibernate.teneo.CDOMappingGenerator; import org.eclipse.emf.cdo.server.internal.hibernate.CDOHibernateConstants; import org.eclipse.emf.cdo.server.internal.hibernate.HibernateMappingProvider; import org.eclipse.emf.cdo.server.internal.hibernate.HibernateStore; import org.eclipse.emf.cdo.server.internal.hibernate.tuplizer.CDOBlobUserType; import org.eclipse.emf.cdo.server.internal.hibernate.tuplizer.CDOClobUserType; import org.eclipse.emf.cdo.server.internal.hibernate.tuplizer.CDOIDUserType; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcoreFactory; import org.eclipse.emf.ecore.xml.type.XMLTypePackage; import org.eclipse.emf.teneo.Constants; import org.eclipse.emf.teneo.PackageRegistryProvider; import org.eclipse.emf.teneo.PersistenceOptions; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Properties; /** * Uses the ecore string in the ePackages of the store to generate a mapping. * * @author Martin Taal * @author Eike Stepper * @since 3.0 */ public class TeneoHibernateMappingProvider extends HibernateMappingProvider { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, TeneoHibernateMappingProvider.class); private Map<String, String> extensions = new HashMap<String, String>(); private Properties mappingProviderProperties = new Properties(); public TeneoHibernateMappingProvider() { } public void putExtension(String extensionClassName, String extendingClassName) { extensions.put(extensionClassName, extendingClassName); } @Override public HibernateStore getHibernateStore() { return (HibernateStore)super.getHibernateStore(); } public String getMapping() { final String mapping = generateMapping(); if (TRACER.isEnabled()) { TRACER.trace("Generated hibernate mapping:"); //$NON-NLS-1$ TRACER.trace(mapping); } return mapping; } // the passed modelObjects collection is defined as a collection of Objects // to prevent binary dependency on emf. public String generateMapping() { if (TRACER.isEnabled()) { TRACER.trace("Generating Hibernate Mapping"); //$NON-NLS-1$ } final Properties storeProperties = getHibernateStore().getProperties(); // merge the store properties with the mapping provider properties // the mapping provider props take precedence // this also prevents overwriting the original properties final Properties properties = new Properties(); properties.putAll(storeProperties); properties.putAll(mappingProviderProperties); PackageRegistryProvider.getInstance().setThreadPackageRegistry(getHibernateStore().getRepository().getPackageRegistry()); // translate the list of EPackages to an array boolean hasXMLTypePackage = false; final List<EPackage> epacks = getHibernateStore().getModelEPackages(); final ListIterator<EPackage> iterator = epacks.listIterator(); while (iterator.hasNext()) { final EPackage epack = iterator.next(); if (epack == XMLTypePackage.eINSTANCE) { hasXMLTypePackage = true; } if (SecurityPackage.eNS_URI.equals(epack.getNsURI())) { setEntityOnSecurityModel(epack); } } if (hasXMLTypePackage) { addTypeAnnotationToXMLTypes(); } addUniqueConstraintAnnotation(); final EPackage[] ePackageArray = epacks.toArray(new EPackage[epacks.size()]); // remove the persistence xml if no epackages as this won't work without // epackages if (ePackageArray.length == 0 && properties.getProperty(PersistenceOptions.PERSISTENCE_XML) != null) { properties.remove(PersistenceOptions.PERSISTENCE_XML); } properties.setProperty(PersistenceOptions.FEATUREMAP_AS_COMPONENT, "true"); // add some annotations to the CDO model so that the mapping gets generated correctly addTransientAnnotationToEClass(EtypesPackage.eINSTANCE.getModelElement()); addTransientAnnotationToEClass(EtypesPackage.eINSTANCE.getAnnotation()); addTypeAnnotationToEDataType(EtypesPackage.eINSTANCE.getBlob(), CDOBlobUserType.class.getName()); addTypeAnnotationToEDataType(EtypesPackage.eINSTANCE.getClob(), CDOClobUserType.class.getName()); addTypeAnnotationToAuditingResourcePackage(); final CDOMappingGenerator mappingGenerator = new CDOMappingGenerator(); mappingGenerator.getExtensions().putAll(extensions); String hbm = mappingGenerator.generateMapping(ePackageArray, properties); // to solve an issue with older versions of teneo hbm = hbm.replaceAll("_cont", "cont"); //$NON-NLS-1$ //$NON-NLS-2$ // System.err.println(hbm); return hbm; } private void setEntityOnSecurityModel(EPackage ePackage) { for (EClassifier eClassifier : ePackage.getEClassifiers()) { if (eClassifier instanceof EClass) { final EClass eClass = (EClass)eClassifier; if (eClass.getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA) != null) { return; } final EAnnotation eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation(); eAnnotation.setSource(Constants.ANNOTATION_SOURCE_TENEO_JPA); eAnnotation.getDetails().put("value", "@Entity(name=\"CdoSecurity" + eClass.getName() + "\")"); eClass.getEAnnotations().add(eAnnotation); } } } private void addTypeAnnotationToXMLTypes() { for (EClassifier eClassifier : XMLTypePackage.eINSTANCE.getEClassifiers()) { if (eClassifier instanceof EDataType) { final EDataType eDataType = (EDataType)eClassifier; if (eDataType.getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA) != null) { continue; } final EAnnotation eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation(); eAnnotation.setSource(Constants.ANNOTATION_SOURCE_TENEO_JPA); final String typeAnnotation = "@Type(type=\"org.eclipse.emf.cdo.server.internal.hibernate.tuplizer.XMLUserType$" + eDataType.getName() + "\")"; eAnnotation.getDetails().put("value", typeAnnotation); eDataType.getEAnnotations().add(eAnnotation); } } } private void addTypeAnnotationToEDataType(EDataType eDataType, String type) { if (eDataType.getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA) != null) { return; } { final EAnnotation eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation(); eAnnotation.setSource(Constants.ANNOTATION_SOURCE_TENEO_JPA); final String typeAnnotation = "@Type(type=\"" + type + "\")"; eAnnotation.getDetails().put("value", typeAnnotation); eDataType.getEAnnotations().add(eAnnotation); } { final EAnnotation eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation(); eAnnotation.setSource(Constants.ANNOTATION_SOURCE_TENEO_JPA_AUDITING); final String typeAnnotation = "@Type(type=\"" + type + "\")"; eAnnotation.getDetails().put("value", typeAnnotation); eDataType.getEAnnotations().add(eAnnotation); } } private void addTypeAnnotationToAuditingResourcePackage() { addTypeAnnotationToAuditingResourceContents(EresourcePackage.eINSTANCE.getCDOResource_Contents()); addTypeAnnotationToAuditingResourceContents(EresourcePackage.eINSTANCE.getCDOResourceFolder_Nodes()); } private void addTypeAnnotationToAuditingResourceContents(EStructuralFeature eFeature) { EAnnotation eAnnotation = eFeature.getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA_AUDITING); if (eAnnotation != null) { return; } eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation(); eAnnotation.setSource(Constants.ANNOTATION_SOURCE_TENEO_JPA_AUDITING); final String typeAnnotation = "@Type(type=\"" + CDOIDUserType.class.getName() + "\")"; eAnnotation.getDetails().put("value", typeAnnotation); eFeature.getEAnnotations().add(eAnnotation); } private void addTransientAnnotationToEClass(EClass eClass) { if (eClass.getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA) != null) { return; } final EAnnotation eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation(); eAnnotation.setSource(Constants.ANNOTATION_SOURCE_TENEO_JPA); final String transientAnnotation = "@Transient"; eAnnotation.getDetails().put("value", transientAnnotation); eClass.getEAnnotations().add(eAnnotation); } // see the CDOEntityMapper, there an explicit unique-key is added to // a column also private void addUniqueConstraintAnnotation() { final EClass eClass = EresourcePackage.eINSTANCE.getCDOResourceNode(); // already been here if (eClass.getEAnnotation("teneo.jpa") != null) //$NON-NLS-1$ { return; } final EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource("teneo.jpa"); //$NON-NLS-1$ final String tableAnnotation = "@Table(uniqueConstraints={@UniqueConstraint(columnNames={\"" //$NON-NLS-1$ + CDOHibernateConstants.CONTAINER_PROPERTY_COLUMN + "\", \"" //$NON-NLS-1$ + EresourcePackage.eINSTANCE.getCDOResourceNode_Name().getName() + "\"})})"; //$NON-NLS-1$ annotation.getDetails().put("value", tableAnnotation); //$NON-NLS-1$ eClass.getEAnnotations().add(annotation); } public Properties getMappingProviderProperties() { return mappingProviderProperties; } public void setMappingProviderProperties(Properties mappingProviderProperties) { this.mappingProviderProperties = mappingProviderProperties; } }