Adam - Like it. Please comments inline.../Thomas
________________________________

From: Adam Murdoch [mailto:[email protected]] 
Sent: Tuesday, March 08, 2011 2:45 AM
To: [email protected]
Subject: Re: [gradle-dev] RE: Gradle's OSGi plugin




On 04/03/2011, at 11:44 PM, Glaeser, Thomas wrote:


        Niclas - Well. The current OSGi plugin is very simple as it
basically only invokes BND to generate the manifest. As of now, the OSGi
plugin itself does not apply the Java plugin. Let's discuss the
following cases
        
        (1) Apply the OSGi plugin together with the Java Plugin
        (2) Apply the OSGi plugin together with the War Plugin
        
        I guess over here we are in a similar situation like you guys
from Qi4j. We have mostly non OSGi-aware applications but moving more
and more into the direction of OSGi. More and more projects we build
need to run in the two different execution environments. 
        
        Right now, case (1) works reasonable well for simple scenarios
where you don't want to embed any dependencies into your bundle and
don't work with fragments. Here we use an extension to the Gradle OSGi
plugin in order to handle embedded jar files.
        
        I have not invested anything in case (2), however would expect
some surprises.
        
        But what should happen is that with case (2) all your runtime
dependencies will be embedded into the bundle under path WEB-INF/lib
while with case (1) it is expected that your runtime dependencies are
provided as part of the application classpath.
        
        So we already have different behavior here when it comes to
runtime dependencies. This is not good, one would expect the same
handling of dependencies no matter what kind of OSGi bundle gets build.
The reason for this is, that the current OSGi plugin does not care about
dependency configurations at all. This has to change as an OSGi
classpath will be different from a plain old Java classpath.
        
        Now I would argue that an OSGi bundle is very similar to a WAR.
I believe that Peter Kriens documentation about WAB confirms this. Both
are container applications.
        



I agree that we should think of OSGi bundles as similar to WARs. We
could also think of a jar published to a repository in a similar way,
where the ivy.xml/pom.xml descriptor provides meta-data about what must
be provided by the execution container at runtime.


More generally, we might do something like:


* A Gradle project bundles bytecode for the JVM into a number of
different archives. These archives might be a JAR, WAR, OSGi bundle, and
so on, or some combination of these. We might also model GWT/Android/GAE
applications and Gradle plugins, and so on, the same way.


* At build time, a subset of runtime dependencies for the project must
be embedded in the archive. For example, a WAR generally embeds (all
runtime dependencies - those dependencies provided by the web
container). A 'fat' JAR might embed all runtime dependencies. An OSGi
bundle might embed (all runtime dependencies - those provided by the
container itself - those provided as services in other bundles).
 
<TG>I'm confused. Why must the container provided dependencies be
embedded in the archive? E.g. in the case of an WAR everything from the
providedRuntime configuration will not get embedded into the archive. I
also would rather say that runtime dependencies for the project might be
embedded in the archive.</TG>


* At build time, some meta-data is generated to describe to the target
container which runtime dependencies the archive now requires. This
meta-data is included either in the archive, in the case of an OSGi
bundle, or published with the archive, such as in the case of a JAR +
pom.xml.


The key point here is that it is the target environment that determines
which dependencies will be provided at runtime, and those which need to
be embedded. That is, there is no single 'provided' classpath. Instead,
there are potentially several.
 
<TG>I like that. This is very much true. No matter what target
environment gets shipped with the product, for testing the different
projects will require a subset of the provided classpath only.</TG>


I think it would be useful to model the target environments/containers,
so that:


* A target environment can define which dependencies will be provided by
that environment.


* A target environment can contribute to the compile classpath for the
project. For example, we might have a 'generic servlet 3.0 container',
which adds the appropriate servlet api, and so on to the compile
classpath. Or we might have a 'jetty 7 container' which adds the
jetty-specific api to the compile classpath. Similarly for 'generic OSGi
container' and 'equinox OSGi container'


* A target environment can influence generation of the archive. For
example, we might have a 'tomcat 7.0 container' which adds, say, some
tomcat-specific descriptor to the WAR.


<TG>Agreed.</TG> 


        
        This would have some consequences for the new OSGi plugin
        - It would need to apply the Java plugin internally the same way
the WAR plugin does
        - The meaning of the provided* configurations are the same as
with the WAR plugin
        (- There would be additional supply* configurations; that's
something the WAR doesn't have)

 <TG>I like the following design. Still have couple questions.</TG> 


I would do this slightly differently:


1. Split the Java plugin into 3 pieces:
  * A 'java' plugin which knows how to compile Java source into bytecode
and how to run unit tests for it.
  * A 'jar-library' plugin which knows how to build and publish a plain
jar.
  * A 'java-runtime' base plugin which provides the minimal pieces to
define the runtime meta-data for the project: the set of classes, and
the set of runtime dependencies.


The 'jar-library' plugin would:
  * Implicitly apply the 'java-runtime' plugin.
  * Add the jar task.
  * Configure the publications so that the jar is published, along with
the runtime dependencies in the dependency descriptor.


2. Change the 'osgi' plugin to:
  * Implicitly apply the 'java-runtime' plugin. It would not apply the
'java' plugin.
  * Add an osgiBundle task. It would not modify the jar task. It would
create a separate bundle task.
  * Configure the publications so that the bundle is published.
  * Introduce the concept of target OSGi container.
 
 <TG>We still need to compile the Java sources into byte code and run
unit tests. I guess we either apply the 'java', 'groovy', or 'scala'
plugin in addition, right?</TG> 

3. Change the 'war' plugin to:
  * Implicitly apply the 'java-runtime' plugin. It would not apply the
'java' plugin.
  * Add the war task.
  * Configure the publications so that the war is published.
  * Introduce the concept of target web container.
  * We would remove the provided* configurations.
 
 <TG>We still need to compile the Java sources into byte code and run
unit tests. I guess we either apply the 'java', 'groovy', or 'scala'
plugin in addition, right?</TG> 

4. Change the 'application' plugin to:
  * Implicitly apply the 'java-runtime' plugin. It would not apply the
'java' plugin.
  * Add the distZip and install tasks.
  * Configure the publications so that the application zip is published.
 
 <TG>We still need to compile the Java sources into byte code and run
unit tests. I guess we either apply the 'java', 'groovy', or 'scala'
plugin in addition, right?</TG> 

  This approach allows:
  * Creating any combination of stand-alone jar, OSGi bundle and WAR.
  * Multiple jars, bundles or WARS, each targeting a different
environment.
  * A project which contains no Java source code. For example, a parent
project which aggregates the classes of its children. Or a
Groovy/Scala/Clojure project.


 <TG>To me this seems to be a very good design. However it introduces a
couple breaking changes. How do we want to proceed?</TG> 

        
        When migration your project from POJO to OSGi the following
would need to be done
        - Apply the OSGi plugin +instead+ of the Java plugin
        - Replace most, if not all, of your compile/runtime dependencies
by providedCompile/providedRuntime
        
        I would consider this a minor migration effort. One has to
divide the project dependencies into three buckets anyway when moving to
OSGi. When running with Equinox, the feature descriptor would list
additional dependencies (supply*) that need to be injected into the
execution environment in order to run your bundle.
        
        Everything build with the new OSGi plugin could be executed in
an OSGi container +or+ as normal Java application, the only difference
is how you would create the classpath from the three sets of
configurations. Does this make sense?
        
        /Thomas
        --

Adam Murdoch
Gradle Developer
http://www.gradle.org
Co-Founder and VP of Engineering, Gradleware Inc. - Gradle Training,
Support, Consulting
http://www.gradleware.com

Reply via email to