Index: plugin-src/src/org/eclipse/emf/validation/model/CategoryManager.java =================================================================== --- plugin-src/src/org/eclipse/emf/validation/model/CategoryManager.java (revision 1513) +++ plugin-src/src/org/eclipse/emf/validation/model/CategoryManager.java (working copy) @@ -17,6 +17,7 @@ import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; +import org.eclipse.emf.common.EMFPlugin; import org.eclipse.emf.validation.internal.EMFModelValidationDebugOptions; import org.eclipse.emf.validation.internal.EMFModelValidationPlugin; import org.eclipse.emf.validation.internal.l10n.ValidationMessages; @@ -230,19 +231,38 @@ * point. */ private void loadCategories() { - IConfigurationElement[] elements = Platform.getExtensionRegistry().getExtensionPoint( + IConfigurationElement[] elements = new IConfigurationElement[0]; + if (EMFPlugin.IS_ECLIPSE_RUNNING) { + elements = Platform.getExtensionRegistry().getExtensionPoint( EMFModelValidationPlugin.getPluginId(), EMFModelValidationPlugin.CONSTRAINT_PROVIDERS_EXT_P_NAME) .getConfigurationElements(); - - for (IConfigurationElement next : elements) { - if (next.getName().equals(XmlConfig.E_CATEGORY)) { - loadCategories(globalCategory, next); - } } + configureCategories(elements); } /** + *

+ * Configures my categories from the Eclipse configuration + * elements + *

+ *

+ * NOTE that this method should only be called by the EMF Model + * Validation Plug-in, not by any client code! + *

+ * + * @param elements + */ + public void configureCategories(IConfigurationElement[] elements) { + for (int i = 0; i < elements.length; i++) { + IConfigurationElement next = elements[i]; + if (next.getName().equals(XmlConfig.E_CATEGORY)) { + loadCategories(globalCategory, next); + } + } + } + + /** * Loads subcategories of the specified parent category. * @param parent * @param element Index: plugin-src/src/org/eclipse/emf/validation/preferences/EMFModelValidationPreferences.java =================================================================== --- plugin-src/src/org/eclipse/emf/validation/preferences/EMFModelValidationPreferences.java (revision 1513) +++ plugin-src/src/org/eclipse/emf/validation/preferences/EMFModelValidationPreferences.java (working copy) @@ -14,6 +14,7 @@ import org.eclipse.core.runtime.Preferences; +import org.eclipse.emf.common.EMFPlugin; import org.eclipse.emf.validation.internal.EMFModelValidationPlugin; import org.eclipse.emf.validation.service.ConstraintRegistry; import org.eclipse.emf.validation.service.IConstraintDescriptor; @@ -27,7 +28,7 @@ static final String CONSTRAINT_DISABLED_PREFIX = "con.disabled/"; //$NON-NLS-1$ private static final Preferences prefs = - EMFModelValidationPlugin.getPlugin().getPluginPreferences(); + (!EMFPlugin.IS_ECLIPSE_RUNNING)?new Preferences():EMFModelValidationPlugin.getPlugin().getPluginPreferences(); /** * Not instantiable, as all features are static. Index: plugin-src/src/org/eclipse/emf/validation/internal/service/TraversalStrategyManager.java =================================================================== --- plugin-src/src/org/eclipse/emf/validation/internal/service/TraversalStrategyManager.java (revision 1513) +++ plugin-src/src/org/eclipse/emf/validation/internal/service/TraversalStrategyManager.java (working copy) @@ -18,6 +18,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; +import org.eclipse.emf.common.EMFPlugin; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; @@ -95,11 +96,12 @@ * required by a validation operation. */ private void initStrategies() { - IConfigurationElement[] strats = - Platform.getExtensionRegistry().getConfigurationElementsFor( + IConfigurationElement[] strats = new IConfigurationElement[0]; + if (EMFPlugin.IS_ECLIPSE_RUNNING) { + strats = Platform.getExtensionRegistry().getConfigurationElementsFor( EMFModelValidationPlugin.getPluginId(), TRAVERSAL_EXT_P_NAME); - + } for (int i = 0; i < strats.length; i++) { IConfigurationElement config = strats[i]; Index: plugin-src/src/org/eclipse/emf/validation/internal/EMFModelValidationPlugin.java =================================================================== --- plugin-src/src/org/eclipse/emf/validation/internal/EMFModelValidationPlugin.java (revision 1513) +++ plugin-src/src/org/eclipse/emf/validation/internal/EMFModelValidationPlugin.java (working copy) @@ -12,16 +12,25 @@ package org.eclipse.emf.validation.internal; +import java.net.URL; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.EMFPlugin; import org.eclipse.emf.common.util.ResourceLocator; import org.eclipse.emf.validation.internal.l10n.ValidationMessages; +import org.eclipse.emf.validation.internal.service.ClientContextManager; +import org.eclipse.emf.validation.internal.util.XmlConstraintFactory; +import org.eclipse.emf.validation.model.CategoryManager; +import org.eclipse.emf.validation.service.ConstraintFactory; +import org.eclipse.emf.validation.service.ModelValidationService; +import org.eclipse.emf.validation.util.XmlConfig; import org.eclipse.osgi.util.NLS; /** @@ -166,6 +175,13 @@ new EMFModelValidationPlugin(); private static Implementation plugin; + + /** + * Flag to track standalone configuration, that should happen once + * to prevent multiple registration of constraint providers, parsers, + * etc. + */ + private boolean alreadyConfigured = false; /** * Initializes me. @@ -174,6 +190,49 @@ super(new ResourceLocator[]{}); } + /** + * Configures parsers, constraint providers, categories and constraint bindings + * from the given XML document urls in standalone mode (no Eclipse). + *

+ * At a minimum one URL should refer to the org.eclipse.emf.validation plugin descriptor. For example: + *

jar:file:///c:/mydir/lib/org.eclipse.emf.validation_1.1.0.v200705301635.jar!/plugin.xml
+ * and another URL should refer to the user contributed constraint providers. For example: + *
file:///c:/mydir/plugin.xml
+ * To enable support for OCL constraints, add a URL to the org.eclipse.emf.validation.ocl plugin descriptor. For example: + *
jar:file:///c:/mydir/lib/org.eclipse.emf.validation.ocl_1.1.0.v200705301635.jar!/plugin.xml
+ * + * @param urls the locations of the XML documents to use for standalone initialization. + * @throws CoreException on any problem parsing an XML file + */ + public void configureStandalone(URL[] urls) throws CoreException { + assert urls != null; + if (!EMFPlugin.IS_ECLIPSE_RUNNING && !alreadyConfigured) { + alreadyConfigured = true; + for (int i=0; i < urls.length; i++) { + IConfigurationElement element = XmlConfig.load(urls[i]); + // Configure any defined parsers + IConfigurationElement[] parsers = + XmlConfig.findExtensionPoint(getPluginId() + "." + XmlConstraintFactory.CONSTRAINT_PARSERS_EXT_P_NAME, element); + if (parsers != null) { + ((XmlConstraintFactory)ConstraintFactory.getInstance()).configureParsers(parsers); + } + // Configure any defined constraint providers and categories + IConfigurationElement[] providers = + XmlConfig.findExtensionPoint(getPluginId() + "." + CONSTRAINT_PROVIDERS_EXT_P_NAME, element); + if (providers != null) { + ModelValidationService.getInstance().configureProviders(providers); + CategoryManager.getInstance().configureCategories(providers); + } + // Configure any defined constraint bindings + IConfigurationElement[] bindings = + XmlConfig.findExtensionPoint(getPluginId() + "." + CONSTRAINT_BINDINGS_EXT_P_NAME, element); + if (bindings != null) { + ClientContextManager.getInstance().configureConstraintBindings(bindings); + } + } + } + } + // implements the inherited method @Override public ResourceLocator getPluginResourceLocator() { @@ -195,7 +254,12 @@ * @return my plug-in unique ID */ public static String getPluginId() { - return getPlugin().getBundle().getSymbolicName(); + if (!EMFPlugin.IS_ECLIPSE_RUNNING) { + return "org.eclipse.emf.validation"; + } + else { + return getPlugin().getBundle().getSymbolicName(); + } } /** @@ -229,7 +293,7 @@ * */ protected static boolean shouldTrace() { - return plugin.isDebugging(); + return (!EMFPlugin.IS_ECLIPSE_RUNNING)?false:plugin.isDebugging(); } /** Index: plugin-src/src/org/eclipse/emf/validation/internal/util/ConstraintsContentHandler.java =================================================================== --- plugin-src/src/org/eclipse/emf/validation/internal/util/ConstraintsContentHandler.java (revision 1513) +++ plugin-src/src/org/eclipse/emf/validation/internal/util/ConstraintsContentHandler.java (working copy) @@ -31,6 +31,7 @@ import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; +import org.eclipse.emf.common.EMFPlugin; import org.eclipse.emf.validation.internal.EMFModelValidationPlugin; import org.eclipse.emf.validation.internal.EMFModelValidationStatusCodes; @@ -529,6 +530,10 @@ if ((s == null) || !s.startsWith("%")) { //$NON-NLS-1$ return s; } else if (resourceBundle == null) { + // FIXME Localize in standalone mode + if (!EMFPlugin.IS_ECLIPSE_RUNNING) { + return s; + } return Platform.getResourceString( Platform.getBundle(extension.getNamespaceIdentifier()), s); Index: plugin-src/src/org/eclipse/emf/validation/internal/util/Log.java =================================================================== --- plugin-src/src/org/eclipse/emf/validation/internal/util/Log.java (revision 1513) +++ plugin-src/src/org/eclipse/emf/validation/internal/util/Log.java (working copy) @@ -16,6 +16,7 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.emf.common.EMFPlugin; import org.eclipse.emf.validation.internal.EMFModelValidationPlugin; /** @@ -141,8 +142,17 @@ Status s = new Status(severity, EMFModelValidationPlugin.getPluginId(), code, message, throwable); - - EMFModelValidationPlugin.getPlugin().log(s); + if (!EMFPlugin.IS_ECLIPSE_RUNNING) { + if (s.isOK()) { + System.out.println(s); + } + else { + System.err.println(s); + } + } + else { + EMFModelValidationPlugin.getPlugin().log(s); + } } /** @@ -154,7 +164,17 @@ * @param status The status object on which to base the log. */ public static void log(IStatus status) { - EMFModelValidationPlugin.getPlugin().log(status); + if (!EMFPlugin.IS_ECLIPSE_RUNNING) { + if (status.isOK()) { + System.out.println(status); + } + else { + System.err.println(status); + } + } + else { + EMFModelValidationPlugin.getPlugin().log(status); + } } /** Index: plugin-src/src/org/eclipse/emf/validation/internal/util/XmlConfigurationElement.java =================================================================== --- plugin-src/src/org/eclipse/emf/validation/internal/util/XmlConfigurationElement.java (revision 1513) +++ plugin-src/src/org/eclipse/emf/validation/internal/util/XmlConfigurationElement.java (working copy) @@ -91,12 +91,18 @@ */ public Object createExecutableExtension(String propertyName) throws CoreException { - - String message = EMFModelValidationPlugin.getMessage( + Object result = null; + String className = getAttribute(propertyName); + try { + Class clazz = this.getClass().getClassLoader().loadClass(className); + result = clazz.newInstance(); + } + catch (Exception ex) { + String message = EMFModelValidationPlugin.getMessage( EMFModelValidationStatusCodes.XML_CREATE_EXTENSION_MSG, new Object[] {getName()}); - CoreException ce = new CoreException( + CoreException ce = new CoreException( new Status( IStatus.ERROR, EMFModelValidationPlugin.getPluginId(), @@ -104,8 +110,10 @@ message, null)); - Trace.throwing(getClass(), "createExecutableExtension", ce); //$NON-NLS-1$ - throw ce; + Trace.throwing(getClass(), "createExecutableExtension", ce); //$NON-NLS-1$ + throw ce; + } + return result; } // implements the interface method Index: plugin-src/src/org/eclipse/emf/validation/internal/util/JavaConstraintParser.java =================================================================== --- plugin-src/src/org/eclipse/emf/validation/internal/util/JavaConstraintParser.java (revision 1513) +++ plugin-src/src/org/eclipse/emf/validation/internal/util/JavaConstraintParser.java (working copy) @@ -157,8 +157,13 @@ Bundle bundle = Platform.getBundle(bundleName); try { - Class resultType = bundle.loadClass(className); - + Class resultType = null; + if (bundle == null) { + resultType = this.getClass().getClassLoader().loadClass(className); + } + else { + resultType = bundle.loadClass(className); + } if (AbstractModelConstraint.class.isAssignableFrom(resultType)) { // instantiate the class extending AbstractModelConstraint result = new ConstraintAdapter( Index: plugin-src/src/org/eclipse/emf/validation/internal/util/XmlConstraintFactory.java =================================================================== --- plugin-src/src/org/eclipse/emf/validation/internal/util/XmlConstraintFactory.java (revision 1513) +++ plugin-src/src/org/eclipse/emf/validation/internal/util/XmlConstraintFactory.java (working copy) @@ -43,7 +43,7 @@ /** * Extension point name for the model providers extension point. */ - private static final String CONSTRAINT_PARSERS_EXT_P_NAME = + public static final String CONSTRAINT_PARSERS_EXT_P_NAME = "constraintParsers"; //$NON-NLS-1$ /** Mapping of language names to parser implementations. */ @@ -115,6 +115,12 @@ } } + public void configureParsers(IConfigurationElement[] elements) { + for (int i = 0; i < elements.length; i++) { + registerParser(elements[i]); + } + } + @SuppressWarnings("deprecation") protected IModelConstraint createConstraint(IParameterizedConstraintDescriptor descriptor) { final String lang = descriptor.getLanguage(); @@ -210,11 +216,13 @@ * extension point. */ private void initializeParsers() { - IConfigurationElement[] configs = - Platform.getExtensionRegistry().getConfigurationElementsFor( + IConfigurationElement[] configs = new IConfigurationElement[0]; + if (Platform.getExtensionRegistry() != null) { + configs = + Platform.getExtensionRegistry().getConfigurationElementsFor( EMFModelValidationPlugin.getPluginId(), CONSTRAINT_PARSERS_EXT_P_NAME); - + } for (IConfigurationElement config : configs) { registerParser(config); } Index: plugin-src/src/org/eclipse/emf/validation/util/XmlConfig.java =================================================================== --- plugin-src/src/org/eclipse/emf/validation/util/XmlConfig.java (revision 1513) +++ plugin-src/src/org/eclipse/emf/validation/util/XmlConfig.java (working copy) @@ -20,7 +20,11 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IContributor; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IPluginDescriptor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.InvalidRegistryObjectException; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.emf.validation.internal.EMFModelValidationDebugOptions; @@ -351,6 +355,19 @@ element.getDeclaringExtension().getNamespaceIdentifier()).getEntry("/"); //$NON-NLS-1$ } } + + /** + * Loads a configuration element from the specified url + * + * @param url the location of the XML document + * @return the configuration element representing the XML document + * @throws CoreException on any problem parsing an XML file + * @see #load(IConfigurationElement, URL) + */ + public static IConfigurationElement load(URL url) + throws CoreException { + return load(new DummyConfigurationElement(), url); + } /** * Loads a <constraints> element from the specified @@ -410,6 +427,33 @@ } } + /** + * Returns the children of the configuration element that matches the given + * extensionPoint, searches recursively the given parent element. + * + * @param extensionPoint The name of the extension point to match + * @param parent The top level configuration element to search + * @return the matching configuration element children or null if not found + */ + public static IConfigurationElement[] findExtensionPoint(String extensionPoint, IConfigurationElement parent) { + if (parent.getAttribute("point") != null && parent.getAttribute("point").equals(extensionPoint)) { + return parent.getChildren(); + } + else { + // Recurse + IConfigurationElement[] children = parent.getChildren(); + if (children != null) { + for (int i = 0; i < children.length; i++) { + IConfigurationElement[] result = findExtensionPoint(extensionPoint, children[i]); + if (result != null) { + return result; + } + } + } + } + return null; + } + /** * Flushes the resource bundles that were loaded for localization of strings * in an XML constraint provider's XML constraint declarations. @@ -440,4 +484,139 @@ return result; } + + // Inner classes + + /** + * A mock configuration element used to supply a valid extension namespace identifier + *

+ * This class is not intended to be used outside of the validation framework. + *

+ * @see XmlConfig#load(URL) + */ + private static class DummyConfigurationElement implements IConfigurationElement { + + IExtension dummyExtension = new DummyExtension("org.eclipse.emf.validation.internal"); + + public IExtension getDeclaringExtension() throws InvalidRegistryObjectException { + return dummyExtension; + } + + // Unused Methods + + public Object createExecutableExtension(String propertyName) throws CoreException { + return null; + } + + public String getAttribute(String name) throws InvalidRegistryObjectException { + return null; + } + + public String getAttributeAsIs(String name) throws InvalidRegistryObjectException { + return null; + } + + public String[] getAttributeNames() throws InvalidRegistryObjectException { + return null; + } + + public IConfigurationElement[] getChildren() throws InvalidRegistryObjectException { + return null; + } + + public IConfigurationElement[] getChildren(String name) throws InvalidRegistryObjectException { + return null; + } + + public IContributor getContributor() throws InvalidRegistryObjectException { + return null; + } + + public String getName() throws InvalidRegistryObjectException { + return null; + } + + public String getNamespace() throws InvalidRegistryObjectException { + return null; + } + + public String getNamespaceIdentifier() throws InvalidRegistryObjectException { + return null; + } + + public Object getParent() throws InvalidRegistryObjectException { + return null; + } + + public String getValue() throws InvalidRegistryObjectException { + return null; + } + + public String getValueAsIs() throws InvalidRegistryObjectException { + return null; + } + + public boolean isValid() { + return false; + } + + } + + /** + * A mock extension used to supply a valid namespace identifier + *

+ * This class is not intended to be used outside of the validation framework. + *

+ * @see XmlConfig#load(URL) + */ + private static class DummyExtension implements IExtension { + + String namespaceIndentifier = null; + + public DummyExtension(String namespaceIdentifier) { + this.namespaceIndentifier = namespaceIdentifier; + } + + public String getNamespaceIdentifier() throws InvalidRegistryObjectException { + return namespaceIndentifier; + } + + // Unused Methods + + public IConfigurationElement[] getConfigurationElements() throws InvalidRegistryObjectException { + return null; + } + + public IContributor getContributor() throws InvalidRegistryObjectException { + return null; + } + + public IPluginDescriptor getDeclaringPluginDescriptor() throws InvalidRegistryObjectException { + return null; + } + + public String getExtensionPointUniqueIdentifier() throws InvalidRegistryObjectException { + return null; + } + + public String getLabel() throws InvalidRegistryObjectException { + return null; + } + + public String getNamespace() throws InvalidRegistryObjectException { + return null; + } + + public String getSimpleIdentifier() throws InvalidRegistryObjectException { + return null; + } + + public String getUniqueIdentifier() throws InvalidRegistryObjectException { + return null; + } + + public boolean isValid() { + return false; + } + } }