package org.archstudio.prolog.archstudio; import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; import org.archstudio.prolog.engine.ProofContext; import org.archstudio.prolog.parser.ParseException; import org.archstudio.prolog.parser.PrologParser; import org.archstudio.prolog.term.ComplexTerm; import org.archstudio.prolog.term.ConstantTerm; import org.archstudio.prolog.term.StringTerm; import org.archstudio.prolog.term.Term; import org.archstudio.sysutils.SystemUtils; import org.archstudio.xadl3.prolog_3_0.PrologExtension; import org.archstudio.xadl3.prolog_3_0.Statement; import org.archstudio.xarchadt.ObjRef; import org.archstudio.xarchadt.XArchADTProxy; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.osgi.framework.Bundle; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Sets; public class PrologUtils { public static List<ComplexTerm> getFacts(ProofContext proofContext, IProgressMonitor monitor, EObject eObject) throws ParseException { SubMonitor progress = SubMonitor.convert(monitor, "Calculating Facts", 1); try { List<ComplexTerm> facts = Lists.newArrayList(); Set<String> nsURIs = Sets.newHashSet(); StringBuffer sb = new StringBuffer(":- discontiguous(child/3, type/2, value/3).\n"); processEObject(proofContext, facts, nsURIs, sb, 0, progress.newChild(1), null, null, eObject); // add prolog for schema NS URIs IExtensionRegistry reg = Platform.getExtensionRegistry(); if (reg != null) { // The Extension Registry can be null if we're running outside of Eclipse for (IConfigurationElement statements : reg .getConfigurationElementsFor("org.archstudio.prolog.archstudio.prologstatement")) { String name = statements.getAttribute("name"); String nsURI = statements.getAttribute("nsURI"); if (nsURI == null || nsURIs.contains(nsURI)) { sb.append("\n% ").append(name).append("\n"); if (nsURI != null) { sb.append("% ").append(nsURI).append("\n"); } for (IConfigurationElement child : statements.getChildren()) { if ("Statement".equals(child.getName())) { String statement = child.getValue(); if (statement != null && statement.trim().length() > 0) { sb.append(statement).append("\n"); for (Term term : PrologParser.parseTerms(proofContext, statement)) { facts.add((ComplexTerm) term); } } } else if ("Resource".equals(child.getName())) { String bundleName = statements.getContributor().getName(); String path = child.getAttribute("path"); Bundle bundle = Platform.getBundle(bundleName); URL url = bundle.getEntry(path); InputStream in = null; try { BufferedReader br = new BufferedReader(new InputStreamReader(in = url.openStream())); String line; StringBuffer statement = new StringBuffer(); while ((line = br.readLine()) != null) { sb.append(line).append("\n"); statement.append(line).append("\n"); } if (statement.toString().trim().length() > 0) { for (Term term : PrologParser.parseTerms(proofContext, statement.toString())) { facts.add((ComplexTerm) term); } } } catch (IOException e) { throw new ParseException(e); } finally { if (in != null) { SystemUtils.closeQuietly(in); } } } } } } } StringSelection stringSelection = new StringSelection(sb.toString()); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, stringSelection); return facts; } finally { if (monitor != null) { monitor.done(); } } } private static void processEObject(ProofContext proofContext, List<ComplexTerm> facts, Set<String> nsURIs, StringBuffer sb, int indent, SubMonitor monitor, EObject eParent, EStructuralFeature eFeature, EObject eObject) throws ParseException { if (eObject == null) { return; } // Record the NS URI of each eObject nsURIs.add(eObject.eClass().getEPackage().getNsURI()); // add relationship of parent to child if (eParent != null) { facts.add(createChild(sb, indent, eParent, eFeature.getName(), eObject)); } // add types of eObject for (EClass eClass : eObject.eClass().getEAllSuperTypes()) { facts.add(createType(sb, indent + 1, eObject, eClass)); } facts.add(createType(sb, indent + 1, eObject, eObject.eClass())); // Process Structural Features SubMonitor featureMonitor = monitor.newChild(1).setWorkRemaining( eObject.eClass().getEAllStructuralFeatures().size()); boolean isDocumentRoot = eObject.eContainer() == null; for (EStructuralFeature feature : sort(eObject.eClass().getEAllStructuralFeatures())) { if (monitor.isCanceled()) { break; } if (isDocumentRoot) { if (feature.getName().equals("mixed")) { continue; } if (feature.getName().equals("xMLNSPrefixMap")) { continue; } if (feature.getName().equals("xSISchemaLocation")) { continue; } if (feature.getName().equals("topLevelElement")) { continue; } } if (feature instanceof EAttribute) { // e.g., id, name processEAttribute(facts, sb, indent + 1, eObject, feature); featureMonitor.worked(1); } else if (feature instanceof EReference && !((EReference) feature).isContainment()) { processEReference(facts, sb, indent + 1, eObject, (EReference) feature); featureMonitor.worked(1); } else if (feature.isMany()) { // e.g., components, connectors, brick interfaces SubMonitor childMonitor = featureMonitor.newChild(1).setWorkRemaining( ((EList<?>) eObject.eGet(feature)).size()); for (Object childObject : (EList<?>) eObject.eGet(feature)) { if (childObject instanceof EObject) { processEObject(proofContext, facts, nsURIs, sb, indent + 1, childMonitor.newChild(1), eObject, feature, (EObject) childObject); } else { processEAttribute(facts, sb, indent + 1, eObject, feature); } childMonitor.worked(1); } } else { // Plain children processEObject(proofContext, facts, nsURIs, sb, indent + 1, featureMonitor.newChild(1), eObject, feature, (EObject) eObject.eGet(feature)); } } // Process prolog statements if (eObject instanceof PrologExtension) { for (Statement statement : ((PrologExtension) eObject).getStatement()) { String value = statement.getValue(); if (value == null || value.trim().length() == 0) { continue; } sb.append(Strings.repeat(" ", indent + 1)).append(value).append("\n"); for (Term term : PrologParser.parseTerms(proofContext, value)) { facts.add((ComplexTerm) term); } } } } private static List<EStructuralFeature> sort(EList<EStructuralFeature> eAllStructuralFeatures) { List<EStructuralFeature> sorted = Lists.newArrayList(eAllStructuralFeatures); Collections.sort(sorted, new Comparator<EStructuralFeature>() { @Override public int compare(EStructuralFeature arg0, EStructuralFeature arg1) { if (sortIsSimple(arg0) && !sortIsSimple(arg1)) { return -1; } if (!sortIsSimple(arg0) && sortIsSimple(arg1)) { return 1; } return arg0.getName().compareTo(arg1.getName()); } }); return sorted; } private static boolean sortIsSimple(EStructuralFeature f) { return f instanceof EAttribute; } private static void processEAttribute(List<ComplexTerm> facts, StringBuffer sb, int indent, EObject parent, EStructuralFeature eAttribute) { String attributeName = eAttribute.getName(); // Ignore attributes with no value Object attributeValue = parent.eGet(eAttribute); if (attributeValue == null) { return; } facts.add(createAttribute(sb, indent, parent, attributeName, attributeValue)); } @SuppressWarnings("unchecked") private static void processEReference(List<ComplexTerm> facts, StringBuffer sb, int indent, EObject parent, EReference eReference) { String refType = eReference.getName(); if (parent.eGet(eReference) instanceof EObject) { EObject refObj = (EObject) parent.eGet(eReference); if (refObj != null) { facts.add(createChild(sb, indent, parent, refType, refObj)); } } else if (parent.eGet(eReference) instanceof EList) { for (EObject refObj : (EList<EObject>) parent.eGet(eReference)) { facts.add(createChild(sb, indent, parent, refType, refObj)); } } } private static ComplexTerm createAttribute(StringBuffer sb, int indent, EObject parent, String attributeName, Object attributeValue) { sb.append( Strings.repeat(" ", indent) + "value(" + toAtom(parent) + ", " + SystemUtils.uncapFirst(attributeName) + ", " + toAtom(attributeValue) + ").").append("\n"); return new ComplexTerm("value", Lists.newArrayList(toTerm(parent), new ConstantTerm(SystemUtils.uncapFirst(attributeName)), toTerm(attributeValue))); } private static ComplexTerm createChild(StringBuffer sb, int indent, EObject parent, String childName, EObject child) { sb.append( Strings.repeat(" ", indent) + "child(" + toAtom(parent) + ", " + SystemUtils.uncapFirst(childName) + ", " + toAtom(child) + ").").append("\n"); return new ComplexTerm("child", Lists.newArrayList(toTerm(parent), new ConstantTerm(SystemUtils.uncapFirst(childName)), toTerm(child))); } private static ComplexTerm createType(StringBuffer sb, int indent, EObject eObject, EClass eClass) { sb.append( Strings.repeat(" ", indent) + "type(" + toAtom(eObject) + ", " + SystemUtils.uncapFirst(eClass.getName()) + ").").append("\n"); return new ComplexTerm("type", Lists.newArrayList(toTerm(eObject), new ConstantTerm(SystemUtils.uncapFirst(eClass.getName())))); } private static Term toTerm(Object value) { if (value instanceof Number) { return new ConstantTerm(value); } if (value instanceof EObject) { return new ConstantTerm(value); } return new StringTerm("" + value); } private static String toAtom(Object value) { String atom; if (value instanceof EObject) { ObjRef id = XArchADTProxy.unproxy((EObject) value); atom = Long.toString(id.getUID()); } else if (value instanceof Number) { atom = value.toString(); } else { atom = "'" + value.toString().replace('\'', '\"').replaceAll("\\s+", " ") + "'"; } return atom; } }