Community
Participate
Working Groups
In order to provide jsr199 support, I need to define a service which provides our implementation of the jsr199 as a possible java compiler. In order to do that I define a file called javax.tool.JavaCompiler inside the META-INF/services folder. This folder is located in a source folder in order to be copied to the output folder. Inside the package explorer META-INF/services is seen as a non-java resources. In order to make it visible to other plugins (like my test plugin), I need to add it as part of the Export-Package section of the bundle manifest. Export-Package: org.eclipse.jdt.compiler.tool, META-INF.services On the line that contains it, I get an error saying that "Package 'META-INF.services' does not exist in this plug-in". Since I need this line, I'd like it to be error-free. To reproduce the problem, check out the project org.eclipse.jdt.compiler.tool from dev.eclipse.org.
Brian, please take a look
Just to clarify. META-INF is not a valid package name according to the JLS since '-' is not a valid java identifier part. The problem in this case is that the entry inside the Export-Package section is a requirement from OSGI to "export" the services (in the java sense). The services are located in a services folder inside the META-INF folder. So if I want the plugin to export its services when used as a bundle, I need to have this entry in the Export-Package section. From an OSGI point of view, this is not an error even if PDE reports it as is. PDE seems to validate all entries of the Export-Package section using the JLS meaning. This is not a requirement for OSGI. There is no way from my end to fix this issue since the services has to be located inside the META-INF folder in order to be found by the call: java.util.ServiceLoader.load(<Class name>); See the java.util.ServiceLoader class in the JDK 6 javadoc.
I'm not following this. If you export this "package" then someone must be either requiring the containing bundle or importing the package. Which is it? Which classloader is used when doing java.util.ServiceLoader.load(<Class name>)? One of the challenges here is that exporting such packages will form a massive split package in the general case. Worse, the package cannot be versioned effectively. So it is not clear that you will get deterministic behaviour at all. While I am not disputing the PDE issue, it seems that there may be something more fundamental at play here.
adding Tom to the party.
We need Jeff's questions answered from comment 3. In particular we need to know what classloader is used to find the META-INF/services/... resource. If this is the bundle classloader that contains the META-INF/services/... resource then there is no need to export it because the classloader will find the resource in its own bundle.
ServiceLoader is the extension mechanism for java. When a service is being looked up, the serviceloader either use a specified classloader (ServiceLoader.load(Class, ClassLoader)) or uses the famous context classloader. In either case I can't see how the mechanism can work without exporting meta-inf/services since at one point ServiceLoader do a getResources on the classloader.
Here is the doc of ServiceLoader: http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html
the classloader used bears on how the dependencies should/can be set up. It would also be interesting to know how this service mechanism works in more detail. That is, what class is looked up? How does the referer know what service to name? For example, in the OSGi service mechanism you look up by the interface but get an instance of some other class. If the Java services mechanism is just a lookup then you know what interface/class you are looking for. If you had to instantiate it as well then the dependencies get more complex.
Similarly to osgi services, the java serviceloader takes the name of the class for which you want a service. In the present case, we want an instance of the JavaCompiler service, so the actual call being made is: ServiceLoader.load(javax.tool.JavaCompiler) This method returns an iterator on all the services available. Because the convention to register new service implementations is to create a file called <serviceClassName> located in the Meta-INF/services folder, the service loader will use the classloader being passed down (I will refer to it as SL-CL) (the classloader can either be an actual classloader, the system classloader when null is set, or the CCL is nothing is passed down (like in the previous call)) and do a call to getResources. In this case it does getResources("Meta-inf/services/javax.tools.JavaCompiler") on the CCL. The <serviceClassName> file contains the fully qualified name of the classes implementing the service interface. As the client code iterates over the iteration returned from the call, the implementation classes will be loaded from the SL-CL. Here a few problems that I can think of: - if a client bundle of serviceLoader imports meta-inf.service, then it will be able to see service declaration files whose type won't be loadable unless the proper classloader is passed down. Example: A registers a new service and exports meta-inf/services B import meta-inf/services but does *not* depend on A B's call to serviceloader will cause A service declaration file to be found but the loading of it will fail since B classloder (to whom the context finder delegates) does not see the service impl class. To solve that problem, a "God" classloader that can see all the classes would have to be passed while doing the serviceloader lookup. - if a client bundle requires a bundle that exports meta-inf.services, only the services defined in a prereq'ed bundle will be accessible. - if the service loader object is being passed outside the bundle who instantiated it, then the context classloder will be different since our context classloader is the finder which computes the value dynamically. - serviceloaders would have to be hooked in bundle lifecycles to ensure dynamic awareness.
exactly. So the summary is, this is not going to work correctly/reliably even if you could export the META-INF/services package. This sounds like a fine topic for discussion in the OSGi CPEG community. Is there anything that PDE could/should do in the mean time?
I'm using Provide-Package: META-INF.services with buddy classloading in latest Eclipse. Package is exported, service is discovered. But it shouldn't work, since Bundle-ManifestVersion: 2 disallows Provide-Package. Is this an accidental feature ? ;)
At runtime the Provide-Package is simply converted to an Export-Package statement for backwards compatibility. Strictly speaking we could ignore this header if Bundle-ManifestVersion > 1 but it does not violate the specification to recognize headers that are not defined by the specification. At a minimum I would expect PDE to flag these as deprecated if Bundle-ManifestVersion > 1
The provide-package issue will be tracked here: https://bugs.eclipse.org/bugs/show_bug.cgi?id=169373
*** Bug 170409 has been marked as a duplicate of this bug. ***
(In reply to comment #14) > *** Bug 170409 has been marked as a duplicate of this bug. *** > Just wanted to summarize from the dup'd bug, that we encounter this in some xerces bundles. We had META-INF.services on the exported packages list, removed it since PDE said it was an error, but then found problems in some runtime situations (for example, running our code on some 1.4 JRE's did not find the more recent xerces libraries as they do, with META-INF.services included. For us, this was a pretty hard bug to find and track down and is evidence that I was beginning to blindly trust those PDE warnings :)
Given that this problem shows up in bundles from orbit, such as the batik ones, I sure hope this problem gets fixed for 3.3 because I too wasted much time on these problems that aren't problems. What's the outlook for getting this fixed (i.e., getting the PDE not to mark this as an error)?
Brian, can we please make them go away? I suspect the problem here is that we explicitly look for legitimate package fragments. We should let in regular folders too.
Created attachment 66184 [details] patch Wassim, this is the one line fix you mentioned earlier. Can you verify this is ok to release?
*** Bug 157810 has been marked as a duplicate of this bug. ***
Comment on attachment 66184 [details] patch Looks good, Bauman :)
Sorry for not getting to this earlier. Should no longer be a problem after RC1
*** Bug 187600 has been marked as a duplicate of this bug. ***