Bug 295106 - IJavaModel should register itself with OSGI as a service
Summary: IJavaModel should register itself with OSGI as a service
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.6   Edit
Hardware: PC Windows XP
: P3 enhancement (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-11-13 14:16 EST by Min Idzelis CLA
Modified: 2009-11-16 13:11 EST (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Min Idzelis CLA 2009-11-13 14:16:49 EST
User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5
Build Identifier: 

When the IJavaModel is created, it should register itself with OSGI as a service. This will allow an easy way to lookup the IJavaModel and allow interoperability with declarative services. 

Reproducible: Always
Comment 1 Olivier Thomann CLA 2009-11-13 15:40:15 EST
This is an enhancement.
What do you want to do with the java model?
Comment 2 Min Idzelis CLA 2009-11-13 15:58:16 EST
I would like to add a Java element change listener using JavaCore#addElementChangedListener(). 

I am using declarative services, so my plugin is started/activated before the JDT core plugin is activated. Just by referencing JavaCore as an import causes the class to be loaded, and then the JDT core plugin is activated and started - unnecessarily. Really, I just want to add my listener whenever the JavaCore starts, but not cause the plugin to be activated. 

This is doubly bad because I'm activated before the ResourcesPlugin is fully initialized. Actually - the ResourcesPlugin is causing me to be activated. When it registered the IWorkspace with OSGI it triggered me to start - but the start() method is not done yet. Since JavaCore uses ResourcesPlugin classes that may not have been loaded yet, deadlock would result. Except that OSGI works around this by allowing class loads to work without a fully activated plugin after a 5second delay. This causes very slow startup - but it does eventually finish. The message that is printed is similar to: 

!ENTRY org.eclipse.osgi 2 0 2009-11-13 11:35:25.843
!MESSAGE While loading class "org.eclipse.core.resources.IContainer", thread
"Thread[main,6,main]" timed out waiting (5000ms) for thread "Thread[Component
Resolve Thread,5,main]" to finish starting bundle
"org.eclipse.core.resources_3.6.0.v20091019 [1160]". To avoid deadlock, thread
"Thread[main,6,main]" is proceeding but "org.eclipse.core.resources.IContainer"
may not be fully initialized.
!STACK 0
org.osgi.framework.BundleException: State change in progress for bundle
"reference:file:/D:/dev/targets2/RAD76-20091103_0403/eclipse/plugins/org.eclipse.core.resources_3.6.0.v20091019.jar"
by thread "Component Resolve Thread".


I have a poor workaround. What I do is install a bundle listener that listens for when the JavaCore plugin is activated, and then I call the JavaCore method I need. Unfortunately, the class that is being activated can not have any references in any imports to any JDT classes (since resolving/loading a class will resolve/load all its imports). So I have to create a proxy that uses reflection to invoke JDT methods. 

In OSGI services, you can specify multiple dependencies. Right now I can only specify IWorkspace. Ideally, I would specify IWorkspace and IJavaModel. Then, my service will only be activated when both those services have been registered. 


=== my workaround ===
updater = new JDTListenerProxy();
// workaround, until we get a proper osgi service for IJavaModel
// don't activate the jdt core plugin!
final Bundle b = Platform.getBundle("org.eclipse.jdt.core"); //$NON-NLS-1$
if (b != null) {
  final BundleContext c = b.getBundleContext();
  if (c != null) {
    if (b.getState() != Bundle.ACTIVE) {
      c.addBundleListener(new BundleListener() {

	public void bundleChanged(BundleEvent event) {
	  if (b.equals(event.getBundle()) && event.getType() == BundleEvent.STARTED) {
	    updater.start();
	    c.removeBundleListener(this);
	   }
				}
	});
    }
  else {
    updater.start();
  }
  }
}