/*
Copyright (C) 2009 by Claas Wilke (claaswilke@gmx.net)
This file is part of the EMF Ecore Model Instance Type of Dresden OCL2 for Eclipse.
Dresden OCL2 for Eclipse is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your option)
any later version.
Dresden OCL2 for Eclipse 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 Lesser General Public License
for more details.
You should have received a copy of the GNU Lesser General Public License along
with Dresden OCL2 for Eclipse. If not, see <http://www.gnu.org/licenses/>.
*/
package org.dresdenocl.modelinstancetype.ecore.internal.modelinstance;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import org.apache.log4j.Logger;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.osgi.util.NLS;
import org.dresdenocl.model.IModel;
import org.dresdenocl.model.ModelAccessException;
import org.dresdenocl.modelinstancetype.ecore.EcoreModelInstanceTypePlugin;
import org.dresdenocl.modelinstancetype.ecore.internal.msg.EcoreModelInstanceTypeMessages;
import org.dresdenocl.modelinstancetype.ecore.internal.util.EcoreModelInstanceTypeUtility;
import org.dresdenocl.modelinstancetype.exception.TypeNotFoundInModelException;
import org.dresdenocl.modelinstancetype.types.IModelInstanceElement;
import org.dresdenocl.modelinstancetype.types.IModelInstanceEnumerationLiteral;
import org.dresdenocl.modelinstancetype.types.IModelInstanceFactory;
import org.dresdenocl.modelinstancetype.types.base.BasisJavaModelInstanceFactory;
import org.dresdenocl.modelinstancetype.types.base.ModelInstanceEnumerationLiteral;
import org.dresdenocl.pivotmodel.Enumeration;
import org.dresdenocl.pivotmodel.EnumerationLiteral;
import org.dresdenocl.pivotmodel.Type;
/**
* <p>
* This factory can be used to create {@link IModelInstanceElement} for given
* {@link EObject}s.
* </p>
*
* @author Claas Wilke
*/
public class EcoreModelInstanceFactory extends BasisJavaModelInstanceFactory
implements IModelInstanceFactory {
/** The {@link Logger} for this class. */
private static final Logger LOGGER = EcoreModelInstanceTypePlugin
.getLogger(EcoreModelInstanceFactory.class);
/**
* The already adapted {@link IModelInstanceElement}s of this
* {@link EcoreModelInstanceFactory}. <strong>This is a {@link WeakHashMap}!
* If an {@link EObject} is disposed, its adapted
* {@link IModelInstanceElement} will be disposed as well.</p>
*/
private Map<EObject, IModelInstanceElement> myCachedAdaptedObjects = new WeakHashMap<EObject, IModelInstanceElement>();
/** The IModel for that the {@link IModelInstanceElement}s will be created. */
private IModel myModel;
/**
* The {@link EcoreModelInstanceTypeUtility} used to find {@link Type}s in
* the {@link IModel}.
*/
private EcoreModelInstanceTypeUtility myTypeUtility;
/**
* <p>
* Creates a new {@link EcoreModelInstanceFactory} for a given
* {@link IModel}.
* </p>
*/
public EcoreModelInstanceFactory(IModel model) {
this.myModel = model;
this.myTypeUtility = new EcoreModelInstanceTypeUtility(model);
}
/*
* (non-Javadoc)
*
* @see
* org.dresdenocl.modelbus.modelinstance.types.IModelInstanceFactory
* #createModelInstanceElement(java.lang.Object)
*/
public IModelInstanceElement createModelInstanceElement(Object adapted)
throws TypeNotFoundInModelException {
/* Probably debug the entry of this method. */
if (LOGGER.isDebugEnabled()) {
String msg;
msg = "createModelInstanceElement("; //$NON-NLS-1$
msg += "adapted = " + adapted; //$NON-NLS-1$
msg += ")"; //$NON-NLS-1$
LOGGER.debug(msg);
}
// no else.
IModelInstanceElement result;
/*
* Try to delegate the basis factory to create a primitive or collection
* instance.
*/
result = super.createModelInstanceElement(adapted);
if (result == null) {
/* Check if the given Object is an EnumerationLiteral. */
if (adapted instanceof Enum<?>) {
result = this
.createEcoreModelInstanceEnumerationLiteral((Enum<?>) adapted);
}
/* Else check if the given Object is an EObject. */
else if (adapted instanceof EObject) {
EObject eObject;
eObject = (EObject) adapted;
/* Check if the given Object has been adapted already. */
if (this.myCachedAdaptedObjects.containsKey(eObject)) {
result = this.myCachedAdaptedObjects.get(eObject);
}
else {
result = this.createEcoreModelInstanceObject(eObject);
this.myCachedAdaptedObjects.put(eObject, result);
}
}
else {
String msg;
msg = EcoreModelInstanceTypeMessages.EcoreModelInstanceFactory_AdapteeIsNoEObjectInstance;
msg = NLS.bind(msg, adapted);
throw new TypeNotFoundInModelException(msg);
}
}
// no else.
/* Probably debug the exit of this method. */
if (LOGGER.isDebugEnabled()) {
String msg;
msg = "createModelInstanceElement(Object) - exit"; //$NON-NLS-1$
msg += " return value = " + result; //$NON-NLS-1$
LOGGER.debug(msg);
}
// no else.
return result;
}
/*
* (non-Javadoc)
*
* @see
* org.dresdenocl.modelbus.modelinstance.types.IModelInstanceFactory
* #createModelInstanceElement(java.lang.Object,
* org.dresdenocl.pivotmodel.Type)
*/
public IModelInstanceElement createModelInstanceElement(Object adapted,
Type type) {
/* Probably debug the entry of this method. */
if (LOGGER.isDebugEnabled()) {
String msg;
msg = "createModelInstanceElement("; //$NON-NLS-1$
msg += "adapted = " + adapted; //$NON-NLS-1$
msg += ", type = " + type; //$NON-NLS-1$
msg += ")"; //$NON-NLS-1$
LOGGER.debug(msg);
}
// no else.
IModelInstanceElement result;
/* Check if the object has already been adapted. */
result = this.myCachedAdaptedObjects.get(adapted);
/* Else create a new adapter. */
if (result == null) {
/*
* Try to use the BasisJavaModelInstanceFactory to probably create
* an adapter for a primitive type or a collection.
*/
result = super.createModelInstanceElement(adapted, type);
/* Check if no primitive type or collection has been created. */
if (result == null) {
/* Check if the given type is an Enumeration. */
if (type instanceof Enumeration) {
/*
* If adapted == null, i.e. a PropertyCallExp returned a
* null value, simply try to create an undefined value.
*/
if (adapted == null) {
result = BasisJavaModelInstanceFactory
.createModelInstanceEnumerationLiteral(null);
}
else {
/*
* Check if the object is an EnumerationLiteral and has
* the same type as the given type.
*/
if (adapted.getClass().isEnum()) {
List<String> modelInstanceElementTypeName;
modelInstanceElementTypeName = EcoreModelInstanceTypeUtility
.toQualifiedNameList(adapted.getClass()
.getCanonicalName());
if (modelInstanceElementTypeName.size() > 0) {
try {
Type modelInstanceElementType;
modelInstanceElementType = null;
while (modelInstanceElementTypeName.size() > 0
&& modelInstanceElementType == null) {
modelInstanceElementType = this.myModel
.findType(modelInstanceElementTypeName);
modelInstanceElementTypeName.remove(0);
}
// end while.
if (modelInstanceElementType != null
&& modelInstanceElementType
.conformsTo(type)) {
result = this
.createEcoreModelInstanceEnumerationLiteral((Enum<?>) adapted);
}
// no else.
}
catch (TypeNotFoundInModelException e) {
String msg;
msg = EcoreModelInstanceTypeMessages.EcoreModelInstanceFactory_CannotAdaptToType;
msg = NLS.bind(msg, adapted, type);
throw new IllegalArgumentException();
}
catch (ModelAccessException e) {
String msg;
msg = EcoreModelInstanceTypeMessages.EcoreModelInstanceFactory_CannotAdaptToType;
msg = NLS.bind(msg, adapted, type);
throw new IllegalArgumentException();
}
}
// no else.
}
// no else.
}
/* Else throw an exception. */
if (result == null) {
String msg;
msg = EcoreModelInstanceTypeMessages.EcoreModelInstanceFactory_CannotAdaptToType;
msg = NLS.bind(msg, adapted, type);
throw new IllegalArgumentException(msg);
}
// no else.
}
/* Else adapt to an IModelInstanceObject. */
else {
if (adapted instanceof EObject) {
EObject eObject;
eObject = (EObject) adapted;
/*
* Try to find the type of the adaptable EObject (really
* necessary! Could be a subtype of the given type).
*/
try {
Type modelInstanceElementType;
modelInstanceElementType = this.myTypeUtility
.findTypeOfEObjectInModel(eObject);
/*
* Only adapt if the found type conforms to the
* given type.
*/
/* TODO Improve solution for comparison to EObject. */
if (modelInstanceElementType.conformsTo(type) || type.getQualifiedName().equals("ecore::EObject")) {
result = this
.createEcoreModelInstanceObject(
eObject, type,
modelInstanceElementType);
/* Cache the adapted object. */
this.myCachedAdaptedObjects
.put(eObject, result);
}
/* Else throw an exception. */
else {
String msg;
msg = EcoreModelInstanceTypeMessages.EcoreModelInstanceFactory_CannotAdaptToType;
msg = NLS.bind(msg, adapted, type);
throw new IllegalArgumentException(msg);
}
}
// end try.
catch (TypeNotFoundInModelException e) {
String msg;
msg = EcoreModelInstanceTypeMessages.EcoreModelInstanceFactory_CannotAdaptToType;
msg = NLS.bind(msg, adapted, type);
throw new IllegalArgumentException(msg);
}
// end catch.
}
/* Else adapted is either 'null' or an exception is thrown */
else {
if (adapted == null) {
result = new EcoreModelInstanceObject(null, type,
type, this);
}
/* Else the throw an exception. */
else {
String msg;
msg = EcoreModelInstanceTypeMessages.EcoreModelInstanceFactory_CannotAdaptToType;
msg = NLS.bind(msg, adapted, type);
throw new IllegalArgumentException(msg);
}
}
}
// end else.
}
// no else.
}
// no else.
/* Probably debug the exit of this method. */
if (LOGGER.isDebugEnabled()) {
String msg;
msg = "createModelInstanceElement(Object) - exit"; //$NON-NLS-1$
msg += " - rseult = " + result; //$NON-NLS-1$
LOGGER.debug(msg);
}
// no else.
return result;
}
/**
* <p>
* Returns the {@link EcoreModelInstanceTypeUtility} used to find
* {@link Type}s in the {@link IModel}.
* </p>
*
* @return The {@link EcoreModelInstanceTypeUtility} used to find
* {@link Type}s in the {@link IModel}.
*/
public EcoreModelInstanceTypeUtility getTypeUtility() {
return myTypeUtility;
}
/**
* <p>
* A helper method that creates a new {@link EcoreModelInstanceObject} for a
* given {@link EObject}.
* </p>
*
* @param eObject
* The {@link EObject} that shall be adapted.
* @return The adapted {@link EcoreModelInstanceObject}.
* @throws TypeNotFoundInModelException
* Thrown, if the given {@link EObject} cannot be adapted to any
* {@link Type} of the {@link IModel} of this
* {@link EcoreModelInstanceFactory}.
*/
private IModelInstanceElement createEcoreModelInstanceObject(EObject eObject)
throws TypeNotFoundInModelException {
/* Probably debug the entry of this method. */
if (LOGGER.isDebugEnabled()) {
String msg;
msg = "createEcoreModelInstanceObject("; //$NON-NLS-1$
msg += "eObject = " + eObject; //$NON-NLS-1$
msg += ")"; //$NON-NLS-1$
LOGGER.debug(msg);
}
// no else.
IModelInstanceElement result;
Type type;
type = this.myTypeUtility.findTypeOfEObjectInModel(eObject);
result = new EcoreModelInstanceObject(eObject, type, type, this);
/* Probably debug the exit of this method. */
if (LOGGER.isDebugEnabled()) {
String msg;
msg = "createEcoreModelInstanceObject(EObject) - exit"; //$NON-NLS-1$
msg += " return value = " + result; //$NON-NLS-1$
LOGGER.debug(msg);
}
// no else.
return result;
}
/**
* <p>
* A helper method that creates a new {@link EcoreModelInstanceObject} for a
* given {@link EObject} and a given {@link Type}.
* </p>
*
* @param eObject
* The {@link EObject} that shall be adapted.
* @param type
* The {@link Type} to that the {@link EObject} shall be adapted.
* @param originalType
* The original {@link Type} to that the {@link EObject} shall be
* adapted.
* @return The adapted {@link EcoreModelInstanceObject}.
*/
private IModelInstanceElement createEcoreModelInstanceObject(
EObject eObject, Type type, Type originalType) {
/* Probably debug the entry of this method. */
if (LOGGER.isDebugEnabled()) {
String msg;
msg = "createEcoreModelInstanceObject("; //$NON-NLS-1$
msg += "eObject = " + eObject; //$NON-NLS-1$
msg += ", type = " + type; //$NON-NLS-1$
msg += ")"; //$NON-NLS-1$
LOGGER.debug(msg);
}
// no else.
IModelInstanceElement result;
result = new EcoreModelInstanceObject(eObject, type, originalType, this);
/* Probably debug the exit of this method. */
if (LOGGER.isDebugEnabled()) {
String msg;
msg = "createEcoreModelInstanceObject(EObject) - exit"; //$NON-NLS-1$
msg += " return value = " + result; //$NON-NLS-1$
LOGGER.debug(msg);
}
// no else.
return result;
}
/**
* <p>
* Creates a new {@link ModelInstanceEnumerationLiteral} for a given
* {@link Enum}.
* </p>
*
* @param anEnum
* The {@link Enum} that shall be adapted.
* @return The created {@link ModelInstanceEnumerationLiteral}.
* @throws TypeNotFoundInModelException
* Thrown, if the given {@link Enum} cannot be adapted to the
* {@link IModel} of this {@link EcoreModelInstanceFactory}.
*/
private IModelInstanceElement createEcoreModelInstanceEnumerationLiteral(
Enum<?> anEnum) throws TypeNotFoundInModelException {
/* Probably debug the entry of this method. */
if (LOGGER.isDebugEnabled()) {
String msg;
msg = "createEcoreModelInstanceEnumerationLiteral("; //$NON-NLS-1$
msg += "anEnum = " + anEnum; //$NON-NLS-1$
msg += ")"; //$NON-NLS-1$
LOGGER.debug(msg);
}
// no else.
IModelInstanceEnumerationLiteral result;
Type type;
result = null;
/* Try to find the enumeration of the enum in the model. */
type = this.myTypeUtility.findTypeOfClassInModel(anEnum.getClass());
/* Check if the enumeration has been found in the model. */
if (type != null && type instanceof Enumeration) {
Enumeration enumeration;
enumeration = (Enumeration) type;
/* Try to find a literal with the right value. */
for (EnumerationLiteral aLiteral : enumeration.getOwnedLiteral()) {
if (aLiteral.getName().equalsIgnoreCase(anEnum.toString())) {
result = createModelInstanceEnumerationLiteral(aLiteral);
break;
}
// no else.
}
// end for.
if (result == null) {
String msg;
msg = EcoreModelInstanceTypeMessages.EcoreModelInstanceFactory_TypeNotFoundInModel;
msg = NLS.bind(msg, anEnum);
throw new TypeNotFoundInModelException(msg);
}
}
else {
String msg;
msg = EcoreModelInstanceTypeMessages.EcoreModelInstanceFactory_TypeNotFoundInModel;
msg = NLS.bind(msg, anEnum);
throw new TypeNotFoundInModelException(msg);
}
/* Probably debug the exit of this method. */
if (LOGGER.isDebugEnabled()) {
String msg;
msg = "createEcoreModelInstanceEnumerationLiteral(Enum<?>) - exit"; //$NON-NLS-1$
msg += " return value = " + result; //$NON-NLS-1$
LOGGER.debug(msg);
}
// no else.
return result;
}
}