/******************************************************************************* * Copyright (c) 2015-16 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: * - Philippe Merle <philippe.merle@inria.fr> *******************************************************************************/ package org.occiware.clouddesigner.occi.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EFactory; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EParameter; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.util.Diagnostician; import org.occiware.clouddesigner.occi.Attribute; import org.occiware.clouddesigner.occi.AttributeState; import org.occiware.clouddesigner.occi.Configuration; import org.occiware.clouddesigner.occi.Entity; import org.occiware.clouddesigner.occi.Extension; import org.occiware.clouddesigner.occi.Kind; import org.occiware.clouddesigner.occi.Link; import org.occiware.clouddesigner.occi.Mixin; import org.occiware.clouddesigner.occi.OCCIFactory; import org.occiware.clouddesigner.occi.Resource; /** * This class provides some utility methods for the OCCI metamodel. * * @author Philippe Merle - Inria */ public final class OcciHelper { /** * This class can not be instantiated. */ private OcciHelper() { } // ---------------------------------------------------------------------- // // Related to EMF validation. // // ---------------------------------------------------------------------- /** * Validates a given OCCI object according to the EMF and OCL constraints of its metamodel. * @param occiObject the given OCCI object. */ public static boolean validate(EObject occiObject) { Diagnostic diagnostic = Diagnostician.INSTANCE.validate(occiObject); if (diagnostic.getSeverity() != Diagnostic.OK) { StringBuffer stringBuffer = printDiagnostic(diagnostic, "", new StringBuffer()); System.out.flush(); System.err.println(stringBuffer.toString()); System.err.flush(); return false; } return true; } /** * Print an EMF validation diagnostic. * @param diagnostic * @param indent * @param stringBuffer * @return */ private static StringBuffer printDiagnostic(Diagnostic diagnostic, String indent, StringBuffer stringBuffer) { stringBuffer.append(indent); stringBuffer.append(diagnostic.getMessage()); stringBuffer.append("\n"); for (Diagnostic child : diagnostic.getChildren()) { printDiagnostic(child, indent + " ", stringBuffer); } return stringBuffer; } // ---------------------------------------------------------------------- // // Related to loading OCCI files. // // ---------------------------------------------------------------------- /** * Load an OCCI extension. * @param extensionURI URI of the extension to load. * @return the loaded OCCI extension. */ public static Extension loadExtension(String extensionURI) { return (Extension)loadOCCI(extensionURI); } /** * Load an OCCI configuration. * @param configurationURI URI of the configuration to load. * @return the loaded OCCI configuration. */ public static Configuration loadConfiguration(String configurationURI) { return (Configuration)loadOCCI(configurationURI); } /** * Load an OCCI object. * @param uri URI of the OCCI object to load. * @return the loaded OCCI object. */ private static Object loadOCCI(String uri) { // Create a new resource set. ResourceSet resourceSet = new ResourceSetImpl(); // Load the OCCI resource. org.eclipse.emf.ecore.resource.Resource resource = resourceSet.getResource(URI.createURI(uri), true); // Return the first element. return resource.getContents().get(0); } // ---------------------------------------------------------------------- // // Related to Configuration. // // ---------------------------------------------------------------------- /** * Get the configuration containing a given entity. * @param entity the given entity. * @return the entity configuration. * @throws java.lang.IllegalArgumentException If the given entity is not a resource or a link. */ public static Configuration getConfiguration(final Entity entity) { if(entity instanceof Resource) { return (Configuration)entity.eContainer(); } else if(entity instanceof Link) { EObject econtainer = entity.eContainer(); return (econtainer == null) ? null : (Configuration)econtainer.eContainer(); } else { throw new IllegalArgumentException(entity.toString() + " is not a resource or link!"); } } // ---------------------------------------------------------------------- // // Related to Kind. // // ---------------------------------------------------------------------- /** * Get a kind by its term. * @param extension The extension where to search. * @param kindTerm The term of the kind to search. * @return The found kind. * @throws java.lang.IllegalArgumentException If the term is not found into the given extension. */ public static Kind getKindByTerm(final Extension extension, final String kindTerm) { // Iterate over all kinds of the given extension. for(Kind kind : extension.getKinds()) { // If this kind has the same term that those searched then return this kind. if(kind.getTerm().equals(kindTerm)) { return kind; } } // Kind not found. throw new IllegalArgumentException("term '" + kindTerm + "' is not found into extension '" + extension.getScheme() + "'!"); } // ---------------------------------------------------------------------- // // Related to Entity. // // ---------------------------------------------------------------------- /** * Get all the attributes of an Entity instance. * @param entity the given Entity instance. * @return all the attributes of the given instance. */ public static Collection<Attribute> getAllAttributes(final Entity entity) { List<Attribute> attributes = new ArrayList<Attribute>(); Kind entityKind = entity.getKind(); if(entityKind != null) { addAllAttributes(attributes, entityKind); } for(Mixin mixin : entity.getMixins()) { addAllAttributes(attributes, mixin); } return attributes; } /** * Add all the attributes of a given Kind instance and all its parent kinds. * * @param attributes the collection where attributes will be added. * @param kind the given Kind instance. */ public static void addAllAttributes(final Collection<Attribute> attributes, final Kind kind) { Kind kindParent = kind.getParent(); if (kindParent != null) { addAllAttributes(attributes, kindParent); } attributes.addAll(kind.getAttributes()); } /** * Add all the attributes of a given Mixin instance and all its depend mixins. * * @param attributes the collection where attributes will be added. * @param mixin the given Mixin instance. */ public static void addAllAttributes(final Collection<Attribute> attributes, final Mixin mixin) { for(Mixin md : mixin.getDepends()) { addAllAttributes(attributes, md); } attributes.addAll(mixin.getAttributes()); } /** * Create an entity of a given kind. * @param kind The kind of the entity to create. * @return The created entity, else null. */ public static Entity createEntity(Kind kind) { Entity createdEntity = null; // Get the name space of the Ecore package for this kind. String epackageNS = Occi2Ecore.convertOcciScheme2EcoreNamespace(kind.getScheme()); // Get the Ecore package associated to the kind. EPackage epackage = EPackage.Registry.INSTANCE.getEPackage(epackageNS); if(epackage == null) { System.err.println("WARNING: EPackage " + epackageNS + " not found!"); } else { String classname = Occi2Ecore.convertOcciCategoryTerm2EcoreClassName(kind.getTerm()); // Get the Ecore class associated to the kind. EClass eclass = (EClass) epackage.getEClassifier(classname); if(eclass == null) { System.err.println("WARNING: EClass " + classname + " not found!"); } else { // Get the Ecore factory associated to the kind. EFactory efactory = EPackage.Registry.INSTANCE.getEFactory(epackageNS); if(efactory == null) { System.err.println("WARNING: EFactory " + epackageNS + " not found!"); } else { // Create the EObject for this kind. createdEntity = (Entity)efactory.create(eclass); } } } if(createdEntity == null) { System.err.println("WARNING: Create OCCI Core Resource!"); createdEntity = OCCIFactory.eINSTANCE.createResource(); createdEntity.setKind(kind); } System.err.println("DEBUG: created entity=" + createdEntity); // Return the new entity. return createdEntity; } /** * Set an attribute of an OCCI entity. * @param entity the given entity. * @param attributeName the attribute name. * @param attributeValue the attribute value. * @throws java.lang.IllegalArgumentException Thrown when the attribute name is unknown or the attribute value is invalid. */ public static void setAttribute(Entity entity, String attributeName, String attributeValue) { // Check that attribute name exists from this entity. getAttribute(entity, attributeName); // Search the Ecore structural feature associated to the OCCI attribute. String eAttributeName = Occi2Ecore.convertOcciAttributeName2EcoreAttributeName(attributeName); final EStructuralFeature eStructuralFeature = entity.eClass().getEStructuralFeature(eAttributeName); if (eStructuralFeature == null) { // Create the attribute state and update it, if none, create it. AttributeState attrState = getAttributeStateObject(entity, attributeName); if (attrState == null) { // Create the attribute. attrState = createAttributeState(attributeName, attributeValue); entity.getAttributes().add(attrState); } return; // throw new IllegalArgumentException("Ecore structural feature '" + eAttributeName + "' not found!"); } if(!(eStructuralFeature instanceof EAttribute)) { throw new IllegalArgumentException("Ecore structural feature '" + eAttributeName + "' is not an Ecore attribute!"); } // Obtain the attribute type. EDataType eAttributeType = ((EAttribute)eStructuralFeature).getEAttributeType(); // Convert the attribute value according to the attribute type. Object eAttributeValue = eAttributeType.getEPackage().getEFactoryInstance().createFromString(eAttributeType, attributeValue); // Set the Ecore attribute. entity.eSet(eStructuralFeature, eAttributeValue); } /** * Get an attribute of an OCCI entity. * @param entity the given entity. * @param attributeName the attribute name. * @throws java.lang.IllegalArgumentException Thrown when the attribute name is unknown. */ public static Attribute getAttribute(Entity entity, String attributeName) { for(Attribute attribute : getAllAttributes(entity)) { if(attribute.getName().equals(attributeName)) { return attribute; } } throw new IllegalArgumentException("attribute '" + attributeName + "' is not found in " + entity + "!"); } /** * Execute an action on an OCCI entity. * @param entity the given entity. * @param actionName the action name. * @param parameters the parameters. * @throws IllegalArgumentException Thrown when the action name is unknown or parameters are invalid. * @throws InvocationTargetException Thrown when the action throws an exception. */ public static void executeAction(Entity entity, String actionName, String... parameters) throws InvocationTargetException { // TODO: Check that actionName is an OCCI action. // Search the Ecore operation. EOperation eOperation = null; for(EOperation tmp : entity.eClass().getEAllOperations()) { if(tmp.getName().equals(actionName)) { eOperation = tmp; break; } } // Exception if operation not found. if(eOperation == null) { throw new IllegalArgumentException("Ecore operation '" + actionName + "' not found!"); } // Check the number of parameters. EList<EParameter> eOperationParameters = eOperation.getEParameters(); int nbParameters = eOperationParameters.size(); if(parameters.length != nbParameters) { throw new IllegalArgumentException("Bad number of parameters: " + parameters.length + " given when " + nbParameters + " expected!"); } // Convert parameters according to the type of Ecore operation parameters. Object[] eParameters = new Object[nbParameters]; Class<?>[] parameterClasses = new Class[nbParameters]; for(int i=0; i<nbParameters; i++) { EParameter eParameter = eOperationParameters.get(i); EDataType parameterType = (EDataType)eParameter.getEType(); try { eParameters[i] = parameterType.getEPackage().getEFactoryInstance().createFromString(parameterType, parameters[i]); } catch(IllegalArgumentException e) { throw new IllegalArgumentException("Bad value for '" + eParameter.getName() + "' parameter!", e); } parameterClasses[i] = parameterType.getInstanceClass(); } // Execute the Ecore operation. // FIXME: Does not work for Infrastructure metamodel! // entity.eInvoke(eOperation, null); // FIXME: Then use Java reflection invocation. try { Method method = entity.getClass().getMethod(actionName, parameterClasses); method.invoke(entity, eParameters); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Method '" + actionName + "' not found!", e); } catch (SecurityException e) { throw new IllegalArgumentException("Security exception on method '" + actionName + "'!", e); } catch (IllegalAccessException e) { throw new IllegalArgumentException("Illegal access exception on method '" + actionName + "'!", e); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Illegal argument exception on method '" + actionName + "'!", e); } } /** * Create an attribute without add this to the entity object. * * @param name * @param value * @return AttributeState object. */ private static AttributeState createAttributeState(final String name, final String value) { AttributeState attr = OCCIFactory.eINSTANCE.createAttributeState(); attr.setName(name); attr.setValue(value); return attr; } /** * Get an attribute state object for key parameter. * * @param key * ex: occi.core.title. * @return an AttributeState object, if attribute doesnt exist, null value * is returned. */ private static AttributeState getAttributeStateObject(Entity entity, final String key) { AttributeState attr = null; if (key == null) { return attr; } // Load the corresponding attribute state. for (AttributeState attrState : entity.getAttributes()) { if (attrState.getName().equals(key)) { attr = attrState; break; } } return attr; } }