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

Create OSGi bundle #32

Closed
mdeinum opened this issue Jul 17, 2012 · 32 comments
Closed

Create OSGi bundle #32

mdeinum opened this issue Jul 17, 2012 · 32 comments

Comments

@mdeinum
Copy link

mdeinum commented Jul 17, 2012

Currently the MANIFEST.MF is pretty empty, would be nice if there could be some headers (imports etc.) be added so that it can be used as an OSGI bundle. This goes for the subprojects as well (spring integration for instance).

@davejoyce
Copy link

I second Martin's comment above. Can I jump in and OSGi-ify the Thymeleaf projects, so that the produced JARs are also valid OSGi bundles?

@danielfernandez
Copy link
Member

Thanks. What would this mean, what changes would be required?

@davejoyce
Copy link

Daniel, basically what that means is that:

  • The current Thymeleaf maven artifact projects would need to be altered:
    • to be packaged as bundle rather than jar
    • to specify dependencies at a package level, including accepted version ranges
  • Or, a 2nd parallel set of new maven artifact projects would need to be created to produce bundle rather than jar packages. An OSGi bundle is just a JAR, but with standardized, well-formed headers in the MANIFEST.MF file

@danielfernandez
Copy link
Member

I understand. Could this modifications to MANIFEST.MF have effect on the way the .jars are being processed in enterprise application servers?

What I am worried about is that adding the OSGI-related headers could harm any users currently using the .jar files in environments which could react to this headers in unwanted ways... this is, I would like to be sure that this would not affect non-OSGI-conscious users in any way...

@davejoyce
Copy link

Daniel:

That's the really nice part! The short answer is no. A plain non-OSGi JVM will treat them as normal JAR manifest headers (ie, ignore them).

Sent from my Verizon Wireless BlackBerry

-----Original Message-----
From: Daniel Fernández notifications@github.com
Date: Thu, 13 Sep 2012 08:23:44
To: thymeleaf/thymeleafthymeleaf@noreply.github.com
Reply-To: thymeleaf/thymeleaf reply@reply.github.com
Cc: Dave Joycedavid.joyce13@gmail.com
Subject: Re: [thymeleaf] Create OSGi bundle (#32)

I understand. Could this modifications to MANIFEST.MF have effect on the way the .jars are being processed in enterprise application servers?

What I am worried about is that adding the OSGI-related headers could harm any users currently using the .jar files in environments which could react to this headers in unwanted ways... this is, I would like to be sure that this would not affect non-OSGI-conscious users in any way...


Reply to this email directly or view it on GitHub:
#32 (comment)

@mdeinum
Copy link
Author

mdeinum commented Sep 17, 2012

Creating an OSGI bundle shouldn't harm the current users. A lot of frameworks (Spring, Hibernate to name just 2) ship as valid OSGI bundles and work also in normal environments.

@davejoyce
Copy link

I have just forked thymeleaf and thymeleaf-spring3 repos. My plan is to update the POMs to produce jars which are also OSGi bundles. In a standard JVM (JSE / JEE) environment, they will continue to work exactly as they do now.

Daniel - I will submit a pull request when I'm done.

Marten - how would we go about getting the OSGi bundle jars into the SpringSource EBR?

@mdeinum
Copy link
Author

mdeinum commented Sep 18, 2012

Why would you want them in SpringSource EBR? What is wrong with normal maven? The SpringSource EBR is only to be used for jars which are modified by SpringSource to become OSGI bundles (for jars that aren't).

@danielfernandez
Copy link
Member

@davejoyce that's great! thanks.

What about thymeleaf's dependencies that are not OSGi bundles? I don't know what is the normal behaviour here... will they be included inside the bundle anyway but simply not exported?

@davejoyce
Copy link

Marten - nothing is wrong with a normal maven repository. I asked about the EBR, because OSGi bundles are found either via Eclipse.org, SpringSource EBR, or some other OBR.

Daniel - part of my effort will be to identify existing OSGi bundle-ized dependencies. I may create a separate profile within the POMs to handle the potentially differing dependency resolution.

@mdeinum
Copy link
Author

mdeinum commented Sep 18, 2012

In general most (commonly used) jar files found in the normal maven repository are already OSGi bundles (hibernate, spring, apache-common jars, jsf etc.) so no need to have them in another repository (but that is IMHO ofcourse :) ).

@davejoyce
Copy link

@mdeinum good points. I, too, suspect that most (if not all) of the dependencies will already be OSGi bundles. In the event I find a dependency jar that isn't yet an OSGi bundle, I will return to this issue for discussion.

@danielfernandez
Copy link
Member

@davejoyce @mdeinum thymeleaf's dependency tree is quite small. In fact:

Thymeleaf (core): ognl, javassist, slf4j
Thymeleaf-Spring3: thymeleaf (core), several Spring beans, slf4j

As for OGNL and javassist, they are quite specific to Thymeleaf and I'm not sure of the usefulness it could have to import them as OSGi-contained dependencies. I think this dependencies would be safer "inside" the thymeleaf bundle, without being exported at all, if this is possible.

In fact, there's an important point in favour of this: javassist is used to modify the bytecode of an OGNL class at the very moment this class is loaded by the classloader, in order to make OGNL implement some scenarios of the "equals" operation in a way consistent with Spring EL.

If OGNL is loaded from the OSGi container, I don't think trying to modify this class would have desirable effects. If it works, would this modify the behaviour of any libraries/applications using OGNL besides thymeleaf in the same container? I don't know how classloaders work in an OSGi container, but this could be a problem.

As for slf4j, it would probably be a good idea to import it as an OSGi bundle.

@davejoyce
Copy link

@danielfernandez As you may now be aware, the OSGi 4.2 Core Specification states:

Each bundle has a single class loader. That class loader forms a class loading
delegation network with other bundles...

Do I understand correctly that Thymeleaf's dependency upon javassist is specifically internal for the sole purpose of altering an OGNL class at load-time? If that is the case, then yes - a "thymeleaf-only" copy of javassist and ognl would need to be in the same classloader as the thymeleaf bundle itself. This is achieved with the Bundle-ClassPath header in META-INF/MANIFEST.MF. The javassist and ognl classes from those internal JARs would not be exported by the bundle.

Does that sound right?

@danielfernandez
Copy link
Member

Exactly. javassist is specifically used for that. And I agree that neither javassist nor OGNL should be exported.

@davejoyce
Copy link

@danielfernandez I'm going to inline the contents of ognl and javassist JARs, so that the thymeleaf bundle JAR doesn't contain JARs, but only packages of classes.

Additionally, I'm working against the 2.0-master branch; is that right? What branch should I be putting these changes into?

@danielfernandez
Copy link
Member

@davejoyce You should create your pull requests against 2.0-master, you're right.

Also, I have a question about that inlining of classes: does that mean you are planning to include OGNL and javassist inside the standard Thymeleaf binary distribution .jars? and if the answer to that is "yes"... is this the only way to make thymeleaf use its own "instance" of these libraries?

@davejoyce
Copy link

@danielfernandez I'll continue against 2.0-master, then.

Yes, the contents of the javassist and ognl JARs will be incorporated into the Thymeleaf binary distribution JAR. It is not the only way to make Thymeleaf use these classes, but it is the simplest and most straightforward. This approach, will make the content of thymeleaf-x.x.x.jar similar to that of the popular cglib-x.x-nodeps.jar, which contains its own ASM packages.

@danielfernandez
Copy link
Member

@davejoyce given the fact that this would affect everyone not using OSGi, I don't like that option. At least, the packages for these "inlined" classes should be changed in order to avoid collision with other versions of the same .jars in non-OSGi environments. And changing package would mean modifying their sources and almost creating our own distribution of these two libraries...

So unless there is a better way, I think we should go for the creation of OSGi bundles apart from the standard jars.

@davejoyce
Copy link

@danielfernandez That's fine. This will add complexity to the packaging, but the end product will be:

  • standard thymeleaf-x.x.x.jar
  • OSGi bundle thymeleaf-x.x.x-osgi.jar

@danielfernandez
Copy link
Member

@davejoyce Thanks.

Just in order to better document this issue ticket for future reference, let me explain that the problem I try to avoid is:

(in a non-OSGi container)

  1. Thymeleaf is added to the classpath, and it contains an "inlined" version x of javassist (which classes are therefore added to the classpath too).
  2. Other parts of the user's software require version y of javassist, so he/she adds the required javassist .jar to the classpath.

Maven/Gradle dependency management systems cannot solve this version conflict because they don't "see" the classes inlined inside thymeleaf's jars. So many javassist classes will be duplicated at the application classpath, in different versions, and which class is loaded into the classloader will be just a matter of luck / the specific container implementation, leading to severe integration problems.

The usual solution to this in binary distributions which require having no dependencies --for example, JDBC driver jars-- is to rename packages in the "inlined" libraries (javassist and OGNL, in this case), and so make the inlining library (thymeleaf) use the re-packaged versions. Something like "org.thymeleaf.contrib.javassist.*" would be a valid renaming.

But changing the package names of a library is a modification of the source code which, besides being allowed by the library license, means maintaining a separate distribution of the inlined libraries. It is not the end of the world, but it might mean quite a lot of effort and also losing a good part of the advantages of dependency control (like bug fixing).

@mdeinum
Copy link
Author

mdeinum commented Sep 25, 2012

In Spring they do the same for ASM (and as of late also cglib 3) however they automated the process of inining (and renaming) the packages. Maybe take a look at their proces?

@davejoyce
Copy link

@mdeinum Thanks, Marten. I'll look at what the Spring Framework project team is doing for that.

@gfouquet
Copy link

gfouquet commented Oct 4, 2012

Hi,

I work on an OSGi based project into which I introduced some Thymeleaf, so I had to do the osgi wrapping.

If it's of some help, you can find and reuse the wrapper poms I wrote. You will find the one for thymeleaf here and the one for thymeleaf-spring3 here

I came across the javassist issue. It seems it contained osgi metadata at some point, then lost it. I saw it should be fixed in the next release. Maybe it's worth waiting for this fix ?

@marcosjitisoft
Copy link

javaassist 3.17.0-GA seems to have the attributes set correctly in the manifest. For anyone using earlier versions up to 3.16.1 in an OSGI environment, they just simply have to wrap it as they install it or repackage it.

Can we move on the bundling of thyme and thyme-spring3?

Also remember, that we do not have to change the packaging to bundle, we can just add the following the maven-bundle-plugin to generate the manifest, and a configuration to the jar plugin to include it.

<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<supportedProjectTypes>
<supportedProjectType>jar</supportedProjectType>
<supportedProjectType>bundle</supportedProjectType>
<supportedProjectType>war</supportedProjectType>
</supportedProjectTypes>
<instructions>
...
</instructions>
</configuration>
<extensions>true</extensions>
</plugin>
....

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>
${project.build.sourceDirectory}/META-INF/MANIFEST.MF
</manifestFile>
</archive>
</configuration>
</plugin>
....
</plugins>

@marcosjitisoft
Copy link

forked the project gfouquet mentioned and updated to version 2.0.18 here.

I've tested them with a simple spring/osgi/thymeleaf example. However I was unable to get the webjars and resources to work properly using the spring resource annotation. so I modified my web.xml to use a servlet for static files (e.g. org.eclipse.jetty.servlet.DefaultServlet) and added servlet mappings for those directories. I also had to use maven to unpack the webjars and include them in the WAB.

@jegadisan
Copy link

Is there any progress on this issue ? I do not see the OSGI bundles for thymeleaf in the repositories

@ghost ghost assigned danielfernandez Jan 2, 2014
@luoruici
Copy link

@danielfernandez @davejoyce
Thanks for your work/discussion on OSGi bundle of thymeleaf, it's valuable for my work. I'm now using OSGi framework(Equinox) in my springmvc project and trying to use thymeleaf instead of traditional jsp. I have some experience on it:

It is not neccessary to package javassist and ognl jars to thymeleaf distribution

because actually there exists bundle version for them(you can find from ServiceMix repository(http://mvnrepository.com/artifact/org.apache.servicemix.bundles/org.apache.servicemix.bundles.ognl/3.0.6_1), and I think packaging dependencies together is not a good idea, and OSGi user should resolve the dependencies by themselves. If I cannot find the bundle version of a dependency, I will create the bundle by myself via modifying the source code of Bundlor. For example of thymeleaf in OSGi environment, if I put bundle version of ognl and javassist in Equinox, thymeleaf need only to add OSGi MANIFEST.MF info and there is no side-effect to non-OSGi user.

Issues in thymeleaf-spring3

I also use spring mvc integration with thymeleaf. In the process of bundling thymeleaf-spring3, I find that a package called org.springframework.web.servlet.tags.form which is also packaged in spring-webmvc module. I understand that it tries to using non-public class in that package. But in OSGi environments, there will be some issues. For example, class ValueFormatterWrapper in thymeleaf-spring3 tries to access non-public class ValueFormatter in spring-webmvc. Because of the ClassLoader Mechanism, there are two different class loader in these two bundles, and Java only allows package-private access to classes loaded by the same class loader. Two classes in the same package, but loaded by two different class loaders, can’t access each others’ package-private members. If we bundle thymeleaf-spring3 as regular process, there is IllegalStateException.

In order to solve this issue, I'm using Fragment-Host Header now. To be specific OSGi Header looks like:

Fragment-Host: org.springframework.web.servlet; bundle-version="3.1.0.RELEASE"
Export-Package: org.springframework.web.servlet.tags.form;version="3.1.0.RELEASE"

OSGi environment put host bundle and its fragment in same classloader, By loading fragment classes with the host’s class loader, the fragment classes are properly recombined to avoid this issue.

@oliverlietz
Copy link

I've written a Scripting Engine "Apache Sling Scripting Thymeleaf" for Apache Sling (and Adobe CQ/Experience Manager) as OSGi bundle.
It embedds thymeleaf, unbescape and nekohtml as they aren't available as OSGi bundles. One class from Thymeleaf is slightly modified to run on OSGi, but the OGNL issue (#118) is not addressed yet - but it can also be done for OGNL this way as the bundle does not export packages from its embedded dependencies to not harm other bundles.

@ultraq
Copy link
Member

ultraq commented Aug 2, 2014

Closing, see #280

@balazs-zsoldos
Copy link

Thank you for the great explanation. I know that spring stopped supporting OSGi and I think that was a good decision. OSGi based modules need much more simplicity that Spring has. While spring works great in the JEE monolithic world, it does not fit into OSGi modularized logic.

I hope you do not mind that I uploaded the OSGified Thymeleaf jar to maven-central under our groupId (org.everit.osgi.bundles). I will come up soon with helper modules that make it easier to use Thymeleaf in OSGi and hopefully I will be able to come out soon with an article called "Modularized WEB development". I did the same on the persistence layer in the past. I hope that will convince people to use Thymeleaf instead of JSF in their OSGi based projects.

I am very happy to see that you added OSGi MANIFEST headers to unbescape. This means less work for me if I want to support the new releases of Thymeleaf until one day probably the original project will add the MANIFEST headers.

@danielfernandez
Copy link
Member

@balazs-zsoldos of course, we are perfectly happy with anyone producing and distributing OSGi bundles for thymeleaf, thanks so much for the effort!

@oliverlietz oliverlietz mentioned this issue Aug 18, 2017
rwinch pushed a commit to rwinch/thymeleaf that referenced this issue Dec 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants