blob: 2e41a5e59f8ff400fad398368b84d25205ba747e [file] [log] [blame]
/*
* Copyright (c) 2012, 2015 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:
* Eike Stepper - initial API and implementation
* Martin Taal - moved cdopackage handler to other class, changed configuration
*/
package org.eclipse.emf.cdo.server.internal.hibernate;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionData;
import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.emf.teneo.Constants;
import org.eclipse.emf.teneo.hibernate.auditing.AuditHandler;
import org.eclipse.emf.teneo.hibernate.auditing.model.teneoauditing.TeneoAuditEntry;
import org.hibernate.Session;
import java.lang.reflect.Array;
import java.util.Collection;
/**
* Overrides the {@link AuditHandler} to implement CDO
* specific audit handling.
*
* @author Martin Taal
*/
public class CDOAuditHandler extends AuditHandler
{
@Override
public void setContainerInfo(Session session, TeneoAuditEntry teneoAuditEntry, Object object)
{
final InternalCDORevision cdoRevision = (InternalCDORevision)object;
teneoAuditEntry.setTeneo_container_feature_id(cdoRevision.getContainingFeatureID());
teneoAuditEntry
.setTeneo_container_id(HibernateUtil.getInstance().convertCDOIDToString((CDOID)cdoRevision.getContainerID()));
}
@Override
public boolean isAudited(Object entity)
{
if (!(entity instanceof CDORevision))
{
// TODO: support featuremap entries
return false;
}
if (!getDataStore().isAuditing())
{
return false;
}
final CDORevision cdoRevision = (CDORevision)entity;
final EClass auditEClass = getAuditingModelElement(cdoRevision.getEClass());
return auditEClass != null;
}
public boolean isAudited(CDOID id)
{
if (!getDataStore().isAuditing())
{
return false;
}
if (!(id instanceof CDOClassifierRef.Provider))
{
return false;
}
CDOClassifierRef cdoClassifierRef = ((CDOClassifierRef.Provider)id).getClassifierRef();
final EClass eClass = HibernateUtil.getInstance().getEClass(cdoClassifierRef);
if (eClass == null)
{
return false;
}
final EClass auditEClass = getAuditingModelElement(eClass);
return auditEClass != null;
}
@Override
protected boolean supportCustomType()
{
return true;
}
@Override
public EClass getEClass(Object o)
{
if (o instanceof EObject)
{
return ((EObject)o).eClass();
}
return ((CDORevision)o).getEClass();
}
@SuppressWarnings("unchecked")
@Override
public void copyContentToAuditEntry(Session session, Object object, TeneoAuditEntry auditEntry,
boolean copyCollections)
{
final InternalCDORevision source = (InternalCDORevision)object;
final EClass sourceEClass = source.getEClass();
final EClass targetEClass = auditEntry.eClass();
for (EStructuralFeature targetEFeature : targetEClass.getEAllStructuralFeatures())
{
if (!copyCollections && targetEFeature.isMany())
{
continue;
}
// part of a featuremap
if (ExtendedMetaData.INSTANCE.getGroup(targetEFeature) != null)
{
continue;
}
// initialize with new arrays always to prevent hibernate from complaining if the
// same array is re-used accross entities
if (targetEFeature.getEType().getInstanceClass() != null
&& targetEFeature.getEType().getInstanceClass().isArray())
{
auditEntry.eSet(targetEFeature,
Array.newInstance(targetEFeature.getEType().getInstanceClass().getComponentType(), 0));
}
final EStructuralFeature sourceEFeature = sourceEClass.getEStructuralFeature(targetEFeature.getName());
if (sourceEFeature != null)
{
if (targetEFeature instanceof EAttribute && sourceEFeature instanceof EReference)
{
if (sourceEFeature.isMany())
{
for (Object value : (Collection<?>)source.getList(sourceEFeature))
{
final String idAsString = entityToIdString(session, value);
((Collection<Object>)auditEntry.eGet(targetEFeature)).add(idAsString);
}
}
else
{
final String idAsString = entityToIdString(session, source.getValue(sourceEFeature));
auditEntry.eSet(targetEFeature, idAsString);
}
}
else
{
if (sourceEFeature.isMany())
{
if (FeatureMapUtil.isFeatureMap(sourceEFeature))
{
convertFeatureMap(session, source, sourceEFeature, auditEntry, targetEFeature);
}
else
{
for (Object value : (Collection<?>)source.getList(sourceEFeature))
{
((Collection<Object>)auditEntry.eGet(targetEFeature))
.add(convertValue(sourceEFeature, targetEFeature, value));
}
}
}
else
{
// not set
if (sourceEFeature.isUnsettable() && source.getValue(sourceEFeature) == null)
{
auditEntry.eUnset(targetEFeature);
}
else
{
auditEntry.eSet(targetEFeature,
convertValue(sourceEFeature, targetEFeature, source.getValue(sourceEFeature)));
}
}
}
}
}
}
@Override
protected EStructuralFeature createEMapFeature(EStructuralFeature sourceEFeature, EClass eMapEntryEClass)
{
return createEReferenceAttribute((EReference)sourceEFeature);
}
protected void convertEMap(Session session, InternalCDORevision source, EReference sourceEReference,
TeneoAuditEntry auditEntry, EReference targetEReference)
{
throw new IllegalStateException("Error case: The system should not use this method when doing auditing in CDO");
}
protected void convertFeatureMap(Session session, InternalCDORevision source, EStructuralFeature sourceEFeature,
TeneoAuditEntry auditEntry, EStructuralFeature targetEFeature)
{
super.convertFeatureMap(session, source.getList(sourceEFeature), sourceEFeature, auditEntry, targetEFeature);
}
@Override
public String entityToIdString(Session session, Object entity)
{
if (entity == null || entity == InternalCDORevision.NIL)
{
return null;
}
CDOID cdoID;
if (entity instanceof CDOID)
{
cdoID = (CDOID)entity;
}
else
{
final CDORevision cdoRevision = (CDORevision)entity;
cdoID = cdoRevision.getID();
}
if (cdoID == CDOID.NULL)
{
return null;
}
// get the correct id
if (HibernateThreadContext.isCommitContextSet())
{
final CommitContext commitContext = HibernateThreadContext.getCommitContext().getCommitContext();
CDOID newID = cdoID;
int cnt = 0;
while (commitContext.getIDMappings().containsKey(newID))
{
newID = commitContext.getIDMappings().get(newID);
cnt++;
if (cnt > 1000)
{
throw new IllegalStateException(
"Cycle detected in id mappings " + newID + " maps to " + commitContext.getIDMappings().get(newID));
}
}
cdoID = newID;
}
return HibernateUtil.getInstance().convertCDOIDToString(cdoID);
}
@Override
public String idToString(EClass eClass, Object id)
{
return HibernateUtil.getInstance().convertCDOIDToString((CDOID)id);
}
public Object convertValue(EStructuralFeature sourceEFeature, EStructuralFeature eFeature, Object value)
{
if (value == CDORevisionData.NIL)
{
return null;
}
if (value instanceof EEnumLiteral)
{
return ((EEnumLiteral)value).getLiteral();
}
if (value instanceof Enumerator)
{
return ((Enumerator)value).getLiteral();
}
if (sourceEFeature.getEType() instanceof EEnum && value instanceof Integer)
{
final int ordinal = (Integer)value;
final EEnum eeNum = (EEnum)sourceEFeature.getEType();
if (eeNum.getInstanceClass() != null && eeNum.getInstanceClass().isEnum())
{
final Object[] constants = eeNum.getInstanceClass().getEnumConstants();
for (Object constant : constants)
{
if (constant instanceof Enumerator)
{
final Enumerator enumerator = (Enumerator)constant;
if (enumerator.getValue() == ordinal)
{
return enumerator.getLiteral();
}
}
}
return ((Enum<?>)constants[ordinal]).name();
}
return eeNum.getEEnumLiteral((Integer)value).getLiteral();
}
return super.convertValue(eFeature, value);
}
// map all enums as string
@Override
protected EStructuralFeature createEAttribute(EAttribute eAttribute)
{
final EStructuralFeature eFeature = super.createEAttribute(eAttribute);
if (eFeature.getEType() instanceof EEnum)
{
eFeature.setEType(EcorePackage.eINSTANCE.getEString());
// add a dummy teneo.jpa to prevent anyone of accidentally mapping
// enumerated in a different way
// set in the source efeature will be found there
if (eAttribute.getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA_AUDITING) == null)
{
final EAnnotation eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
eAnnotation.setSource(Constants.ANNOTATION_SOURCE_TENEO_JPA_AUDITING);
eAnnotation.getDetails().put(Constants.ANNOTATION_KEY_VALUE, "");
eAttribute.getEAnnotations().add(eAnnotation);
}
return eFeature;
}
if (isCustomType(eAttribute.getEAttributeType()))
{
if (!isTeneoAnnotated(eAttribute))
{
eFeature.setEType(EcorePackage.eINSTANCE.getEString());
}
}
return eFeature;
}
private boolean isTeneoAnnotated(EAttribute eAttribute)
{
return eAttribute.getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA) != null
|| eAttribute.getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA) != null
|| eAttribute.getEAttributeType().getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA_AUDITING) != null
|| eAttribute.getEAttributeType().getEAnnotation(Constants.ANNOTATION_SOURCE_TENEO_JPA) != null;
}
}