/**
* Copyright (c) 2013/2014 Verein zur Foerderung der IT-Sicherheit in Oesterreich (SBA).
* The work has been developed in the TIMBUS Project and the above-mentioned are Members of the TIMBUS Consortium.
* TIMBUS is supported by the European Union under the 7th Framework Programme for research and technological
* development and demonstration activities (FP7/2007-2013) under grant agreement no. 269940.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including without
* limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTIBITLY, or FITNESS FOR A PARTICULAR
* PURPOSE. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise,
* unless required by applicable law or agreed to in writing, shall any Contributor be liable for damages, including
* any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this
* License or out of the use or inability to use the Work.
* See the License for the specific language governing permissions and limitation under the License.
*/
package net.timbusproject.context.converter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.io.FileDocumentTarget;
import org.semanticweb.owlapi.io.OWLXMLOntologyFormat;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.AddImport;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAssertionAxiom;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDataPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLDeclarationAxiom;
import org.semanticweb.owlapi.model.OWLImportsDeclaration;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;
import org.semanticweb.owlapi.vocab.OWL2Datatype;
import uk.ac.manchester.cs.owl.owlapi.OWL2DatatypeImpl;
import com.archimatetool.editor.model.viewpoints.IViewpoint;
import com.archimatetool.model.FolderType;
import com.archimatetool.model.IAccessRelationship;
import com.archimatetool.model.IArchimateElement;
import com.archimatetool.model.IArchimateModel;
import com.archimatetool.model.IDiagramModelObject;
import com.archimatetool.model.IFolder;
import com.archimatetool.model.IProperty;
import com.archimatetool.model.IRelationship;
import com.archimatetool.model.impl.ArchimateDiagramModel;
import com.archimatetool.model.impl.DiagramModelArchimateObject;
import com.archimatetool.model.impl.DiagramModelGroup;
/**
* Methods to export an Archimate Model to OWL (Web Ontology Language)
*
* @author Rudolf Mayer (rmayer@sba-research.org)
*/
public class OWLExport {
public static final String KEY_SCENARIOS_URL = "ScenariosURL";
private static final String KEY_DIOURL = "DIOURL";
public static final Properties owlExportProperties = new Properties();
static {
String propertiesFileName = "owlExport.properties";
URL resource = OWLExportPlugin.class.getResource(propertiesFileName);
try {
owlExportProperties.load(resource.openStream());
System.out.println();
System.out.println("\nLoaded OWL Export properties from " + resource);
System.out.println("Properties:");
System.out.println(owlExportProperties);
System.out.println("------------------------------\n");
} catch (Exception e) {
System.err.println("\nCould not load OWL Export properties, tried file with name '" + propertiesFileName
+ "'.");
e.printStackTrace();
// default: using the TIMBUS scenarios URL
owlExportProperties.put(KEY_SCENARIOS_URL, "http://timbus.teco.edu/ontologies/examples/");
owlExportProperties.put(KEY_DIOURL, "http://timbus.teco.edu/ontologies/DIO.owl");
System.out.println("==> Using default properties:");
System.out.println("\t" + owlExportProperties);
System.out.println();
}
}
/** a mapping of some Archimate relation names to the OWL names */
public static final HashMap<String, String> propertyNamesMap = new HashMap<String, String>();
static {
propertyNamesMap.put("access", "accesses");
propertyNamesMap.put("aggregation", "aggregates");
propertyNamesMap.put("assignment", "assignment");
propertyNamesMap.put("composition", "composedOf");
propertyNamesMap.put("flow", "flowTo");
propertyNamesMap.put("influence", "influencedBy");
propertyNamesMap.put("realisation", "realizes");
propertyNamesMap.put("specialisation", "specialization");
propertyNamesMap.put("triggering", "triggers");
propertyNamesMap.put("usedby", "usedBy");
}
/** subtypes of the relation "access" */
public static final String[] relationAccessTypes = { "hasAccessTypeWrite", "hasAccessTypeRead",
"hasAccessTypeAccess", "hasAccessTypeRead_Write" };
/** the default property names */
public static final String DEFAULT_PROPERTY = "association";
/** The URL of the TIMBUS DIO */
public static final String TIMBUS_DIO_URL = owlExportProperties.getProperty(KEY_DIOURL);
/** The IRI for the TIMBUS DIO, see {@link #TIMBUS_DIO_URL} */
public static final IRI TIMBUS_DIO_IRI = IRI.create(TIMBUS_DIO_URL);
/** Prefix on the OWL name */
public static final String SCENARIOS_PREFIX = owlExportProperties.getProperty(KEY_SCENARIOS_URL);
/** The types of folders in Archi */
public static final FolderType[] FOLDER_TYPES = { FolderType.BUSINESS, FolderType.APPLICATION,
FolderType.TECHNOLOGY, FolderType.MOTIVATION, FolderType.IMPLEMENTATION_MIGRATION, FolderType.CONNECTORS,
FolderType.RELATIONS };
public static void exportToOwl(IArchimateModel model, File file) throws IOException {
exportToOwl(model, file, getDefaultIRI(file));
}
public static void exportToOwl(IArchimateModel model, File file, String iriThisOntology) throws IOException {
if (iriThisOntology == null || iriThisOntology.trim().length() == 0) {
iriThisOntology = getDefaultIRI(file);
}
// create Ontology manager
OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
OWLDataFactory df = OWLManager.getOWLDataFactory();
OWLOntology ontology;
try {
ontology = manager.createOntology(IRI.create(iriThisOntology));
} catch (OWLOntologyCreationException e) {
e.printStackTrace();
throw new IOException(e);
}
// import the DIO
OWLImportsDeclaration importDeclaraton = df.getOWLImportsDeclaration(TIMBUS_DIO_IRI);
manager.applyChange(new AddImport(ontology, importDeclaraton));
Set<OWLAnnotation> emptyAnnotations = Collections.<OWLAnnotation> emptySet();
for (FolderType folderType : FOLDER_TYPES) {
IFolder folder = model.getFolder(folderType);
List<EObject> elements = new ArrayList<EObject>((int) (folder.getElements().size() * 1.2));
Util.getElements(folder, elements);
for (EObject eObject : elements) {
if (eObject instanceof IArchimateElement) {
IArchimateElement element = (IArchimateElement) eObject;
String elementName = getOWLIRIFragment(element);
String elementClassName = element.eClass().getName();
if (eObject instanceof IRelationship) { // write relationships
IRelationship relationship = (IRelationship) eObject;
String sourceName = getOWLIRIFragment(relationship.getSource());
String tagetName = getOWLIRIFragment(relationship.getTarget());
OWLNamedIndividual source = df.getOWLNamedIndividual(IRI.create("#" + sourceName));
OWLNamedIndividual object = df.getOWLNamedIndividual(IRI.create("#" + tagetName));
// derive the name of the relation from the class name
String propertyName = relationship.eClass().getName().replace("Relationship", "");
if (propertyNamesMap.containsKey(propertyName.toLowerCase())) {
// some relations have a mapping to a better name
propertyName = propertyNamesMap.get(propertyName.toLowerCase());
} else {
propertyName = DEFAULT_PROPERTY;
}
if (eObject instanceof IAccessRelationship) {
// access relations have several subtypes, we add the correct name here
IAccessRelationship accessRelationship = (IAccessRelationship) eObject;
int accesstype = accessRelationship.getAccessType();
propertyName = relationAccessTypes[accesstype];
}
OWLObjectProperty property = df.getOWLObjectProperty(IRI.create(TIMBUS_DIO_URL + "#"
+ propertyName));
OWLObjectPropertyAssertionAxiom objectPropertyAssertion = df
.getOWLObjectPropertyAssertionAxiom(property, source, object);
manager.applyChange(new AddAxiom(ontology, objectPropertyAssertion));
} else { // write individuals (and data properties)
// writes the indiv with the ID as name
OWLNamedIndividual indiv = df.getOWLNamedIndividual(IRI.create("#" + elementName));
OWLDeclarationAxiom indivDeclaration = df.getOWLDeclarationAxiom(indiv);
manager.applyChange(new AddAxiom(ontology, indivDeclaration));
// add an rdfs:label property as annotation
String labelName = formatString(Util.replaceSpecialWhiteSpace(element.getName()));
OWLAnnotation annotation = df.getOWLAnnotation(df.getRDFSLabel(), df.getOWLLiteral(labelName));
OWLAnnotationAssertionAxiom annotationAssertionAxiom = df.getOWLAnnotationAssertionAxiom(
indiv.getIRI(), annotation);
manager.applyChange(new AddAxiom(ontology, annotationAssertionAxiom));
// add a class expression
OWLClass classExpression = df.getOWLClass(IRI.create(TIMBUS_DIO_URL + "#" + elementClassName));
OWLClassAssertionAxiom classAssertion = df.getOWLClassAssertionAxiom(classExpression, indiv);
manager.applyChange(new AddAxiom(ontology, classAssertion));
if (!element.getProperties().isEmpty()) { // add data properties
for (IProperty eProperty : element.getProperties()) {
OWLDataProperty property = df.getOWLDataProperty(IRI.create(TIMBUS_DIO_URL + "#"
+ eProperty.getKey()));
OWLLiteral owlLiteral = df.getOWLLiteral(eProperty.getValue(),
OWL2DatatypeImpl.getDatatype(OWL2Datatype.RDF_PLAIN_LITERAL));
OWLDataPropertyAssertionAxiom dataPropertyAssertion = df
.getOWLDataPropertyAssertionAxiom(property, indiv, owlLiteral, emptyAnnotations);
manager.applyChange(new AddAxiom(ontology, dataPropertyAssertion));
}
}
}
}
}
}
FileDocumentTarget fileTarget = new FileDocumentTarget(file);
try {
manager.saveOntology(ontology, new OWLXMLOntologyFormat(), fileTarget);
} catch (OWLOntologyStorageException e) {
e.printStackTrace();
}
}
/**
* Returns a valid IRI fragment - according to
* http://sourceforge.net/p/owlapi/mailman/owlapi-developer/thread/CAHYxBS
* -dW+FUFLDPZOtbFL1tROZH8W0QmLu8ye9W5L-kCcMPVA@mail.gmail.com/, it must not start with a number, which is however
* what Archi generates as IDs...
*/
private static String getOWLIRIFragment(IArchimateElement element) {
return "i" + element.getId();
}
public static String getDefaultIRI(File file) {
return SCENARIOS_PREFIX + file.getName();
}
/** Exports the layout of the layered view ({@link IViewpoint#LAYERED_VIEWPOINT}) of a model to a CSV separated file */
public static void exportLayout(IArchimateModel model, File layoutFile, File owlFile) throws FileNotFoundException {
exportLayout(layoutFile, getDefaultIRI(owlFile), getLayeredView(model));
}
public static boolean exportLayout(IArchimateModel model, File layoutFile, String ontologyIRI, String viewName)
throws FileNotFoundException {
ArchimateDiagramModel view = null;
if (viewName != null) {
System.out.print("Trying to find view '" + viewName + "'... ");
view = getViewByName(model, viewName);
System.out.println(view != null ? "found" : "not found");
}
if (view == null) {
System.out.print("Trying to find layered view... ");
view = getLayeredView(model);
System.out.println(view != null ? "found" : "not found");
}
if (view == null) {
System.out.print("Checking if there is only one view... ");
EList<EObject> elements = model.getFolder(FolderType.DIAGRAMS).getElements();
if (elements.size() == 1) {
view = (ArchimateDiagramModel) elements.get(0);
System.out.println("succes, using view " + view.getName());
} else if (elements.size() == 0) {
System.out.println("no views found at all!");
} else {
ArrayList<String> viewNames = new ArrayList<String>();
for (EObject eObject : elements) {
viewNames.add(((ArchimateDiagramModel) eObject).getName());
}
System.out.println("found " + elements.size() + " views, please specifiy one of " + viewNames);
}
}
if (ontologyIRI == null || ontologyIRI.trim().length() == 0) {
ontologyIRI = getDefaultIRI(layoutFile);
}
return exportLayout(layoutFile, ontologyIRI, view);
}
/** Exports the layout of a model to a CSV separated file */
public static boolean exportLayout(File layoutFile, String defaultIRI, ArchimateDiagramModel view)
throws FileNotFoundException {
if (view != null) {
EList<IDiagramModelObject> children = view.getChildren();
ArrayList<String> export = new ArrayList<String>();
HashMap<String, String> iriNameMap = new HashMap<String, String>();
exportChildrenLayout(children, iriNameMap, 0, 0, export, defaultIRI);
Collections.sort(export);
PrintWriter pw = new PrintWriter(layoutFile);
for (String string : export) {
pw.println("# " + iriNameMap.get(string));
pw.println(string);
}
pw.flush();
pw.close();
return true;
} else {
return false;
}
}
public static ArchimateDiagramModel getLayeredView(IArchimateModel model) {
for (EObject eObject : model.getFolder(FolderType.DIAGRAMS).getElements()) {
if (eObject instanceof ArchimateDiagramModel) {
ArchimateDiagramModel diagramModel = (ArchimateDiagramModel) eObject;
if (diagramModel.getViewpoint() == IViewpoint.LAYERED_VIEWPOINT) {
return diagramModel;
}
}
}
return null;
}
public static ArchimateDiagramModel getViewByName(IArchimateModel model, String viewName) {
for (EObject eObject : model.getFolder(FolderType.DIAGRAMS).getElements()) {
if (eObject instanceof ArchimateDiagramModel) {
ArchimateDiagramModel diagramModel = (ArchimateDiagramModel) eObject;
if (diagramModel.getName().equals(viewName)) {
return diagramModel;
}
}
}
return null;
}
public static File getDefaultLayoutFile(File file) {
return new File(file.getAbsolutePath() + ".layout.csv");
}
private static void exportChildrenLayout(EList<IDiagramModelObject> children, HashMap<String, String> iriNameMap,
int x, int y, ArrayList<String> export, String iriPrefix) {
for (IDiagramModelObject diagramModelObject : children) {
int coordX = x + diagramModelObject.getBounds().getX();
int coordY = y + diagramModelObject.getBounds().getY();
if (diagramModelObject instanceof DiagramModelGroup) {
exportChildrenLayout(((DiagramModelGroup) diagramModelObject).getChildren(), iriNameMap, coordX,
coordY, export, iriPrefix);
} else {
String elementName = diagramModelObject.getId();
if (diagramModelObject instanceof DiagramModelArchimateObject) {
elementName = getOWLIRIFragment(((DiagramModelArchimateObject) diagramModelObject)
.getArchimateElement());
}
StringBuilder sb = new StringBuilder(iriPrefix).append("#").append(elementName).append("\t")
.append(coordX).append("\t").append(coordY);
if (diagramModelObject instanceof DiagramModelArchimateObject
&& ((DiagramModelArchimateObject) diagramModelObject).getChildren() != null
&& ((DiagramModelArchimateObject) diagramModelObject).getChildren().size() > 0) {
sb.append("\t").append(diagramModelObject.getBounds().getWidth()).append("\t")
.append(diagramModelObject.getBounds().getHeight());
exportChildrenLayout(((DiagramModelArchimateObject) diagramModelObject).getChildren(), iriNameMap,
coordX, coordY, export, iriPrefix);
}
export.add(sb.toString());
iriNameMap.put(sb.toString(), diagramModelObject.getName());
}
}
}
public static String formatString(String s) {
return s.replace(" ", "_").replace("(", "-").replace(")", "-").replace("/", "_");
}
}