/*
* This software is Copyright 2005,2006,2007,2008 Langdale Consultants.
* Langdale Consultants can be contacted at: http://www.langdale.com.au
*/
package au.com.langdale.cimtoole.project;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import au.com.langdale.cim.CIM;
import au.com.langdale.cimtoole.CIMNature;
import au.com.langdale.cimtoole.CIMToolPlugin;
import au.com.langdale.cimtoole.builder.CIMBuilder;
import au.com.langdale.cimtoole.registries.ModelParser;
import au.com.langdale.cimtoole.registries.ModelParserRegistry;
import au.com.langdale.jena.TreeModelBase;
import au.com.langdale.jena.UMLTreeModel;
import au.com.langdale.kena.Composition;
import au.com.langdale.kena.IO;
import au.com.langdale.kena.ModelFactory;
import au.com.langdale.kena.OntModel;
import au.com.langdale.kena.OntResource;
import au.com.langdale.kena.ResIterator;
import au.com.langdale.profiles.MESSAGE;
import au.com.langdale.profiles.ProfileModel;
import au.com.langdale.validation.RepairMan;
import au.com.langdale.validation.ValidatorUtil;
import au.com.langdale.workspace.ResourceOutputStream;
import au.com.langdale.xmi.CIMInterpreter;
import au.com.langdale.xmi.EAPExtractor;
import au.com.langdale.xmi.UML;
import au.com.langdale.xmi.XMIParser;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.OWL2;
import com.hp.hpl.jena.vocabulary.RDF;
/**
* Utility tasks for CIMTool plugin. Tasks are instances of <code>IWorkspaceRunnable</code>
* and in some cases, plain methods.
*/
public class Task extends Info {
public static class EmptyStream extends InputStream {
@Override
public int read() throws IOException {
return -1;
}
}
public static IWorkspaceRunnable chain(final IWorkspaceRunnable first, final IWorkspaceRunnable second) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
first.run(monitor);
second.run(monitor);
}
};
}
public static IWorkspaceRunnable createProfile(final IFile file, final String namespace, final String envname) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
OntModel model = ModelFactory.createMem();
OntModel backgroundModel = getBackgroundModel(file);
initProfile(model, backgroundModel, namespace, envname, null);
monitor.worked(1);
writeProfile(file, model, monitor);
putProperty( file, PROFILE_NAMESPACE, namespace);
monitor.worked(1);
}
};
}
public static IWorkspaceRunnable createProject(final IProject project, final URI location) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
IProjectDescription description = ResourcesPlugin.getWorkspace().newProjectDescription(project.getName());
description.setLocationURI(location);
description.setNatureIds(new String[] {CIMNature.NATURE_ID});
ICommand command = description.newCommand();
command.setBuilderName(CIMBuilder.BUILDER_ID);
description.setBuildSpec(new ICommand[] {command});
project.create(description, monitor);
project.open(monitor);
monitor.worked(1);
getSchemaFolder(project).create(false, true, monitor);
getProfileFolder(project).create(false, true, monitor);
getInstanceFolder(project).create(false, true, monitor);
getIncrementalFolder(project).create(false, true, monitor);
saveSettings(project, ModelFactory.createMem()).run(monitor);
monitor.worked(1);
}
};
}
public static IWorkspaceRunnable createRules(final IFile file, final String template) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
InputStream source;
if(template != null)
source = getClass().getResourceAsStream("/au/com/langdale/profiles/" + template + ".xsl");
else
source = new EmptyStream();
monitor.worked(1);
writeFile(file, source, monitor);
}
};
}
public static IWorkspaceRunnable createValidationRules(final IFile file, final String template) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
InputStream source;
if(template != null)
source = ValidatorUtil.openStandardRules(template);
else
source = new EmptyStream();
monitor.worked(1);
writeFile(file, source, monitor);
}
};
}
public static IWorkspaceRunnable importSchema(final IFile file, final String pathname, final String namespace ) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
importFile(file, pathname, monitor);
putProperty( file, SCHEMA_NAMESPACE, namespace);
}
};
}
public static IWorkspaceRunnable importProfile(final IFile file, final String pathname) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
String defaultName = getPreference(PROFILE_ENVELOPE);
String namespace = getPreference(PROFILE_NAMESPACE);
OntModel model = parse(openExternalFile(pathname, monitor), "owl", namespace);
model = fixupProfile(model, getBackgroundModel(file), defaultName, namespace);
writeProfile(file, model, monitor);
putProperty( file, PROFILE_NAMESPACE, namespace);
}
};
}
public static IWorkspaceRunnable importRules(final IFile file, final String pathname) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
importFile(file, pathname, monitor);
}
};
}
public static IWorkspaceRunnable importModel(final IFile file, final String pathname, final String namespace, final IFile profile) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
importFile(file, pathname, monitor);
putProperty( file, PROFILE_PATH, profile.getName());
putProperty( file, INSTANCE_NAMESPACE, namespace);
}
};
}
public static OntModel parse(IFile file) throws CoreException {
String ext = file.getFileExtension().toLowerCase();
if( ext.equals("xmi")) {
return parseXMI(file);
}
else if( ext.equals("eap"))
return parseEAP(file);
else {
if (ModelParserRegistry.INSTANCE.hasParserForExtension(ext)){
ModelParser[] parsers = ModelParserRegistry.INSTANCE.getParsersForExtension(ext);
/* For now we'll just pick the first one so we don't start adding too much UI stuff... */
ModelParser parser = parsers[0];
parser.setFile(file);
try {
parser.run();
} catch (IOException e) {
throw new CoreException(
new Status(
IStatus.ERROR,
CIMToolPlugin.PLUGIN_ID, e.getMessage(), e));
}
return interpretSchema(parser.getModel(), file);
}else
return parseOWL(file);
}
}
public static TreeModelBase createTreeModel(IResource resource) throws CoreException {
Cache cache = CIMToolPlugin.getCache();
if(resource instanceof IProject)
return createUMLTreeModel(cache.getMergedOntologyWait(getSchemaFolder((IProject)resource)));
else if( isSchemaFolder(resource))
return createUMLTreeModel(cache.getMergedOntologyWait((IFolder)resource));
else if( isSchema(resource))
return createUMLTreeModel(cache.getOntologyWait((IFile)resource));
else if(isProfile(resource)) {
IFile file = (IFile) resource;
return getMessageModel(file);
} else
return new UMLTreeModel();
}
private static TreeModelBase createUMLTreeModel(OntModel model) {
UMLTreeModel tree = new UMLTreeModel();
tree.setOntModel(model);
tree.setRootResource(UML.global_package);
return tree;
}
public static ProfileModel getMessageModel(IFile file) throws CoreException {
ProfileModel model = new ProfileModel();
model.setOntModel(getProfileModel(file));
model.setBackgroundModel(getBackgroundModel(file));
return model;
}
private static OntModel parseXMI(IFile file) throws CoreException {
XMIParser parser = new XMIParser();
try {
parser.parse(new BufferedInputStream( file.getContents()));
} catch (Exception e) {
throw error("Can't parse model file " + file.getName(), e);
}
return interpretSchema(parser.getModel(), file);
}
private static OntModel parseEAP(IFile file) throws CoreException {
EAPExtractor extractor;
try {
extractor = new EAPExtractor(file.getLocation().toFile());
extractor.run();
} catch (IOException e) {
throw error("can't access EA project", e);
}
return interpretSchema(extractor.getModel(), file);
}
private static OntModel interpretSchema(OntModel raw, IFile file) throws CoreException {
String base = getProperty(file, SCHEMA_NAMESPACE);
if( base == null ) {
if( file.getName().toLowerCase().startsWith("cim"))
base = CIM.NS;
else
base = file.getLocationURI().toString() + "#";
}
IFile auxfile = getRelated(file, "annotation");
OntModel annote;
if(auxfile.exists()) {
annote = ModelFactory.createMem();
IO.read(annote, auxfile.getContents(), base, "TURTLE");
}
else
annote = null;
return CIMInterpreter.interpret(raw, base, annote, getPreferenceOption(USE_PACKAGE_NAMES));
}
private static OntModel parseOWL(IFile file) throws CoreException {
OntModel model;
String extn = file.getFileExtension();
if( extn == null )
extn = "";
else
extn = extn.toLowerCase();
String base;
if( isProfile(file))
base = getProperty(file, PROFILE_NAMESPACE);
else if( extn.equals(SETTINGS_EXTENSION))
base = CIMToolPlugin.PROJECT_NS;
else
base = file.getLocationURI().toString() + "#";
try {
model = parse(new BufferedInputStream( file.getContents()), extn, base);
}
catch( Exception ex) {
throw error("Can't parse model file " + file.getName(), ex);
}
return model;
}
public static OntModel parse(InputStream contents, String ext, String base) {
OntModel model = ModelFactory.createMem();
String syntax;
if(ext.equals("n3"))
syntax = "N3";
else if(ext.equals("diagnostic") || ext.equals("cimtool-settings") || ext.equals("mapping-ttl"))
syntax = "TURTLE";
else if(ext.equals("owl") || ext.equals("repair"))
syntax = IO.RDF_XML_WITH_NODEIDS;
else
syntax = "RDF/XML";
IO.read(model, contents, base, syntax);
return model;
}
public static void write(OntModel model, String namespace, boolean xmlbase, IFile file, String format, IProgressMonitor monitor) throws CoreException {
OutputStream stream = new ResourceOutputStream(file, monitor, false, false);
write(model, namespace, xmlbase, format, stream);
}
public static void write(OntModel model, String namespace, boolean xmlbase, String format, OutputStream stream)
throws CoreException {
try {
HashMap style = new HashMap();
if(format != null && format.equals("RDF/XML-ABBREV"))
style.put("prettyTypes", PrettyTypes.PRETTY_TYPES);
if( namespace != null) {
if(namespace.endsWith("#"))
namespace = namespace.substring(0, namespace.length()-1);
if(xmlbase)
style.put("xmlbase", namespace);
style.put("relativeURIs", "same-document");
}
style.put("showXmlDeclaration", "true");
IO.write(model, stream, namespace, format, style);
stream.close();
} catch (IOException e) {
throw error("can't write model to stream", e);
}
}
public static IWorkspaceRunnable exportSchema(final IProject project, final String pathname) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
IFolder folder = Info.getSchemaFolder(project);
OntModel schema = CIMToolPlugin.getCache().getMergedOntologyWait(folder);
OutputStream output;
try {
output = new BufferedOutputStream( new FileOutputStream(pathname));
}
catch( IOException ex) {
throw error("can't write to " + pathname);
}
writeOntology(output, schema, "RDF/XML", monitor);
}
};
}
public static IWorkspaceRunnable saveMappings(final IFile file, final OntModel model) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
writeMappings(file, model, monitor);
}
};
}
public static IWorkspaceRunnable repairProfile(final IFile file, final RepairMan repairs) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
if( repairs.size() > 0 ) {
IFile related = Info.getRelated(file, "owl");
OntModel model = Task.getProfileModel(related);
model = repairs.apply(model);
writeProfile(related, model, monitor);
}
}
};
}
public static IWorkspaceRunnable saveProfile(final IFile file, final OntModel model) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
writeProfile(file, model, monitor);
}
};
}
public static IWorkspaceRunnable saveSettings(final IProject project, final OntModel model) {
model.setNsPrefix("tool", CIMToolPlugin.SETTING_NS);
model.setNsPrefix("project", CIMToolPlugin.PROJECT_NS);
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
write(model, CIMToolPlugin.PROJECT_NS, true, getSettings(project), "TURTLE", monitor);
}
};
}
public static IWorkspaceRunnable delete(final IResource resource) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
resource.delete(false, monitor);
monitor.worked(1);
}
};
}
public static IWorkspaceRunnable delete(final IResource[] resources) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
for (int ix = 0; ix < resources.length; ix++) {
resources[ix].delete(false, monitor);
monitor.worked(1);
}
}
};
}
private static void importFile(final IFile file, final String pathname, IProgressMonitor monitor) throws CoreException {
InputStream source = openExternalFile(pathname, monitor);
writeFile(file, source, monitor);
monitor.worked(1);
}
private static InputStream openExternalFile(final String pathname, IProgressMonitor monitor) throws CoreException {
InputStream source;
try {
source = new BufferedInputStream( new FileInputStream(pathname));
} catch (FileNotFoundException e) {
throw error("can't open " + pathname, e);
}
monitor.worked(1);
return source;
}
private static void writeFile(final IFile file, InputStream source, IProgressMonitor monitor) throws CoreException {
if( file.exists())
file.setContents(source, false, true, monitor);
else
file.create(source, false, monitor);
}
public static void writeProfile(IFile file, OntModel model, IProgressMonitor monitor) throws CoreException {
writeOntology(file, model, IO.RDF_XML_WITH_NODEIDS, monitor);
}
public static void writeOntology(IFile file, OntModel model, String format, IProgressMonitor monitor) throws CoreException {
OutputStream stream = new ResourceOutputStream(file, monitor, false, false);
writeOntology(stream, model, format, monitor);
}
public static void writeOntology(OutputStream stream, OntModel model, String format, IProgressMonitor monitor) throws CoreException {
OntResource ont = model.getValidOntology();
String namespace;
if( ont != null ) {
namespace = ont.getURI() + "#";
model.setNsPrefix("", namespace);
}
else
namespace = null;
write(model, namespace, true, format, stream);
}
public static OntModel getBackgroundModel(IFile file) throws CoreException {
Cache cache = CIMToolPlugin.getCache();
IFolder schema = getSchemaFolder(file.getProject());
return cache.getMergedOntologyWait(schema);
}
public static OntModel getProfileModel(IFile file) throws CoreException {
Cache cache = CIMToolPlugin.getCache();
return fixupProfile(file, cache.getOntologyWait(file), getBackgroundModel(file));
}
public static OntModel fixupProfile(IFile file, OntModel model, OntModel backgroundModel) {
String defaultName, namespace;
try {
defaultName = getProperty(file, Info.PROFILE_ENVELOPE);
namespace = getProperty(file, PROFILE_NAMESPACE);
} catch (CoreException e) {
throw new RuntimeException(e);
}
return fixupProfile(model, backgroundModel, defaultName, namespace);
}
private static OntModel fixupProfile(OntModel model, OntModel backgroundModel, String defaultName, String defaultNamespace) {
OntResource header = model.getValidOntology();
if( header != null )
return model;
model = Composition.copy(model);
String namespace = defaultNamespace;
String label = defaultName;
String comment = null;
// harvest and remove old style, mal-formed or repeated headers
Iterator it = model.listSubjectsWithProperty(RDF.type, OWL2.Ontology).toSet().iterator();
while(it.hasNext()) {
OntResource ont = (OntResource) it.next();
String candLabel = ont.getLabel();
if( candLabel != null && ! candLabel.equals(defaultName))
label = candLabel;
String candComment = ont.getComment();
if( candComment != null && candComment.length() > 0)
comment = candComment;
if( ont.isURIResource()) {
String uri = ont.getURI();
if(! uri.contains("#") || uri.endsWith("#"))
namespace = uri;
}
ont.remove();
}
// remove any untyped, old style header
MESSAGE.profile.inModel(model).remove();
initProfile(model, backgroundModel, namespace, label, comment);
return model;
}
public static void initProfile(OntModel profileModel, OntModel backgroundModel, String namespace, String envname, String comment) {
OntResource header = initOntology(profileModel, namespace, envname, comment);
// add the import to the CIM
if( backgroundModel != null ) {
OntResource backOnt = backgroundModel.getValidOntology();
if( backOnt != null ) {
header.addProperty(OWL.imports, backOnt);
profileModel.setNsPrefix("cim", backOnt.getURI() + "#");
}
}
}
protected static OntResource initOntology(OntModel model, String namespace, String label, String comment) {
// add standard ontology header
if( ! namespace.endsWith("#"))
namespace += "#";
String uri = namespace.substring(0, namespace.length()-1);
OntResource header = model.createResource(uri);
header.addRDFType(OWL.Ontology);
header.addLabel(label, null);
if( comment != null)
header.addComment(comment, null);
model.setNsPrefix("", namespace);
return header;
}
public static IWorkspaceRunnable createMappings(final IFile file, final String namespace, final String envname) {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
OntModel model = ModelFactory.createMem();
initOntology(model, namespace, envname, null);
monitor.worked(1);
writeMappings(file, model, monitor);
monitor.worked(1);
}
};
}
protected static void writeMappings(final IFile file, final OntModel model,
IProgressMonitor monitor) throws CoreException {
String ext = file.getFileExtension();
String format = ext != null && ext.equals("mapping-ttl")? "TURTLE": "RDF/XML";
writeOntology(file, model, format, monitor);
}
}