Community
Participate
Working Groups
With the "model spy" from the e4 tools project I see in my IDE that I have lots of dead and duplicate PartDescriptors entries in my application model. A dead PartDescriptor to me is a PartDescriptors of a part for which the class is not available anymore. This seem to happens if you deinstall a plug-in. A duplicated PartDescriptor can be added by a incorrectly programmed model processor or model add-on. I think the Eclipse IDE should add some "clean-up" code for incorrect model data. As a first step I suggest to write a model add-on which register itself for the application startup completed event and checks if identical part descriptors or dead part descriptors exists. Opinions?
(In reply to Lars Vogel from comment #0) > With the "model spy" from the e4 tools project I see in my IDE that I have > lots of dead and duplicate PartDescriptors entries in my application model. Lars, do you have any steps that show the 'major' issue and allow us to claim victory once done?
(In reply to Dani Megert from comment #1) > (In reply to Lars Vogel from comment #0) > > With the "model spy" from the e4 tools project I see in my IDE that I have > > lots of dead and duplicate PartDescriptors entries in my application model. > > Lars, do you have any steps that show the 'major' issue and allow us to > claim victory once done? 1.) Install the e4 tools, either from its official update site or from http://download.vogella.com/luna/e4tools (p2 update site) 2.) Use Ctrl +3 and open model spy 3.) Review the entries for Part Descriptors 4.) Deinstall a plug-in which contributes a view 5.) Open the model spy again and see that the entries are still part of the application model Work related to Bug 376486 would also reveal broken data in the application model. For example the work in Bug 430988.
I have the BundleSymbolicName and the fully qualified class name. Example: bundleclass://com.example.e4.rcp.todo/com.example.e4.rcp.todo.parts.DynamicPart2 Tom, can you advice what is the best way to check if a bundlesclass defined in the application model is present in the current OSGi runtime?
(In reply to Lars Vogel from comment #3) > I have the BundleSymbolicName and the fully qualified class name. Example: > > bundleclass://com.example.e4.rcp.todo/com.example.e4.rcp.todo.parts. > DynamicPart2 > > Tom, can you advice what is the best way to check if a bundlesclass defined > in the application model is present in the current OSGi runtime? Something like this: import java.util.Collection; import java.util.Collections; import java.util.Map; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.namespace.HostNamespace; import org.osgi.framework.namespace.PackageNamespace; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; import org.osgi.framework.wiring.BundleWiring; import org.osgi.framework.wiring.FrameworkWiring; import org.osgi.resource.Requirement; import org.osgi.resource.Resource; ... public BundleCapability findPackage(final String packageName, String bundleSymbolicName, BundleContext bundleContext) { Requirement req = new Requirement() { @Override public Resource getResource() { // no resource return null; } @Override public String getNamespace() { return PackageNamespace.PACKAGE_NAMESPACE; } @Override public Map<String, String> getDirectives() { return Collections.singletonMap( PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE, "(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + packageName + ")"); } @Override public Map<String, Object> getAttributes() { return Collections.emptyMap(); } }; Collection<BundleCapability> packages = bundleContext.getBundle(Constants.SYSTEM_BUNDLE_LOCATION).adapt(FrameworkWiring.class).findProviders(req); for (BundleCapability pkg : packages) { if (bundleSymbolicName.equals(pkg.getRevision().getSymbolicName())) { return pkg; } } return null; } public Class<?> findClass(String className, BundleCapability pkg) { BundleRevision revision = pkg.getRevision(); BundleWiring wiring = revision.getWiring(); if (wiring == null) { return null; } if ((revision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) { // fragment case; need to get the host wiring wiring = wiring.getRequiredWires(HostNamespace.HOST_NAMESPACE).get(0).getProviderWiring(); } try { return wiring.getClassLoader().loadClass(className); } catch (ClassNotFoundException e) { return null; } }
Created attachment 247791 [details] Screenshot We may also want to find model elements in the current UI which cannot get instantiated anymore. See attached screenshot.
(In reply to Lars Vogel from comment #5) > We may also want to find model elements in the current UI which cannot get > instantiated anymore. See attached screenshot. From a discussion in platform.ui we should not handle this case in this bug. This bug should focus on bogus Part Descriptor data.
Bug 405296 and dependencies show other problems with things that stay in the model for too long.
(In reply to Thomas Watson from comment #4) > (In reply to Lars Vogel from comment #3) > > I have the BundleSymbolicName and the fully qualified class name. Example: > > > > bundleclass://com.example.e4.rcp.todo/com.example.e4.rcp.todo.parts. > > DynamicPart2 > > > > Tom, can you advice what is the best way to check if a bundlesclass defined > > in the application model is present in the current OSGi runtime? > > Something like this: > > import java.util.Collection; > import java.util.Collections; > import java.util.Map; > > import org.osgi.framework.BundleActivator; > import org.osgi.framework.BundleContext; > import org.osgi.framework.Constants; > import org.osgi.framework.namespace.HostNamespace; > import org.osgi.framework.namespace.PackageNamespace; > import org.osgi.framework.wiring.BundleCapability; > import org.osgi.framework.wiring.BundleRevision; > import org.osgi.framework.wiring.BundleWiring; > import org.osgi.framework.wiring.FrameworkWiring; > import org.osgi.resource.Requirement; > import org.osgi.resource.Resource; > > ... > > public BundleCapability findPackage(final String packageName, String > bundleSymbolicName, BundleContext bundleContext) { > Requirement req = new Requirement() { > @Override > public Resource getResource() { > // no resource > return null; > } > @Override > public String getNamespace() { > return PackageNamespace.PACKAGE_NAMESPACE; > } > @Override > public Map<String, String> getDirectives() { > return Collections.singletonMap( > PackageNamespace.REQUIREMENT_FILTER_DIRECTIVE, > "(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + packageName + ")"); > } > > @Override > public Map<String, Object> getAttributes() { > return Collections.emptyMap(); > } > }; > Collection<BundleCapability> packages = > > bundleContext.getBundle(Constants.SYSTEM_BUNDLE_LOCATION). > adapt(FrameworkWiring.class).findProviders(req); > for (BundleCapability pkg : packages) { > if (bundleSymbolicName.equals(pkg.getRevision().getSymbolicName())) { > return pkg; > } > } > return null; > } > > public Class<?> findClass(String className, BundleCapability pkg) { > BundleRevision revision = pkg.getRevision(); > BundleWiring wiring = revision.getWiring(); > if (wiring == null) { > return null; > } > if ((revision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) { > // fragment case; need to get the host wiring > wiring = > wiring.getRequiredWires(HostNamespace.HOST_NAMESPACE).get(0). > getProviderWiring(); > } > try { > return wiring.getClassLoader().loadClass(className); > } catch (ClassNotFoundException e) { > return null; > } > } Thank you for this sample code. I just uploaded a ModelCleanupAddon as sample here: https://git.eclipse.org/r/#/c/34735/ Unfortunately I have some inconsistency by using the findPackage(...) method. In most cases it finds the package and I am also able to check, whether the class is available or not. But in some cases the package is not found even though the bundle is available. I tested my Addon by starting with different run configurations, where I added or removed for example spy projects like org.eclipse.e4.tools.css.spy, org.eclipse.e4.tools.event.spy and so on. In case of the org.eclipse.e4.tools.css.spy bundle the package is never found even if the bundle is available and therefore should be found. Other tested bundles worked as expected, which means that the package is found, when the bundle is available and not found, if the bundle is not available. Can anyone image why the package of the org.eclipse.e4.tools.css.spy bundle is never found?
(In reply to Simon Scholz from comment #8) > Can anyone image why the package of the org.eclipse.e4.tools.css.spy bundle > is never found? Is the package you are looking for exported? I just realized that the package providing the function may not actually be API that should be exported. Is that correct?
Assuming theses are internal packages (not exported) you would need to find the wirings based on bundle symbolic name and then use the wiring to find the class: public Collection<BundleWiring> findWirings(final String bundleSymbolicName, BundleContext bundleContext) { Requirement req = new Requirement() { @Override public Resource getResource() { // no resource return null; } @Override public String getNamespace() { return IdentityNamespace.IDENTITY_NAMESPACE; } @Override public Map<String, String> getDirectives() { return Collections.singletonMap(IdentityNamespace.REQUIREMENT_FILTER_DIRECTIVE, "(" + IdentityNamespace.IDENTITY_NAMESPACE + "=" + bundleSymbolicName + ")"); } @Override public Map<String, Object> getAttributes() { return Collections.emptyMap(); } }; Collection<BundleCapability> identities = bundleContext.getBundle(Constants.SYSTEM_BUNDLE_LOCATION).adapt(FrameworkWiring.class).findProviders(req); Collection<BundleWiring> result = new ArrayList<>(1); // normally only one for (BundleCapability identity: identities) { BundleRevision revision = identity.getRevision(); BundleWiring wiring = revision.getWiring(); if (wiring != null) { if ((revision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) { // fragment case; need to get the host wiring wiring = wiring.getRequiredWires(HostNamespace.HOST_NAMESPACE).get(0).getProviderWiring(); } result.add(wiring); } } return result; } If you require the contributing bundle to be a singleton then there will only be on wiring in the collection because BundleWiring can only exist for resolved bundles and only one version of a singleton bundle is allowed to be resolved at a time.
(In reply to Thomas Watson from comment #10) > Assuming theses are internal packages (not exported) you would need to find > the wirings based on bundle symbolic name and then use the wiring to find You are right, the package of the css parts are not exported, while the others are exported. I will try the findWirings methods in a minute. Thank you very much for your support Thomas.
Here is my proposal for removing unavailable PartDescriptors: https://git.eclipse.org/r/#/c/34735/ Your findWirings() method works out. Thank you Thomas :)
(In reply to Simon Scholz from comment #12) > Here is my proposal for removing unavailable PartDescriptors: > > https://git.eclipse.org/r/#/c/34735/ > > Your findWirings() method works out. > Thank you Thomas :) Thanks Simon and Thomas for the help and the Gerrit review, I committed a slightly modified version of it with http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=8531da8680d98833ecd96f1a6df6807f05ee6c0a This Model Addon will not affect incorrectly Part Descriptors contributed via the on ViewRegistry class, which evaluates the view extension point and adds these Views to the application model. But it should remove Part Descriptors with invalid classes, these would be for example part descriptors contributed by plug-ins based on model fragment which have been uninstalled. This should allow us to start using the application model in the IDE, e.g. via Bug 405296 for the Show View menu.
(In reply to Lars Vogel from comment #13) This should allow us to start using the application model in > the IDE, e.g. via Bug 405296 for the Show View menu. Sorry wrong bug number, Bug 430988 is the correct one.
(In reply to Lars Vogel from comment #13) > http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/ > ?id=8531da8680d98833ecd96f1a6df6807f05ee6c0a Please include the bug number in the commit comment. This change caused a test failure in N20141104-2000: Wrong bundles loaded: - org.eclipse.ui.ide.application at org.eclipse.jdt.text.tests.PluginsNotLoadedTest.testPluginsNotLoaded(PluginsNotLoadedTest.java:263) The reason is this addition in org.eclipse.ui.ide.application's MANIFEST.MF: Bundle-ActivationPolicy: lazy Why is this necessary? Does the bundle really have to be activated, given that it doesn't even have a Bundle-Activator? If there's a technical reason, then we can adjust the regression test. Otherwise, I think we can save a few cycles here and remove the Bundle-ActivationPolicy again.
.
Thanks Markus for catching this, the lazy flag is not necessary for this scenario. Fixed with http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=145ead594f2240c8d3709251257f14a22fcfbb0f
Removing the dependencies (405296 430988) to avoid lots of emails for affect people. Actually the Lazy Flag is necessary, as otherwise the BundleContext in line 152 is null bundleContext.getBundle(Constants.SYSTEM_BUNDLE_LOCATION) .adapt(FrameworkWiring.class).findProviders(req); I set the flag again with http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=5bfde32f45d74d736b205fb1b2c9fdd45ac65742 Simon, can you please have a look at the failing test?
OK, I've fixed the test with http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/commit/?id=1193b28613355f888e7b361e80bdbbb86a1a7f3c
Thanks Markus. The fix for the test was embarrassing easy.
(In reply to Lars Vogel from comment #21) > Thanks Markus. The fix for the test was embarrassing easy. No problem. It's our test, so it's also our job to look at it and fix it. I just wasn't sure if bundle activation was really necessary, and I didn't want to just update the test without seeing if it can be avoided.