Jump to content
  • JasperReports does not work in an OSGi container with Groovy provided by another bundle


    apupier
    Assigned User teodord
    CategoryBug report
    PriorityNormal
    ReproducibilityAlways
    ResolutionFixed
    SeverityBlock
    StatusClosed

    JasperReports does not work in an OSGi container with Groovy provided by another bundle

     

    this is related to this topic: http://jasperforge.org/plugins/espforum/view.php?group_id=102&forumid=103&topicid=71955

     

    In JRClassLoader, Thread.currentThread().getContextClassLoader() is used. This is bad.

    Simply use getClass().getClassLoader() or ask for a classloader as parameter

     

     

    Nota, if no bundle from your dependence provides groovy implementation and that groovy-all is just aside your jasperReports, it works. But it leaks classes in the Perm Gen.


    Attachments: osgi-patch.zip

    User Feedback

    Recommended Comments

    Hi,

     

    I have looked deeper into the patch you sent and there is something I don't understand.

     

    We already had an IF block in our method which used the JRClassLoader.class.getClassLoader() approach in case the Groovy class was not found in the current thread context class loader.

     

    Did you see it? Why do you think it does not work in your case?

     

    Thanks,

    Teodor

    Link to comment
    Share on other sites

    Hi,

     

    I uploaded the stacktrace that I obtain when I'm trying to fill a JasperReports using OSGi dependency.

     

    In fact, I think that the contextClassLoader is not the right one.

    The groovy classes are loaded in the contextClassLoader of org.codehaus.groovy but it tries to compile Groovy expression that contains JasperReports classes. JasperReports classes are not in the context classloader of org.codehaus.groovy .

     

    Do you see what I mean?

     

    Some thoughts on the solution:

    - perhaps we can add some libraries to the classpath of groovy when we ask it to compile.

    - or based on what antlr 2.7.x seems to do, use a system property(ANTLR_USE_DIRECT_CLASS_LOADING) to ask if we want to use context classloader or not. (see antlr.Utils)

     

     

    Link to comment
    Share on other sites

    Hi,

     

    I assume the stacktrace is from when you run with Groovy as OSGi bundle and the unmodified JR (that uses current thread context class loader).

    If so, I think what you are saying is that although Groovy is found by this context class loader, it is not working properly as this particular Groovy does not see JR classes back, hence the Groovy script compilation error.

     

    Can you confirm this?

     

    Thanks,

    Teodor

    Link to comment
    Share on other sites

    Hi,

     

    We have made some manifest file modifications to include some OSGi bundle information. Can you get the latest from SVN, build the JAR and let us know if it works better for you?

     

    (That is, without the need to modify JR code)

     

    Thanks,

    Teodor

    Link to comment
    Share on other sites

    Hi,

     

    the MANIFEST.MF generated is not OSGi valid.

     

    I don't know exactly the specification but I upload an example that is valid.

    (It is related to the order of the attribute)

     

    Regards,

    Aurelien

    Link to comment
    Share on other sites

    HUm, there is no require-bundle or import-package... It doesn't work.

     

    Or do you want that I try just to replac the jasperreports lib in my bundle? (and so not use yjaspeereports as an osgi bundle)

    But in this case I'm not sure that it will take care of the import-package inside the lib.

    BTW, I tried like that, I have exactly the same issue from the beginning.

     

    Provides an osgi bundle of jasperreports would be the best to do but I think that you would need to remove this 'really bad practice in OSGi world' to use getContextClassloader()

    Link to comment
    Share on other sites

    This is very strange.

    I have the same SVN version on my machine, and when I run

    >ant clean jar

    (not >mvn clean jar)

    I end up with jasperreports-4.0.1.jar in /dist, which has the attached META-INF/MANIFEST.MF file inside it.

     

    Can you double check this please? Do you have the /src/META-INF/METAINF.MF in the soure tree of the project?

    If you don't have it, that would explain why you don't have in the JAR neither.

     

    Thank you,

    Teodor

    Link to comment
    Share on other sites

    hum, yes I was using ant clean jar (I mistype in the previous commentary)

     

    I suppose that you mistype also for /src/META-INF/METAINF.MF in the source tree and want to say /src/META-INF/MANIFEST.MF

    so I have the MANIFEST.MF. It contains only export package for all net.sf.jaspeerreports.* and import package :

    groovyjarjarasm.asm;resolution:=optional;version="1.7.5",

    org.codehaus.groovy.ast;resolution:=optional;version="1.7.5",

    org.codehaus.groovy.ast.control;resolution:=optional;version="1.7.5"

     

    I upload the jar that is generated to the bug

    EDIT: jar is too big, I will upload only the generated MANIFEST.MF

     

     

    Link to comment
    Share on other sites

    Thank you for your patience with this.

     

    I have updated the META-INF/MANIFEST.MF and the build.xml so that we better control order of lines.

     

    I was hoping that deploying both Groovy and JR as OSGi bundles in your environment would now result in these two libraries seeing each other.

     

    We would like to make the exact same tests you are doing, but I'm not sure which is the minimum OSGi infrastructure to test this.

     

    I know we can try playing with Eclipse plugins, but I was thinking that maybe we should try something much more simple such a basic OSGi container like Felix.

     

    The idea is to reproduce your problem in a very simple environment that is easy to test and hopefully easier to fix.

     

    What do you think?

     

    Thanks,

    Teodor

    Link to comment
    Share on other sites

    You're welcome :)

     

    In order to have a working JR OSGi bundle, you need to add all the package needed in the list of import-package of the MANIFEST and/or embed the lib that doesn't provide an OSGi bundle and add them in MANIFEST to Bundle-Classpath.

     

    I think that testing it on Equinox will be better (no need of org.eclipse.core.runtime).

     

    To reproduce the issue, tell me if you have specific question I will try to help you.

    Link to comment
    Share on other sites

    Hi,

     

    I have modified the MANIFEST.MF file of the JR JAR to have

     

    DynamicImport-Package: *

     

    just like Groovy itself has.

     

    Then, I tried to simulate a real-world OSGi environment using a JR sample.

    When the JR JAR is supposed to be deployed as an OSGi bundle, it is expected that some, or all, of its dependencies be available as OSGi bundles as well.

    In order to simulate that, I have created a special OSGi bundle containing some minimal JR dependency JARs and I called it jrdepend.jar.

    The Groovy JAR is as well loaded as a separate OSGi bundle of its own.

    Then, I created yet another OSGi bundle to test a Groovy report by compiling it and filling it using an activator in this bundle. This testing bundle called testosgi.jar makes use of the JR API loaded from OSGi.

     

    I would like you to make a similar test and let me know what you think is wrong with it.

     

    I have attached an osgi.zip file that you should extract in the /demo/samples folder of the latest version of the JR project taken from SVN.

     

    You then compile the JR JAR using >ant clean jar from project root.

    Compile the sample bundles using >ant clean javac jrdepend testosgi from the /demo/samples/osgi folder of the project.

    Launch the Equinox container by running equinox.sh or equinox.bat, depending on your system.

     

    When inside the equinox console, install and activate the bundles similar to the way I did it in the equinox.log file I have attached.

     

    After you activate the testosgi bundle, you will see it has successfuly compiled and filled the Groovy report, the resulting files being placed in the /demo/samples/osgi/reports folder, besides the source JRXML.

     

    Let me know how it goes for you.

     

    Thanks,

    Teodor

    Link to comment
    Share on other sites

    Hi,

     

    I tried it :)

    It works with your sample but I reproduce the issue with my reports.

    I don't know in which way they are different.

    I upload the .jrxml and the .jasper.

    I let you update the test.osgi to use these files. I recommend you to only try to compile as they are subreports and see in .jrxml what can be the cause.

     

    Now the error seems to be on jfreechart:

    org.osgi.framework.BundleException: Exception in testosgi.Activator.start() of bundle testosgi.

    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:806)

    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:755)

    at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:352)

    at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:280)

    at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:272)

    at org.eclipse.osgi.framework.internal.core.FrameworkCommandProvider._start(FrameworkCommandProvider.jav

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

    at java.lang.reflect.Method.invoke(Unknown Source)

    at org.eclipse.osgi.framework.internal.core.FrameworkCommandInterpreter.execute(FrameworkCommandInterpre

    at org.eclipse.osgi.framework.internal.core.FrameworkConsole.docommand(FrameworkConsole.java:303)

    at org.eclipse.osgi.framework.internal.core.FrameworkConsole.console(FrameworkConsole.java:288)

    at org.eclipse.osgi.framework.internal.core.FrameworkConsole.run(FrameworkConsole.java:224)

    at java.lang.Thread.run(Unknown Source)

    Caused by: java.lang.NoClassDefFoundError: Lorg/jfree/chart/plot/PlotOrientation;

    at java.lang.Class.getDeclaredFields0(Native Method)

    at java.lang.Class.privateGetDeclaredFields(Unknown Source)

    at java.lang.Class.getDeclaredField(Unknown Source)

    at java.io.ObjectStreamClass.getDeclaredSUID(Unknown Source)

    at java.io.ObjectStreamClass.access$700(Unknown Source)

    at java.io.ObjectStreamClass$2.run(Unknown Source)

    at java.security.AccessController.doPrivileged(Native Method)

    at java.io.ObjectStreamClass.(Unknown Source)

    at java.io.ObjectStreamClass.lookup(Unknown Source)

    at java.io.ObjectStreamClass.initNonProxy(Unknown Source)

    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)

    at java.io.ObjectInputStream.readClassDesc(Unknown Source)

    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)

    at java.io.ObjectInputStream.readClassDesc(Unknown Source)

    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)

    at java.io.ObjectInputStream.readObject0(Unknown Source)

    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)

    at java.io.ObjectInputStream.defaultReadObject(Unknown Source)

    at net.sf.jasperreports.engine.base.JRBaseChart.readObject(JRBaseChart.java:1384)

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

    at java.lang.reflect.Method.invoke(Unknown Source)

    at java.io.ObjectStreamClass.invokeReadObject(Unknown Source)

    at java.io.ObjectInputStream.readSerialData(Unknown Source)

    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)

    at java.io.ObjectInputStream.readObject0(Unknown Source)

    at java.io.ObjectInputStream.readObject(Unknown Source)

    at java.util.ArrayList.readObject(Unknown Source)

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

    at java.lang.reflect.Method.invoke(Unknown Source)

    at java.io.ObjectStreamClass.invokeReadObject(Unknown Source)

    at java.io.ObjectInputStream.readSerialData(Unknown Source)

    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)

    at java.io.ObjectInputStream.readObject0(Unknown Source)

    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)

    at java.io.ObjectInputStream.readSerialData(Unknown Source)

    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)

    at java.io.ObjectInputStream.readObject0(Unknown Source)

    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)

    at java.io.ObjectInputStream.defaultReadObject(Unknown Source)

    at net.sf.jasperreports.engine.base.JRBaseReport.readObject(JRBaseReport.java:823)

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

    at java.lang.reflect.Method.invoke(Unknown Source)

    at java.io.ObjectStreamClass.invokeReadObject(Unknown Source)

    at java.io.ObjectInputStream.readSerialData(Unknown Source)

    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)

    at java.io.ObjectInputStream.readObject0(Unknown Source)

    at java.io.ObjectInputStream.readObject(Unknown Source)

    at net.sf.jasperreports.engine.util.JRLoader.loadObject(JRLoader.java:97)

    at net.sf.jasperreports.engine.JasperFillManager.fillReportToFile(JasperFillManager.java:119)

    at testosgi.Activator.start(Activator.java:20)

    at org.eclipse.osgi.framework.internal.core.BundleContextImpl$1.run(BundleContextImpl.java:783)

    at java.security.AccessController.doPrivileged(Native Method)

    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:774)

    ... 14 more

    Caused by: java.lang.ClassNotFoundException: org.jfree.chart.plot.PlotOrientation

    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:494)

    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:410)

    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:398)

    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:105)

    at java.lang.ClassLoader.loadClass(Unknown Source)

    ... 73 more

     

     

     

    NOTA: DynamicImport-package is often not a good practice: http://blog-o-lok.blogspot.com/2008/01/osgi-and-dynamicimport-package.html

    but I don't know well this option so this is just a warn, perhaps need to dig on it ^^

     

     

    Link to comment
    Share on other sites

    Hi,

     

    I took your ProcessReport.jrxml, renamed it to GroovyReport.jrxml and modified it to use language="groovy".

    I have then copied it in the reports folder of my sample and obtained the same error as you, which basically said that JFreeChart is missing from our OSGi environment.

     

    To solve this additional dependency, I have edited the build.xml and the MANIFEST.MF.jrdepend so that JFreeChart and JCommons be part of this OSGi bundle, just like the other JR dependencies were.

    Basically, any new dependency that you might use in your report needs to be made available to OSGi by means of a bundle. This is why I use the jrdepend bundle in my sample.

     

    This also confirms the fact that DynamicImport-Package: * is correct, because in a JR report, you could make calls to any possible Java library. Those could be helper classes of your own or maybe other charting and visualisation packages that we don't know about when we build our JR JAR. So we have to dynamically import everything with a *, because there is no way to know what API's would people use in their report expressions. This is similar to how Groovy does it, because Groovy cannot know what packages and classes people will use in their Groovy scripts, so they have to dynamically import everything.

     

    If you extract the attached osgi-patch.zip on-top of the previous OSGi sample I provided, you could see that now your report compiles successfully.

     

    As far as the JR JAR is concerned, I think what we have now is complete. It is not our responsibility to provide all JR dependencies as part of our JR OSGi bundle. People using JR in an OSGi environment have to make sure the JR dependencies are available when they deploy our "JR JAR file".

     

    If you are looking for a complete JR OSGi bundle that would also contain the JR dependencies, you either go with something like the jrdepend JAR that we have build in the above sample, or you take a look at this JasperReports Eclipse plugin project, which provides a "net.sf.jasperreports" plugin that might fulfill your JR OSGi needs, as it comes with all the JR dependencies inside (including Groovy).

     

    http://jasperforge.org/scm/viewvc.php/trunk/?root=jasperreportseclipseplugin

     

    Note that these plugins are part of the Jaspersoft Studio project.

    http://jasperforge.org/projects/jaspersoftstudio

     

    Thanks,

    Teodor

    Link to comment
    Share on other sites

    Hi,

     

    ok for jfreechart, I thought it was in jrdepend.

     

    I need to test also with og.codehaus.groovy instead of groovy-all because it doesn't have an 'dynamicImport-package: *'

    They should also have an issue.

     

    Regards,

    Link to comment
    Share on other sites

    Hi,

     

    OK, we are going to consider this matter closed for now.

     

    Feel free to reopen the tracker when you'll have time and more feedback on this issue.

     

    Thank you,

    Teodor

    Link to comment
    Share on other sites



    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now

×
×
  • Create New...