/**
* <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
* Michael Kanaley, TIBCO Software Inc., custom type handling
* </copyright>
*
* $Id: HibernateMappingGenerator.java,v 1.24 2009/03/07 21:15:19 mtaal Exp $
*/
package org.eclipse.emf.teneo.hibernate.mapper;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.teneo.PersistenceOptions;
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.PAnnotatedModel;
import org.eclipse.emf.teneo.annotations.pannotation.PannotationFactory;
import org.eclipse.emf.teneo.extension.ExtensionManager;
import org.eclipse.emf.teneo.extension.ExtensionManagerAware;
import org.eclipse.emf.teneo.extension.ExtensionPoint;
import org.eclipse.emf.teneo.hibernate.hbannotation.FilterDef;
import org.eclipse.emf.teneo.hibernate.hbannotation.NamedQuery;
import org.eclipse.emf.teneo.hibernate.hbannotation.ParamDef;
import org.eclipse.emf.teneo.hibernate.hbannotation.Parameter;
import org.eclipse.emf.teneo.hibernate.hbannotation.TypeDef;
import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEClass;
import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEDataType;
import org.eclipse.emf.teneo.hibernate.hbmodel.HbAnnotatedEPackage;
import org.eclipse.emf.teneo.mapping.strategy.impl.ClassicEntityNameStrategy;
import org.eclipse.emf.teneo.simpledom.Document;
import org.eclipse.emf.teneo.simpledom.DocumentHelper;
import org.eclipse.emf.teneo.simpledom.Element;
import org.eclipse.emf.teneo.util.StoreUtil;
/**
* The main starting point for generating a hibernate mapping from a PAnnotated
* model.
*
* @author <a href="mailto:mtaal at elver.org">Martin Taal</a>
*/
public class HibernateMappingGenerator implements ExtensionPoint,
ExtensionManagerAware {
/** The logger */
private static final Log log = LogFactory
.getLog(HibernateMappingGenerator.class);
/** The list of processed annotated classes */
private Set<PAnnotatedEClass> processedPAClasses = null;
/** the mapping context */
private MappingContext hbmContext;
/** The extensionManager */
private ExtensionManager extensionManager;
/** The persistenceoptions */
private PersistenceOptions persistenceOptions;
/**
* Register the entity names in context.
*/
protected void initEntityNames(MappingContext hbmContext,
PAnnotatedModel paModel) {
for (PAnnotatedEPackage pae : paModel.getPaEPackages()) {
for (PAnnotatedEClass paClass : pae.getPaEClasses()) {
if (paClass.getEntity() != null) {
hbmContext.setEntityName(paClass.getModelEClass(),
getEntityName(paClass));
}
}
}
}
/**
* @return Returns the entity name for the given paClass
*/
protected String getEntityName(PAnnotatedEClass paClass) {
final EClass eclass = paClass.getModelEClass();
String name = paClass.getEntity().getName();
if (name == null) {
// TODO sure we do not need package here?
// MT: I think for 99.9% of the cases there are no name clashes but
// it is possible to
// that a package name is required to make things unique. This can
// be done in a next
// release as an
// optional feature.
name = hbmContext.getEntityNameStrategy().toEntityName(eclass);
}
return name;
}
/** Generate a hibernate mapping xml document from the pamodel */
public Document generate(PAnnotatedModel paModel) throws MappingException {
if (log.isDebugEnabled()) {
log.debug("Geneting Hibernate mapping for " + paModel);
}
try {
this.hbmContext = getExtensionManager().getExtension(
MappingContext.class);
this.hbmContext.setMappingProperties(getPersistenceOptions());
hbmContext.setPaModel(paModel);
hbmContext.beginDocument(createDocument());
initEntityNames(hbmContext, paModel);
processTypedefs(paModel);
processPersistentClasses(paModel);
// Process Named Queries
// Added by PhaneeshN
// This will emit the named query implementation into the mapping
// based on model annotation @NamedQuery(name={name},
// query={query});
// Named queries can be parameterized
for (PAnnotatedEPackage paPackage : paModel.getPaEPackages()) {
processPANamedQueries(paPackage);
for (PAnnotatedEClass paEClass : paPackage.getPaEClasses()) {
processPANamedQueries(paEClass);
}
}
return hbmContext.endDocument();
} catch (MappingException exc) {
throw new MappingException("Hibernate mapping generation failed",
exc);
}
}
/**
* Generate the hibernate mapping xml as a string
*/
public String generateToString(PAnnotatedModel annotatedModel)
throws MappingException {
return generate(annotatedModel).emitXML();
}
/**
* @return Returns an empty document used as template for the genration.
*/
protected Document createDocument() {
Document mappingDoc = new Document();
mappingDoc
.setDocType("<!DOCTYPE hibernate-mapping PUBLIC \"-//Hibernate/Hibernate Mapping DTD 3.0//EN\" "
+ "\"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd\">");
mappingDoc.setRoot(DocumentHelper.createElement("hibernate-mapping"));
// set auto-import is false if the default eclass naming strategy is not
// used
if (!(hbmContext.getEntityNameStrategy() instanceof ClassicEntityNameStrategy)) {
log
.debug("Setting auto-import=false because eclassnamingstrategy is not the defaulteclassnamestrategy");
mappingDoc.getRoot().addAttribute("auto-import", "false");
}
return mappingDoc;
}
/** Process all annotated classes of the pamodel */
protected void processPersistentClasses(PAnnotatedModel paModel) {
try {
processedPAClasses = new HashSet<PAnnotatedEClass>();
for (PAnnotatedEPackage paPackage : paModel.getPaEPackages()) {
for (PAnnotatedEClass paEClass : paPackage.getPaEClasses()) {
// here, we eliminate map.enties
if (!hbmContext.isMapEMapAsTrueMap()
|| !StoreUtil.isMapEntry(paEClass.getModelEClass())) {
processPAClass(paEClass);
}
mapFilterDef(hbmContext.getCurrent(),
((HbAnnotatedEClass) paEClass).getFilterDef());
}
mapFilterDef(hbmContext.getCurrent(),
((HbAnnotatedEPackage) paPackage).getFilterDef());
}
} finally {
processedPAClasses = null;
}
}
protected void mapFilterDef(Element parentElement,
List<FilterDef> filterDefs) {
for (FilterDef fd : filterDefs) {
final Element fdElement = parentElement.addElement("filter-def");
fdElement.addAttribute("name", fd.getName());
if (fd.getDefaultCondition() != null) {
fdElement.addAttribute("condition", fd.getDefaultCondition());
}
for (ParamDef pd : fd.getParameters()) {
final Element pdElement = fdElement.addElement("filter-param");
pdElement.addAttribute("name", pd.getName());
pdElement.addAttribute("type", pd.getType());
}
}
}
/**
* Process the given class, ensures that processing order is consistent with
* inheritance order. The given paEClass is added to the processedPAClasses.
*/
protected void processPAClass(PAnnotatedEClass paEClass) {
if (processedPAClasses.add(paEClass)) {
// also mapped superclasses can have an entity but ignore them here
if (paEClass.getEntity() != null
&& paEClass.getMappedSuperclass() == null) {
// this is a persistent entity
PAnnotatedEClass paSuperEntity = paEClass.getPaSuperEntity();
if (paSuperEntity != null) {
// enforce processing order consistent with inheritance
// order
processPAClass(paSuperEntity);
}
// ignore the map entries which do not have an explicit entity
if (paEClass.getModelEClass().getInstanceClass() == Map.Entry.class
&& paEClass.getEntity() == null) {
log.debug("Ignoring " + paEClass.getModelEClass().getName()
+ " ignored, is a map entry");
paEClass.setTransient(PannotationFactory.eINSTANCE
.createTransient());
return;
}
hbmContext.setCurrentEClass(paEClass.getModelEClass());
hbmContext.getEntityMapper().processEntity(paEClass);
} else if (log.isDebugEnabled()) {
log.debug("Skipping non-persistent class " + paEClass);
}
}
}
/**
* Processes the typedef annotations and creates corresponding typedef
* instances in the mapping.
*/
protected void processTypedefs(PAnnotatedModel paModel) {
// Walk thru all the packages looking for custom EDataTypes.
for (PAnnotatedEPackage annotatedEPackage : paModel.getPaEPackages()) {
HbAnnotatedEPackage paPackage = (HbAnnotatedEPackage) annotatedEPackage;
// handle the typedefs
for (TypeDef td : paPackage.getHbTypeDef()) {
emitTypeDef(td);
}
// Walk thru all the classifiers of the given package.
for (PAnnotatedEDataType annotatedEDataType : paPackage
.getPaEDataTypes()) {
final HbAnnotatedEDataType hed = (HbAnnotatedEDataType) annotatedEDataType;
if (hed.getHbTypeDef() != null) {
emitTypeDef(hed.getHbTypeDef());
}
}
}
}
/**
* Process the given class and declare named queries that are annotated as
* Model Annotations
*
* @author PhaneeshN <a
* href="mailto:phaneesh.nagararaja@sos.sungard.com">phaneesh
* .nagararaja@sos.sungard.com</a> <a
* href="http://www.sungardhe.com">SunGard Higher Education</a>
*/
protected void processPANamedQueries(PAnnotatedEClass paEClass) {
// TODO: Should be refactored into a NamedQueryMapper Extension and
// register it into
// extension Manager
if (log.isDebugEnabled()) {
log.debug("Processing Queries for "
+ paEClass.getModelEClass().getName());
}
if (log.isDebugEnabled()) {
log
.debug("********************** Named Queries ***************************");
for (NamedQuery namedQuery : ((HbAnnotatedEClass) paEClass)
.getHbNamedQuery()) {
log.info(namedQuery.getName() + ":" + namedQuery.getQuery());
}
log
.debug("****************************************************************");
}
for (NamedQuery namedQuery : ((HbAnnotatedEClass) paEClass)
.getHbNamedQuery()) {
final Element target = this.hbmContext.getCurrent().addElement(
"query");
target.addAttribute("name", namedQuery.getName());
target.addText("<![CDATA[" + namedQuery.getQuery() + "]]>");
}
}
protected void processPANamedQueries(PAnnotatedEPackage paEPackage) {
// TODO: Should be refactored into a NamedQueryMapper Extension and
// register it into
// extension Manager
if (log.isDebugEnabled()) {
log.debug("Processing Queries for "
+ paEPackage.getModelEPackage().getName());
}
if (log.isDebugEnabled()) {
log
.debug("********************** Named Queries ***************************");
for (NamedQuery namedQuery : ((HbAnnotatedEPackage) paEPackage)
.getHbNamedQuery()) {
log.info(namedQuery.getName() + ":" + namedQuery.getQuery());
}
log
.debug("****************************************************************");
}
for (NamedQuery namedQuery : ((HbAnnotatedEPackage) paEPackage)
.getHbNamedQuery()) {
final Element target = this.hbmContext.getCurrent().addElement(
"query");
target.addAttribute("name", namedQuery.getName());
target.addText("<![CDATA[" + namedQuery.getQuery() + "]]>");
}
}
/** Emit a typedef */
protected void emitTypeDef(TypeDef td) {
final Element target = this.hbmContext.getCurrent().addElement(
"typedef");
target.addAttribute("name", td.getName());
target.addAttribute("class", td.getTypeClass());
for (Parameter param : td.getParameters()) {
target.addElement("param").addAttribute("name", param.getName())
.addText(param.getValue());
}
}
/**
* @return the extensionManager
*/
public ExtensionManager getExtensionManager() {
return extensionManager;
}
/**
* @param extensionManager
* the extensionManager to set
*/
public void setExtensionManager(ExtensionManager extensionManager) {
// set the default extensions for mapping in the extensionManager
this.extensionManager = extensionManager;
}
/**
* @return the persistenceOptions
*/
public PersistenceOptions getPersistenceOptions() {
return persistenceOptions;
}
/**
* @param persistenceOptions
* the persistenceOptions to set
*/
public void setPersistenceOptions(PersistenceOptions persistenceOptions) {
this.persistenceOptions = persistenceOptions;
}
}