/******************************************************************************* * Copyright (c) 2015-2016 Obeo, Inria * 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: * William Piers <william.piers@obeo.fr> * Philippe Merle <philippe.merle@inria.fr> *******************************************************************************/ package org.occiware.clouddesigner.occi.emfgen; import java.util.HashMap; import java.util.Map; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EModelElement; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EParameter; import org.eclipse.emf.ecore.EcoreFactory; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.util.EcoreUtil; import org.occiware.clouddesigner.occi.Action; import org.occiware.clouddesigner.occi.Attribute; import org.occiware.clouddesigner.occi.Extension; import org.occiware.clouddesigner.occi.Kind; import org.occiware.clouddesigner.occi.util.Occi2Ecore; /** * Convert an OCCI Extension to Ecore. */ public class OCCIExtension2Ecore { private static final String EANNOTATION_SOURCE = "OCCIE2Ecore"; /** * Store mapping from OCCI Kind to Ecore EClass. */ private Map<Kind, EClass> occiKind2emfEclass = new HashMap<Kind, EClass>(); /** * Get the EClass associated to an OCCI Kind. * * @param kind * the given OCCI kind. * @return the EClass. */ private EClass getMappedEClass(Kind kind) { EClass res = null; if (kind != null) { // retrieve from currently converted kinds res = occiKind2emfEclass.get(kind); if (res == null) { // retrieve from installed extensions. EPackage p = ConverterUtils.getEPackage(kind); res = (EClass) p.getEClassifier(ConverterUtils.toU1Case(kind.getTerm())); // Cache it for optimizing next searches. occiKind2emfEclass.put(kind, res); } } return res; } /** * Store mapping from OCCI EDataType to Ecore EClassifier. */ private Map<EDataType, EClassifier> occiType2emfType = new HashMap<EDataType, EClassifier>(); /** * Get the EMF data type associated to an OCCI data type. * * @param type * the given OCCI data type. * @return the EMF data type. */ private EClassifier getMappedType(EDataType type) { EClassifier res = null; if (type == null) { res = EcorePackage.eINSTANCE.getEString(); } else { // retrieve from currently converted data types res = occiType2emfType.get(type); if (res == null) { // retrieve from installed extensions. EPackage p = ConverterUtils.getEPackage(type); res = p.getEClassifier(type.getName()); // Cache it for optimizing next searches. occiType2emfType.put(type, res); } } return res; } /** * Convert an OCCI extension to an Ecore package. * * @param extension * the OCCI extension to convert. * @return the resulting Ecore package. */ public EPackage convertExtension(Extension extension) { // Create the Ecore package. EPackage ePackage = EcoreFactory.eINSTANCE.createEPackage(); // Set the name of the Ecore package. String formattedName = ConverterUtils .formatName(extension.getName().replaceFirst("OCCI ", "").replaceFirst("OCCIware ", "").toLowerCase()); ePackage.setName(formattedName); // Set the name space prefix of the Ecore package. ePackage.setNsPrefix(formattedName); // Set the URI of the Ecore package. ePackage.setNsURI(Occi2Ecore.convertOcciScheme2EcoreNamespace(extension.getScheme())); // TODO fetch occi package // but won't solve issue if user wants to use types from installed // models // EClass root = EcoreFactory.eINSTANCE.createEClass(); // ePackage.getEClassifiers().add(root); // root.setName(ConverterUtils.toU1Case(extension.getName()+"Configuration")); // root.getESuperTypes().add(OCCIPackage.eINSTANCE.getConfiguration()); // Convert all data types of the OCCI extension to data types of the // Ecore package. for (EDataType type : extension.getTypes()) { // Copy the OCCI data type. EDataType copiedType = EcoreUtil.copy(type); // Cache the copied data type to search it later. occiType2emfType.put(type, copiedType); // Add the data type to the Ecore package. ePackage.getEClassifiers().add(copiedType); } // Convert all OCCI kinds. for (Kind kind : extension.getKinds()) { // Convert each OCCI kind to an Ecore class. EClass convertKind = convertKind(kind); // Add the Ecore class to the Ecore package. if (convertKind != null) { ePackage.getEClassifiers().add(convertKind); } } // Convert all OCCI mixins. // TODO // for (Mixin mixin : extension.getMixins()) { // EClass convertMixin = convertMixin(mixin); // if (convertMixin != null) { // ePackage.getEClassifiers().add(convertMixin); // } // } // Resolve inheritance between OCCI kinds. for (Kind kind : extension.getKinds()) { // Get the Ecore class of this OCCI kind. EClass mappedEClass = getMappedEClass(kind); // If kind has a parent kind then if (kind.getParent() != null) { // Get the Ecore class of the OCCI kind's parent. EClass mappedParentEClass = getMappedEClass(kind.getParent()); if (mappedParentEClass != null) { // The Ecore class of the kind's parent is a super type of // the Ecore class of the OCCI kind. mappedEClass.getESuperTypes().add(mappedParentEClass); } else { // Should never happen! throw new IllegalArgumentException("Not found: " + kind.getParent()); } } } return ePackage; } // protected EClass convertMixin(Mixin mixin) { // EClass eClass = EcoreFactory.eINSTANCE.createEClass(); // eClass.setName(ConverterUtils.toU1Case(ConverterUtils.formatName(mixin // .getTerm()))); // eClass.setAbstract(true); // for (Attribute attribute : mixin.getAttributes()) { // EAttribute convertAttribute = convertAttribute(attribute); // if (convertAttribute != null) { // eClass.getEStructuralFeatures().add(convertAttribute); // } // } // for (Action action : mixin.getActions()) { // EOperation convertAction = convertAction(action); // if (convertAction != null) { // eClass.getEOperations().add(convertAction); // } // } // return eClass; // } /** * Convert an OCCI kind to an Ecore class. * * @param kind * the OCCI kind to convert. * @return the resulting Ecore class. */ protected EClass convertKind(Kind kind) { // Create the Ecore class. EClass eClass = EcoreFactory.eINSTANCE.createEClass(); // Set the name of the Ecore class. eClass.setName(ConverterUtils.toU1Case(ConverterUtils.formatName(kind.getTerm()))); // Convert all attributes of the OCCI kind. for (Attribute attribute : kind.getAttributes()) { // Convert each OCCI attribute to an Ecore attribute. EAttribute convertAttribute = convertAttribute(attribute); if (convertAttribute != null) { // Add the Ecore attribute as a structural feature of the Ecore // class. eClass.getEStructuralFeatures().add(convertAttribute); } } // Convert all actions of the OCCI kind. for (Action action : kind.getActions()) { // Convert each OCCI action to an Ecore operation. EOperation convertAction = convertAction(action); if (convertAction != null) { // Add the Ecore action as an operation of the Ecore class. eClass.getEOperations().add(convertAction); } } attachInfo(eClass, "title", kind.getTitle()); // Keep the Ecore class into a cache to search it later. occiKind2emfEclass.put(kind, eClass); return eClass; } /** * Convert an OCCI action to an Ecore operation. * * @param action * the OCCI action to convert. * @return the resulting Ecore operation. */ protected EOperation convertAction(Action action) { // Create the Ecore operation. EOperation eOperation = EcoreFactory.eINSTANCE.createEOperation(); // Set the name of the Ecore operation. eOperation.setName(ConverterUtils.formatName(action.getTerm())); // Convert all attributes of the OCCI action. for (Attribute attribute : action.getAttributes()) { // Each OCCI attribute of the OCCI action is converted to an Ecore // parameter of the Ecore operation. EParameter convertParameter = convertParameter(attribute); if (convertParameter != null) { // Add the Ecore parameter to the Ecore operation. eOperation.getEParameters().add(convertParameter); } } attachInfo(eOperation, "title", action.getTitle()); return eOperation; } /** * Convert an OCCI action's attribute to an Ecore operation parameter. * * @param attribute * the OCCI attribute to convert. * @return the resulting Ecore operation parameter. */ protected EParameter convertParameter(Attribute attribute) { // Create an Ecore parameter. EParameter eParam = EcoreFactory.eINSTANCE.createEParameter(); // Set the name of the Ecore parameter. eParam.setName(Occi2Ecore.convertOcciAttributeName2EcoreAttributeName(attribute.getName())); // Set the type of the Ecore parameter. eParam.setEType(getMappedType(attribute.getType())); // If the OCCI attribute is required then the Ecore parameter is also // required. if (attribute.isRequired()) { eParam.setLowerBound(1); } attachInfo(eParam, "description", attribute.getDescription()); return eParam; } /** * Convert an OCCI attribute to an Ecore attribute. * * @param attribute * the OCCI attribute to convert. * @return the resulting Ecore attribute. */ protected EAttribute convertAttribute(Attribute attribute) { // Create an Ecore attribute. EAttribute eAttr = EcoreFactory.eINSTANCE.createEAttribute(); // Set the name of the Ecore attribute. eAttr.setName(Occi2Ecore.convertOcciAttributeName2EcoreAttributeName(attribute.getName())); // Set the type of the Ecore attribute. eAttr.setEType(getMappedType(attribute.getType())); // Set the default value of the Ecore attribute. String defaultValue = attribute.getDefault(); if (defaultValue != null && !defaultValue.isEmpty()) { eAttr.setDefaultValue(defaultValue); } // The Ecore attribute is required when the OCCI attribute is required. if (attribute.isRequired()) { eAttr.setLowerBound(1); } attachInfo(eAttr, "description", attribute.getDescription()); // TODO: setUpperBound(-1) if attribute.multiple_value return eAttr; } private void attachInfo(EModelElement element, String key, String value) { EAnnotation annotation = element.getEAnnotation(EANNOTATION_SOURCE); if (annotation == null) { annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource(EANNOTATION_SOURCE); element.getEAnnotations().add(annotation); } annotation.getDetails().put(key, value); } }