Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annex registry should have standalone mode #1387

Closed
lwrage opened this issue Jul 19, 2018 · 54 comments
Closed

Annex registry should have standalone mode #1387

lwrage opened this issue Jul 19, 2018 · 54 comments

Comments

@lwrage
Copy link
Contributor

@lwrage lwrage commented Jul 19, 2018

Currently the annex registry relies on the eclipse extension mechanism. to run in standalone mode there needs to be a registry that can be configured programmatically. This is similar to what EMF does for standalone operation.
child of #1538

@lwrage
Copy link
Contributor Author

@lwrage lwrage commented Sep 17, 2018

Also, we should add the AADL name of an annex to the registry (or establish the convention that the file extension must match the AADL name).

@lwrage lwrage removed this from the 2.3.6 milestone Oct 4, 2018
@lwrage lwrage assigned AaronGreenhouse and unassigned lwrage Mar 18, 2019
@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Mar 28, 2019

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Mar 28, 2019

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Mar 28, 2019

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Mar 29, 2019

From Lutz:

About the standalone stuff: It's probably best if you try to look into running emf standalone first.

  • Class EcorePlugin reads data from the extension registry into data structures at startup. This is when it's running in eclipse.
  • IIRC, for standalone operation EcorePlugin is not present but the user must write code to fill the data structures. There should be code examples for this.
  • Xtext's standalonesetup methods also do this.
  • What we need to add is stadalone setup for the annex registry and contributed AADL (probably more, we also register analysis methods in ALISA). It may be best to follow the EcorePlugin implementation for reading the registry as it's worked for many years now.
  • Plugin contributed AADL also needs a URI mapping, we do that for tests, but that's for later.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Mar 29, 2019

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Mar 29, 2019

See pages 94 and 126 of the XText book.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Mar 29, 2019

Per Lutz:

As an initial task you could have a program that loads an instance model into a resource set.

  1. That would only use emf and no xtext. References into the instance declarative model wouldn't be resolved.
  2. Then add loading of the referenced declarative files into the same resource set. We have something like that for tests.
  3. Then load declarative and run instantiation.
  4. Next add an annex to the declarative model and make sure it gets parsed. This needs the standalone annex registry.
  5. Then add predeclared properties, which needs the standalone contributions to work.

Please put all the code for your experiment in a git repo. It could be either a new repo or put in in a new subdirectory in the osate2 repo.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Mar 29, 2019

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Mar 29, 2019

Created project StandaloneExperiments in osate2. So far it only exists in the branch 1387_stand_alone_xtext.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 1, 2019

Removed the jar files from the project. Made the project into a plug-in project. Added the org.osate.aadl2 plug-in as a dependency. This in turn depends on the EMF plug-ins, which makes the classpath happy.

Was able to run the main class successfully.

Was also able to use Export > Runnable Jar file to create a jar file and run that from the command line.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 3, 2019

Cannot even load a basic declarative model without the annex stuff blowing up.

Need to fix AnnexRegistry.initialize() to handle the case of Platform.getExtensionRegistry() returning null.

  • find out what exactly happens when a non-existent registry is encountered, and duplicate case.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 5, 2019

Changed AnnexRegistry.initialize from

	protected void initialize(String extensionId) {
		IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
		IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(AnnexPlugin.PLUGIN_ID, extensionId);
		IExtension[] exts = extensionPoint.getExtensions();

		extensions = new HashMap();
		for (int i = 0; i < exts.length; i++) {
			IConfigurationElement[] configElems = exts[i].getConfigurationElements();

			for (int j = 0; j < configElems.length; j++) {
				String annexName = configElems[j].getAttribute(ATT_ANNEXNAME);
				String annexNSURI = configElems[j].getAttribute(ATT_ANNEXNSURI);

				if (extensions.get(annexName) != null) {
					AnnexPlugin.logError("Duplicate extension: " + extensionId + ", annex " + annexName, null);
				} else {
					ParseUtil.setAnnexNS(annexName, annexNSURI);

					extensions.put(annexName.toLowerCase(), createProxy(configElems[j]));
				}
			}
		}
	}

to

	protected void initialize(String extensionId) {
		extensions = new HashMap();

		IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();

		/* If the system is running outside of Eclipse we wont' have an extension registry */
		if (extensionRegistry != null) {
		   ...
		} else {
			/* Running outside of eclipse, just use the default support */
			final Object defaultHandler = getDefault();
			if (defaultHandler != null) {
				extensions.put("*", defaultHandler);
			}
		}

and added

	protected Object getDefault() {
		// By default, there is no default thing to do
		return null;
	}

Implemented getDefault() in AnnexParserRegistry and AnnexUnparserRegistry to return an instance of DefaultAnnexParser and DefaultAnnexUnparser respectively.

This was done based on the fact that the lookup methods in AnnexParserRegistry and AnnexUnparserRegistry look for the * element when the given annex name is not found. The existing code registers a * parser and * unparser in the plugin.xml file.

Can now load and verify a .aadl file without errors.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 5, 2019

In the long term need to replace getDefault with a mechanism that gets annex information in a non-Eclipse-dependent way.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 15, 2019

Okay. two things going on above

  1. There is an exception during process (not sure what it is yet)
  2. The NullPointerException comes from trying to log the exception from #1, but we run into problems because there is no instance of AnnexPlugin.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 15, 2019

The main exception comes from trying to parse a plugin.xml file as a MANIFEST.MF file.

The code tries to take a URL for the former and turn it into a URL for the latter:

				URI pluginLocation = pluginXMLURI.trimSegments(1);
				URI manifestURI = pluginLocation.appendSegments(new String[] { "META-INF", "MANIFEST.MF" });

The problem is that the URI for the plugin.xml file is not being considered as "hierarchical", which means that the call to trim doesn't do anything.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 15, 2019

The main exception comes from trying to parse a plugin.xml file as a MANIFEST.MF file.

Updated the ant script to add the MANIFEST.MF file from the annexsupport plug-in.

(Doesn't fix the above problem, but we still need this.)

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 15, 2019

The main exception comes from trying to parse a plugin.xml file as a MANIFEST.MF file.

The code tries to take a URL for the former and turn it into a URL for the latter:

				URI pluginLocation = pluginXMLURI.trimSegments(1);
				URI manifestURI = pluginLocation.appendSegments(new String[] { "META-INF", "MANIFEST.MF" });

The problem is that the URI for the plugin.xml file is not being considered as "hierarchical", which means that the call to trim doesn't do anything.

Fixed this by changing the two lines of code shown above to

				URI pluginLocation;
				URI manifestURI;
				if (pluginXMLURI.isHierarchical()) {
					pluginLocation = pluginXMLURI.trimSegments(1);
					manifestURI = pluginLocation.appendSegments(new String[] { "META-INF", "MANIFEST.MF" });
				} else {
					// We have to do this through string manipulation
					final String uriString = pluginXMLURI.toString();
					final int loc = uriString.lastIndexOf('/');
					final String pluginLocationString = uriString.substring(0, loc + 1);
					pluginLocation = URI.createURI(pluginLocationString);
					final String manifestURIString = pluginLocationString + "META-INF/MANIFEST.MF";
					manifestURI = URI.createURI(manifestURIString);
				}

Together with the other change of actually including the annexsupport MANIFEST.MF file in the generated .jar file this allows LoadDeclarativeModel to run correctly from a jar file. It is VERY slow. Loads a lot of stuff during execution it seems. Probably a bunch of stuff that is usually initialized when Eclipse itself is first started.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 16, 2019

Added org.osate.xtext.aadl.errormodel to the project requirements so that EMV2 annex extensions are available. This causes a new error to occur:

Exception in thread "main" java.lang.NullPointerException
	at org.osate.annexsupport.AnnexPlugin.createStatus(AnnexPlugin.java:187)
	at org.osate.annexsupport.AnnexPlugin.log(AnnexPlugin.java:166)
	at org.osate.annexsupport.AnnexPlugin.logError(AnnexPlugin.java:148)
	at org.osate.annexsupport.AnnexParserProxy.getParser(AnnexParserProxy.java:99)
	at org.osate.annexsupport.AnnexParserProxy.parseAnnexLibrary(AnnexParserProxy.java:67)
	at org.osate.xtext.aadl2.parsing.AnnexParserAgent.afterModelLinked(AnnexParserAgent.java:162)
	at org.eclipse.xtext.linking.impl.AbstractCleaningLinker.linkModel(AbstractCleaningLinker.java:57)
	at org.eclipse.xtext.resource.XtextResource.doLinking(XtextResource.java:340)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doLinking(LazyLinkingResource.java:121)
	at org.eclipse.xtext.resource.XtextResource.updateInternalState(XtextResource.java:301)
	at org.eclipse.xtext.resource.DerivedStateAwareResource.updateInternalState(DerivedStateAwareResource.java:170)
	at org.eclipse.xtext.resource.XtextResource.updateInternalState(XtextResource.java:290)
	at org.eclipse.xtext.resource.DerivedStateAwareResource.updateInternalState(DerivedStateAwareResource.java:162)
	at org.eclipse.xtext.resource.XtextResource.doLoad(XtextResource.java:180)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doLoad(LazyLinkingResource.java:114)
	at org.eclipse.emf.ecore.resource.impl.ResourceImpl.load(ResourceImpl.java:1563)
	at org.eclipse.emf.ecore.resource.impl.ResourceImpl.load(ResourceImpl.java:1342)
	at org.eclipse.xtext.resource.persistence.StorageAwareResource.load(StorageAwareResource.java:79)
	at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.demandLoad(ResourceSetImpl.java:259)
	at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.demandLoadHelper(ResourceSetImpl.java:274)
	at org.eclipse.xtext.resource.XtextResourceSet.getResource(XtextResourceSet.java:265)
	at org.eclipse.xtext.resource.SynchronizedXtextResourceSet.getResource(SynchronizedXtextResourceSet.java:25)
	at org.osate.standalone.emf.LoadDeclarativeModel.main(LoadDeclarativeModel.java:27)

This exception is misleading because it occurs in a catch clause. A lot of the code tries to use the log method from the plugin object itself to report errors, and this doesn't work because the plugin instance doesn't exist when running headless.

Substituting a Throwable.printStackTrace() instead gets us this:

org.eclipse.core.runtime.CoreException: Contributor "org.osate.xtext.aadl2.errormodel" was unable to instantiate class "org.osate.xtext.aadl2.errormodel.parsing.EMV2AnnexParser".
	at org.eclipse.core.runtime.spi.RegistryStrategy.createExecutableExtension(RegistryStrategy.java:229)
	at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:934)
	at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:246)
	at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:63)
	at org.osate.annexsupport.AnnexParserProxy.getParser(AnnexParserProxy.java:96)
	at org.osate.annexsupport.AnnexParserProxy.parseAnnexLibrary(AnnexParserProxy.java:67)
	at org.osate.xtext.aadl2.parsing.AnnexParserAgent.afterModelLinked(AnnexParserAgent.java:162)
	at org.eclipse.xtext.linking.impl.AbstractCleaningLinker.linkModel(AbstractCleaningLinker.java:57)
	at org.eclipse.xtext.resource.XtextResource.doLinking(XtextResource.java:340)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doLinking(LazyLinkingResource.java:121)
	at org.eclipse.xtext.resource.XtextResource.updateInternalState(XtextResource.java:301)
	at org.eclipse.xtext.resource.DerivedStateAwareResource.updateInternalState(DerivedStateAwareResource.java:170)
	at org.eclipse.xtext.resource.XtextResource.updateInternalState(XtextResource.java:290)
	at org.eclipse.xtext.resource.DerivedStateAwareResource.updateInternalState(DerivedStateAwareResource.java:162)
	at org.eclipse.xtext.resource.XtextResource.doLoad(XtextResource.java:180)
	at org.eclipse.xtext.linking.lazy.LazyLinkingResource.doLoad(LazyLinkingResource.java:114)
	at org.eclipse.emf.ecore.resource.impl.ResourceImpl.load(ResourceImpl.java:1563)
	at org.eclipse.emf.ecore.resource.impl.ResourceImpl.load(ResourceImpl.java:1342)
	at org.eclipse.xtext.resource.persistence.StorageAwareResource.load(StorageAwareResource.java:79)
	at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.demandLoad(ResourceSetImpl.java:259)
	at org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.demandLoadHelper(ResourceSetImpl.java:274)
	at org.eclipse.xtext.resource.XtextResourceSet.getResource(XtextResourceSet.java:265)
	at org.eclipse.xtext.resource.SynchronizedXtextResourceSet.getResource(SynchronizedXtextResourceSet.java:25)
	at org.osate.standalone.emf.LoadDeclarativeModel.main(LoadDeclarativeModel.java:27)
Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
	at java.lang.reflect.Constructor.newInstance(Unknown Source)
	at org.eclipse.core.runtime.spi.RegistryStrategy.createExecutableExtension(RegistryStrategy.java:226)
	... 23 more
Caused by: java.lang.NullPointerException
	at org.osate.xtext.aadl2.errormodel.parsing.EMV2AnnexParser.<init>(EMV2AnnexParser.java:23)
	... 28 more

It's the last line that is interesting. It points us to this:

	public EMV2AnnexParser() {
		Injector injector = IResourceServiceProvider.Registry.INSTANCE
				.getResourceServiceProvider(URI.createFileURI("dummy.emv2")).get(Injector.class);
		injector.injectMembers(this);
	}

Specifically the line with getResourceServiceProvider.

I think the problem here is that even though we use code like this throughtout OSATE, this is probably not the best way to get the injector that we want.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 16, 2019

I think the problem here is that even though we use code like this throughtout OSATE, this is probably not the best way to get the injector that we want.

Ha! Incorrect. This is caused by not properly initializing the EMV2 meta model. Need to add a call to ErrorModelStandaloneSetup.doSetup() to the start of the program:

public final class LoadDeclarativeModel {
	public static void main(String[] args) {
		final Injector injector = new Aadl2StandaloneSetup().createInjectorAndDoEMFRegistration();
		ErrorModelStandaloneSetup.doSetup();

		final XtextResourceSet rs = injector.getInstance(XtextResourceSet.class);
		final Resource[] resources = new Resource[args.length];
		for (int i = 0; i < args.length; i++ ) {
			resources[i] = rs.getResource(URI.createURI(args[i]), true);
		}
...

Once this is done, things work beautifully when running the project from the eclipse IDE. This can load and parse an AADL declarative model thta uses the EMV2 annex and produce EMV2 parse tress in the Annex node. Loading the following source file

package fred2
public
	annex EMV2 {**
		error types
			flintstone: type;
			fred: type extends flintstone;
			wilma: type extends flintstone;
			pebbles: type extends flintstone;
			
			rubble: type;
			barney: type extends rubble;
			betty: type extends rubble;
			bambam: type extends rubble;
		end types;
	**};
end fred2;

yields the following nodes:

org.osate.aadl2.impl.AadlPackageImpl@5496c165 (name: fred2)
org.osate.aadl2.impl.PublicPackageSectionImpl@51a8313b (name: null) (noAnnexes: false, noProperties: false)
org.osate.aadl2.impl.DefaultAnnexLibraryImpl@2a03d65c (name: EMV2) (sourceText: {**
		error types
			flintstone: type;
			fred: type extends flintstone;
			wilma: type extends flintstone;
			pebbles: type extends flintstone;
			
			rubble: type;
			barney: type extends rubble;
			betty: type extends rubble;
			bambam: type extends rubble;
		end types;
	**})
org.osate.xtext.aadl2.errormodel.errorModel.impl.ErrorModelLibraryImpl@7c129ef6 (name: EMV2)
org.osate.xtext.aadl2.errormodel.errorModel.impl.ErrorTypeImpl@96a75da (name: flintstone)
org.osate.xtext.aadl2.errormodel.errorModel.impl.ErrorTypeImpl@61e7bf2f (name: fred)
org.osate.xtext.aadl2.errormodel.errorModel.impl.ErrorTypeImpl@1a28b346 (name: wilma)
org.osate.xtext.aadl2.errormodel.errorModel.impl.ErrorTypeImpl@25e49cb2 (name: pebbles)
org.osate.xtext.aadl2.errormodel.errorModel.impl.ErrorTypeImpl@7f7af971 (name: rubble)
org.osate.xtext.aadl2.errormodel.errorModel.impl.ErrorTypeImpl@23382f76 (name: barney)
org.osate.xtext.aadl2.errormodel.errorModel.impl.ErrorTypeImpl@7c551ad4 (name: betty)
org.osate.xtext.aadl2.errormodel.errorModel.impl.ErrorTypeImpl@7d5508e0 (name: bambam)

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 16, 2019

This works fine when running the example from Eclipse. Need to test with an exported JAR file still.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 16, 2019

Reverted LoadDecarativeModel back to the way it was, and created a new test project LoadDeclarativeModelAndEMV2 that declares a dependency on org.osate.xtext.aadl.errormodel and inits the EMV2 meta model at start up.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 16, 2019

Created executable jar file for the project. Again, it is necessary to create an ant script to create the jar, and then edit it to force the inclusion of the annex-related registry information:

        	<fileset dir="C:/Users/aarong/git/osate2/core" includes="org.osate.annexsupport/plugin.xml" />
        	<fileset dir="C:/Users/aarong/git/osate2/core" includes="org.osate.annexsupport/META-INF/MANIFEST.MF" />
        	<fileset dir="C:/Users/aarong/git/osate2/emv2" includes="org.osate.xtext.aadl2.errormodel/plugin.xml" />
        	<fileset dir="C:/Users/aarong/git/osate2/emv2" includes="org.osate.xtext.aadl2.errormodel/META-INF/MANIFEST.MF" />

You must also update the class path that it uses to include the above files:

                <attribute name="Rsrc-Class-Path" value="./ org.osate.annexsupport/ org.osate.xtext.aadl2.errormodel/ jfxswt.jar ... />

Running this jar file from the PowerShelll works fine. The EMV2 annex is parsed correctly.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 16, 2019

Current status: Things work.

  • You must be sure to init each meta model using the appropriate "StandaloneSetup" class
  • The AnnexRegistry has been updated to init the extension registry if Eclipse is not present.
  • The executable jar file must include the plugin.xml and MANIFEST.MF file for the annexsupport plug-in, and for each plug-in that registers an annex.
  • The project must depend on org.osate.xtext.aadl2 as well as each plug-in that registers an annex.

Problems

  • Startup time is very very slow. Not sure what to do about this.
  • Error handling is broken. Current code wants to report to the logger that belongs to the plugin object, but this instance doesn't exist. So trying to log the error causes a new error to occur.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 16, 2019

  • Error handling is broken. Current code wants to report to the logger that belongs to the plugin object, but this instance doesn't exist. So trying to log the error causes a new error to occur.

This is not easy to deal with. I tired just creating an AnnexPlugin instance at the start of the test code. This doesn't help because there are a bunch of other objects that are not initialized that are used to try and get the logger internally.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 18, 2019

Had a discussion with Lutz today.

Long start-up time for running from the jar file is probably caused by the fact that the jar file is 57 megabytes and full of nested jar files. The process method that I added to scan from the manifest files is probably taking a lot of time digging around in the jar file.

  • See what happens if you run with all the jar files on the classpath individually. (Setting this up is probably annoying, but the ant script that creates the jar file lists them all already, so that is a big help.)
  • Don't use the manifest information at all, but have the program programmatically declare via method calls what annexes it is using and register them directly. This should be fasted route.

Regarding the error handling problem: The process method is only going to be called from stand-alone programs, so it should never use the log method from the plugin. Handle the errors in some other way.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 18, 2019

I changed AnnexRegistry so that process needs to be called explicitly. Groveling through the jar files is definitely what is slowing things down.

Next step is to move this method somewhere else because it is not specific to the annex at all. We need it for the contributed AADL files as well. Should be in a StandAloneUtils class or some such ting.

Also need to fix the erro rhandling still

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 18, 2019

Fixed the error handling. There are three places in the process method that called the AnnexPlugin.log method:

  • 2 were in catch clauses. I chnaged the code to remoce the try-catch and allowed the exception to propogate out of the process method.
  • 1 is in a nested RegistryStrategy object that is passed to the RegistryFactory. I changed process to take a new RegistryLogger object (a new nested static class) that is used by the RegistryStrategy. Create a new parameterless process that just passes a trivial logger that does nothing. Not sure why we would ever care about these messages, but they are available is someone wants them.
	@FunctionalInterface
	public static interface RegistryLogger {
		public void log(IStatus status);
	}

	private final static RegistryLogger NULL_REGISTRY_LOGGER = new RegistryLogger() {
		@Override
		public void log(final IStatus status) {
			// do nothing
		}
	};

	public static void process() throws CoreException, IOException {
		process(NULL_REGISTRY_LOGGER);
	}

	public static synchronized void process(final RegistryLogger registryLogger) throws CoreException, IOException {
		// Ensure processing only happens once and only when not running an Eclipse application.
		//
		if (!initializedAlready && !EMFPlugin.IS_ECLIPSE_RUNNING) {
			initializedAlready = true;

			// If there isn't already a registry...
			//
			IExtensionRegistry registry = RegistryFactory.getRegistry();
			if (registry == null) {
				// Create a new registry.
				//
				final IExtensionRegistry newRegistry = RegistryFactory.createRegistry(new RegistryStrategy(null, null) {
					@Override
					public void log(final IStatus status) {
						registryLogger.log(status);
					}

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 18, 2019

Also update the ANT script to contain a task that executes the demo program expliclity building the classpath from all the items that would normally be included in the comprehenive jar. This is easy to do by copying the jar task into a new java task and doing a little search and replace.

Running the programs this way is much faster, closer in speed to running from inside Eclipse, but with a little bit of ant overhead.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 19, 2019

Added registerProxy method to AnnexRegistry to allow extesnions to be explicitly added. (I realized midway that I'm not actually going to added Proxy objects with them. I will change the name in the next step.)

Added a demo program that uses them to parse the EMV2 annex instead of loading from the project metadata.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 19, 2019

Long start-up time for running from the jar file is probably caused by the fact that the jar file is 57 megabytes and full of nested jar files. The process method that I added to scan from the manifest files is probably taking a lot of time digging around in the jar file.

It's not only the loading of the plugin.xml files. It's the loading of the EMF/Xtext cass files from the StandaloneSetup classes.

Bottom line: the nested jar files are very bad idea.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 19, 2019

Replaced registerProxy with registerExtension, and then added specificregisterXXX methods. This way I can have type-appropriate arguments for the handler objects.

	private final void registerExtension(final String annexName, final Object handler) {
		extensions.put(annexName.toLowerCase(), handler);
	}

	private static void registerExtension(final String extensionId, final String annexName, Object handler) {
		getRegistry(extensionId).registerExtension(annexName, handler);
	}

	public static void registerContentAssist(final String annexName, final AnnexContentAssist extension) {
		registerExtension(ANNEX_CONTENT_ASSIST_EXT_ID, annexName, extension);
	}

	public static void registerHighlighter(final String annexName, final AnnexHighlighter extension) {
		registerExtension(ANNEX_HIGHLIGHTER_EXT_ID, annexName, extension);
	}

	public static void registerInstantiator(final String annexName, final AnnexInstantiator extension) {
		registerExtension(ANNEX_INSTANTIATOR_EXT_ID, annexName, extension);
	}

	public static void registerLinkingService(final String annexName, final AnnexLinkingService extension) {
		registerExtension(ANNEX_LINKINGSERVICE_EXT_ID, annexName, extension);
	}

	public static void registerParser(final String annexName, final AnnexParser extension) {
		registerExtension(ANNEX_PARSER_EXT_ID, annexName, extension);
	}

	public static void registerResolver(final String annexName, final AnnexResolver extension) {
		registerExtension(ANNEX_RESOLVER_EXT_ID, annexName, extension);
	}

	public static void registerTextPositionResolver(final String annexName, final AnnexTextPositionResolver extension) {
		registerExtension(ANNEX_TEXTPOSITIONRESOLVER_EXT_ID, annexName, extension);
	}

	public static void registerUnparser(final String annexName, final AnnexUnparser extension) {
		registerExtension(ANNEX_UNPARSER_EXT_ID, annexName, extension);
	}

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented Apr 29, 2019

Need to create launch configuration files for each demo program.

Also, add readme describing what each demo is and how to run it.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented May 1, 2019

Added AnnexRegistry.registerAnnex() method that register an annex with a single method call. Tolerates null arguments.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented May 3, 2019

Added ReadMe.txt files and .launch configuration files to all the examples programs.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented May 13, 2019

The question now is do we need AnnexRegistry.initializeExtensionRegistry() or can we just use EcorePlugin$ExtensionProcessor.process() as is.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented May 13, 2019

The question now is do we need AnnexRegistry.initializeExtensionRegistry() or can we just use EcorePlugin$ExtensionProcessor.process() as is.

When I replaced initializeExtensionRegistry() in the LoadDeclarativeModelAndEMV2 example, the example worked correctly when run within Eclipse. The EMV2 extension is found, and EMV2 annex models are parsed nad turned into models.

The problem is how to run outside of eclipse. I thought I would just have to add the annexupport and errormodel plugin jars to the classpath and things would work. Not quite.

  • True, without the annexsupport plugin, we get an exception during parsing -- no extensions are found and we have the error in the AnnexRegistry.initialize method described way up above.
  • The errormodel plugin doesn't seem to be doing anything useful though. The EMV2 annex is not parsed, regardless of whether the plugin is on the classpath.

I still think I must be setting up the executable incorrectly.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented May 14, 2019

The question now is do we need AnnexRegistry.initializeExtensionRegistry() or can we just use EcorePlugin$ExtensionProcessor.process() as is.

When I replaced initializeExtensionRegistry() in the LoadDeclarativeModelAndEMV2 example, the example worked correctly when run within Eclipse. The EMV2 extension is found, and EMV2 annex models are parsed nad turned into models.

The problem is how to run outside of eclipse. I thought I would just have to add the annexupport and errormodel plugin jars to the classpath and things would work. Not quite.

  • True, without the annexsupport plugin, we get an exception during parsing -- no extensions are found and we have the error in the AnnexRegistry.initialize method described way up above.
  • The errormodel plugin doesn't seem to be doing anything useful though. The EMV2 annex is not parsed, regardless of whether the plugin is on the classpath.

I still think I must be setting up the executable incorrectly.

Okay, this was dumb. I misspelled the name of the errormodel plugin jar so it didn't work. If I spell it is correctly it works.

java -cp ".\runit.jar;.\org.osate.annexsupport_1.0.0.v20190311-1415.jar;.\org.osate.xt
ext.aadl2.errormodel_1.0.0.v20190217-2022.jar" org.osate.standalone.emf.LoadDeclarativeModelAndEMV2 .\aadl_files\fred2.a
adl

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented May 17, 2019

Summary of the important items here

You must initialized the AADL meta model:

final Injector injector = new Aadl2StandaloneSetup().createInjectorAndDoEMFRegistration();

If you want to use instance models then you must initialized the meta model for that too:

Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("aaxl2", new Aadl2ResourceFactoryImpl());
InstancePackage.eINSTANCE.eClass();

Get the resource set from the Injector obtained from initializing the AADL meta model:

final XtextResourceSet rs = injector.getInstance(XtextResourceSet.class);

Load resources using ResourceSet.getResource() and Resource.load().

It's a good idea to validate the model to make sure it doesn't have errors or cross-reference issues:

IResourceValidator validator = ((XtextResource) resource).getResourceServiceProvider()
		.getResourceValidator();
List<Issue> issues = validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl);
for (Issue issue : issues) {
	System.out.println(issue.getMessage());
}

To actually get have the Annex extension information registered so that they can be parsed/bound/unparsed, etc., there are two options. The information can be read from plugin.xml files in the plug-ins, or the annex can be explicitly registered using an API.

To read the information directly from the plug-ins, you need to call

EcorePlugin.ExtensionProcessor.process(null);

before loading any AADL resources that use annexes. This call can be slow because it looks through all the jar files on the classpath to find all the plugin.xml files and process them. Additionally, you must make sure the plug-in jar file containing the annex you want is on the classpath when you run the program.

Alternatively, you can add the annex using a method call to explicitly register the components necessary to process the annex. The easiest way to do this is to use the AnnexRegistry.registerAnnex() method, e.g.,:

// Add the EMV2 annex handling
AnnexRegistry.registerAnnex("EMV2", new EMV2AnnexParser(), new EMV2AnnexUnparser(),
		new EMV2AnnexLinkingService(), null, null, null, null, null);

There should be one call to registerAnnex for each annex that you need to handle.

The projects standalone programs should still be created as Plug-In Projects and not regular Java projects. This makes handling the dependencies easier.

  • A project that uses the declarative model should depend on the plug-in org.osate.xtext.aadl2.
  • If it also uses the instance model it should additionally depend on org.osate.aadl2.
  • A project that uses annexes must also depend on org.osate.annexsupport as well as each plug-in that handle an annex that it is interested in, e.g., org.osate.xtext.aadl2.errormodel.

@AaronGreenhouse
Copy link
Contributor

@AaronGreenhouse AaronGreenhouse commented May 21, 2019

@lwrage lwrage added this to the 2.5.1 milestone May 21, 2019
@lwrage lwrage closed this in 16f83fa May 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

2 participants