package com.cimphony.cimtoole.ecore; import java.io.IOException; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.URI; 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.EEnum; import org.eclipse.emf.ecore.EEnumLiteral; import org.eclipse.emf.ecore.ENamedElement; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.Resource.Factory.Descriptor; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.util.EcoreUtil; import au.com.langdale.cimtoole.registries.ModelParser; import au.com.langdale.kena.ModelFactory; import au.com.langdale.kena.OntModel; import au.com.langdale.kena.OntResource; import au.com.langdale.xmi.UML; import au.com.langdale.xmi.XMIModel; import com.cimphony.cimtoole.CimphonyCIMToolPlugin; import com.cimphony.cimtoole.util.CIMToolEcoreUtil; import com.hp.hpl.jena.graph.FrontsNode; import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.OWL2; import com.hp.hpl.jena.vocabulary.XSD; public class EcoreExtractor extends XMIModel implements ModelParser{ public class InvalidEDataTypeException extends Exception{ private static final long serialVersionUID = -2616865485691314837L; EDataType type; public InvalidEDataTypeException(EDataType type){ this.type = type; } public EDataType getType(){ return type; } } protected IFile file; /** the ontology under construction */ protected Map<EPackage, OntResource> packageMap; protected Map<EClassifier, OntResource> classMap; protected Set<EReference> processedAssociations; public EcoreExtractor(){ model = ModelFactory.createMem(); packageMap = new HashMap<EPackage, OntResource>(); classMap = new HashMap<EClassifier, OntResource>(); processedAssociations = new HashSet<EReference>(); } /** * Return the underlying Jena OWL model. */ public OntModel getModel() { return model; } private static String getXUID(EObject o){ return "_"+Integer.toHexString(EcoreUtil.getURI(o).toString().hashCode()); } public void run() throws IOException, CoreException{ if (file == null) throw new CoreException(new Status(IStatus.ERROR, CimphonyCIMToolPlugin.PLUGIN_ID, "No input file set")); if (!file.getFileExtension().equals("ecore")) return; URI uri; if (file.getLocation().isAbsolute()){ uri = URI.createFileURI(file.getLocation().toFile().getAbsolutePath()); }else{ uri = URI.createPlatformResourceURI(file.getLocation().toString(), true); } Resource res = new ResourceSetImpl().getResource(uri, true); //Resource res = ((Descriptor)Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().get("ecore")).createFactory() //.createResource(URI.createFileURI(file.getFullPath().toString())); //res.load(file.getContents(), Collections.EMPTY_MAP); if (res.getContents().size()==0) throw new CoreException(new Status(IStatus.ERROR, CimphonyCIMToolPlugin.PLUGIN_ID, "ECore Resource is empty")); if (!(res.getContents().get(0) instanceof EPackage)) throw new CoreException(new Status(IStatus.ERROR, CimphonyCIMToolPlugin.PLUGIN_ID, "File contains no EPackages")); EPackage root = (EPackage)res.getContents().get(0); try{ String ns = root.getNsURI(); if (!ns.endsWith("#")) ns += "#"; model.setNsPrefix(root.getNsPrefix(), ns); processEPackage(root); for (EClassifier c: classMap.keySet()) postProcessEClassifiers(c); }catch (NullPointerException npe){ npe.printStackTrace(); } } protected void processEPackage(EPackage p) throws CoreException{ OntResource op = createIndividual(EcoreExtractor.getXUID(p), p.getName(), UML.Package); annotate(p, op); packageMap.put(p, op); OntResource parent = packageMap.get(p.getESuperPackage()); String ns = p.getNsURI(); if( ns != null && ! ns.isEmpty()) { if( ! ns.contains("#")) { ns = ns + "#"; } op.addProperty(UML.baseuri, ns); } op.addIsDefinedBy(parent == null? UML.global_package: parent); for (EPackage sp: p.getESubpackages()){ processEPackage(sp); } for (EClassifier c: p.getEClassifiers()){ processEClassifier(c); } } protected void processEClassifier(EClassifier c) throws CoreException{ OntResource oc = createClass(EcoreExtractor.getXUID(c), c.getName()); annotate(c, oc); classMap.put(c, oc); OntResource op = packageMap.get(c.getEPackage()); oc.addIsDefinedBy(op == null? UML.global_package: op); if (c instanceof EEnum){ oc.addProperty(UML.hasStereotype, UML.enumeration); EEnum ee = (EEnum)c; for (EEnumLiteral lit: ee.getELiterals()){ createIndividual(EcoreExtractor.getXUID(lit), lit.getLiteral(), oc); } }else if (c instanceof EClass){ EClass ec = (EClass)c; if (!ec.isAbstract()){ oc.addProperty(UML.hasStereotype, UML.concrete); } }else if (c instanceof EDataType){ oc.addProperty(UML.hasStereotype, UML.datatype); try{ oc.addProperty(OWL.sameAs, getXSDType((EDataType)c)); oc.addProperty(OWL2.equivalentClass, getXSDType((EDataType)c)); }catch(InvalidEDataTypeException ex){ throw new CoreException(new Status(IStatus.ERROR, CimphonyCIMToolPlugin.PLUGIN_ID, "Invalid EDataType in Ecore - no XSD Mapping", ex)); } }else{ System.err.println("EClassifier of type "+c.getClass().getName()); } } protected com.hp.hpl.jena.rdf.model.Resource getXSDType(EDataType d) throws InvalidEDataTypeException{ /* http://www.w3.org/2001/XMLSchema#string = java.lang.String http://www.w3.org/2001/XMLSchema#float = double http://www.w3.org/2001/XMLSchema#integer = int http://www.w3.org/2001/XMLSchema#int = int http://www.w3.org/2001/XMLSchema#boolean = boolean http://www.w3.org/2001/XMLSchema#dateTime = java.util.Date * */ Class<?> ic = d.getInstanceClass(); if (CIMToolEcoreUtil.getType(ic)!=null){ return CIMToolEcoreUtil.getType(ic); } /* if (ic == String.class){ return XSD.xstring; }else if (ic == double.class){ return XSD.xdouble; }else if (ic == float.class){ return XSD.xfloat; }else if (ic == int.class){ return XSD.xint; }else if (ic == short.class){ return XSD.xshort; }else if (ic == long.class){ return XSD.xlong; }else if (ic == boolean.class){ return XSD.xboolean; }else if (ic == Date.class){ return XSD.dateTime; }else if (ic == byte.class){ return XSD.base64Binary; } */ System.err.println(d +" "+ic); throw new InvalidEDataTypeException(d); } protected void postProcessEClassifiers(EClassifier c) throws CoreException{ if (c instanceof EClass){ OntResource oc = classMap.get(c); for (EClass cs: ((EClass) c).getESuperTypes()){ OntResource os = classMap.get(cs); oc.addSuperClass(os); } for (EStructuralFeature f: ((EClass) c).getEStructuralFeatures()){ if (f instanceof EAttribute){ OntResource subject = createAttributeProperty(EcoreExtractor.getXUID(f), f.getName()); subject.addDomain(oc); annotate(f, subject); FrontsNode type = classMap.get(f.getEType()); if (type == null && f.getEType() instanceof EDataType){ try { type = getXSDType((EDataType)f.getEType()); } catch (InvalidEDataTypeException ex) { throw new CoreException(new Status(IStatus.ERROR, CimphonyCIMToolPlugin.PLUGIN_ID, "Invalid EDataType in Ecore - no XSD Mapping", ex)); } } if (type != null) subject.addRange(type); else subject.addRange(XSD.anyURI); }else if (f instanceof EReference){ EReference r = (EReference)f; if (!processedAssociations.contains(r)){ Role rolea = extractProperty(r, classMap.get(r.getEType()), r.isContainer(), true); rolea.property.addDomain(oc); processedAssociations.add(r); if (r.getEOpposite()!=null && classMap.containsKey(r.getEOpposite().getEType())){ Role roleb = extractProperty(r.getEOpposite(), classMap.get(r.getEOpposite().getEType()), r.getEOpposite().isContainer(), false); roleb.property.addDomain(classMap.get(r.getEOpposite().getEContainingClass())); rolea.mate(roleb); roleb.mate(rolea); processedAssociations.add(r.getEOpposite()); } } } } } } protected Role extractProperty(EReference ref, OntResource destin, boolean aggregate, boolean sideA) { Role role = new Role(); role.property = createObjectProperty(EcoreExtractor.getXUID(ref), sideA, ref.getName()); role.range = destin; role.aggregate = aggregate; role.upper = ref.getUpperBound(); role.lower = ref.getLowerBound(); return role; } protected void annotate(ENamedElement el, OntResource o){ if (el.getEAnnotation("http://www.eclipse.org/emf/2002/GenModel")!=null){ if (el.getEAnnotation("http://www.eclipse.org/emf/2002/GenModel").getDetails().get("documentation")!=null){ o.addComment(el.getEAnnotation("http://www.eclipse.org/emf/2002/GenModel").getDetails().get("documentation"), LANG); } } } @Override public void setFile(IFile file) { this.file = file; } }