felix-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Neil Bartlett <njbartl...@gmail.com>
Subject Re: Fragment bundles and Bundle-Classpath of host
Date Thu, 15 Mar 2012 13:32:09 GMT
Bnd doesn't do any special processing for fragments, it will still analyse the contents of
the fragment bundle and generate an Import-Package statement. The reason for this is that
Bnd analyses bundles in isolation, and in general there is no way of knowing what packages
might be already present in the host.

Of course in runtime terms, the Import-Package statement of the fragment will be appended
to the Import-Package statement of the host, so the combined host+fragment might end up trying
to import packages that it already contains. On the other hand I would expect this to lead
to OSGi resolution errors rather than CNFEs....

When building fragments it's probably best to use a bang pattern to exclude host packages
from Import-Package, for example:

     Import-Package: org.example.hostpkg, *

Where "org.example.hostpkg" is a package that is known to be contained within the host. Note
the trailing catch-all asterisk in this instruction, since you DO want to include imports
that are not going to be satisfied by the host.

Rgds
Neil



On Thursday, 15 March 2012 at 13:20, Richard S. Hall wrote:

> Well, given your last message I was going to suggest that this was an 
> issue with your imports in your fragment, but it seems that you 
> discovered this below. Yeah, I don't know how bnd supports creating 
> fragments, but you definitely shouldn't have to include what is on the 
> class path of the host bundle, because you get that by default.
> 
> -> richard
> 
> On 3/15/12 05:14 , Christopher BROWN wrote:
> > I've just found a "hack" solution that avoids having to export the
> > "freemarker.template.*" package from the main bundle's bundle
> > classpath.
> > 
> > I tweaked the Import-Package directive in the fragment bundle (the
> > ".bnd" file, to be specific) so that it imports
> > "freemarker.template.*;resolution:=optional" (adding optional
> > resolution). It works, but it just seems like a hack. I'm guessing
> > there should be some way to tell ".bnd" to accept the bundle classpath
> > without requiring that it be duplicated into the fragment. Maybe I'm
> > wrong, maybe it doesn't exist, or maybe it does (and I just don't know
> > where to find documentation for that feature).
> > 
> > I tried:
> > http://www.aqute.biz/Blog/2007-02-19
> > ...but it discussed adding to the bundle-classpath with fragments, not
> > referring to classes on the host's bundle classpath.
> > 
> > Thanks,
> > Christopher
> > 
> > 
> > 
> > On 15 March 2012 09:58, Christopher BROWN<brown@reflexe.fr (mailto:brown@reflexe.fr)>
wrote:
> > > Hello,
> > > 
> > > So, I have the bundle "B" which contains lib/freemarker.jar ("F" for
> > > short) in the Bundle-Classpath, and a fragment for testing "T" which
> > > declares "B" as the fragment host.
> > > 
> > > When I don't have the export directive in the manifest of "B", when I
> > > try to USE (compiling and BND usage is OK) it, I get this output for
> > > my JUnit test runner:
> > > ________________________________________
> > > 
> > > Failed to load "viewer.system.themes.freemarker.TestFM_T001" from
> > > bundle system.themes-freemarker [11]
> > > (java.lang.ClassNotFoundException: *** Class
> > > 'viewer.system.themes.freemarker.TestFM_T001' was not found. Bundle
> > > system.themes-freemarker [11] does not import package
> > > 'viewer.system.themes.freemarker', nor is the package exported by any
> > > other bundle or available from the system class loader. ***).
> > > Failed to load "viewer.system.themes.freemarker.TestFM_T002" from
> > > bundle system.themes-freemarker [11]
> > > (java.lang.ClassNotFoundException: *** Class
> > > 'viewer.system.themes.freemarker.TestFM_T002' was not found. Bundle
> > > system.themes-freemarker [11] does not import package
> > > 'viewer.system.themes.freemarker', nor is the package exported by any
> > > other bundle or available from the system class loader. ***).
> > > Failed to load "viewer.system.themes.freemarker.TestFM_T003" from
> > > bundle system.themes-freemarker [11]
> > > (java.lang.ClassNotFoundException: *** Class
> > > 'viewer.system.themes.freemarker.TestFM_T003' was not found. Bundle
> > > system.themes-freemarker [11] does not import package
> > > 'viewer.system.themes.freemarker', nor is the package exported by any
> > > other bundle or available from the system class loader. ***).
> > > ________________________________________
> > > 
> > > As I said, I use BND (version 0.0.384) -- incidentally, I'm using
> > > Felix 3.2.2 as I'm deferring the upgrade to 4.x until I have time to
> > > get the hang of compiling from source using Java 6 -- and for
> > > information, here's the ".bnd" files".
> > > 
> > > First, for bundle "B" (note the commented-out #Export directive which
> > > I enable to make it work) ; also the Bundle-Classpath.
> > > ________________________________________
> > > 
> > > Bundle-Version: 0.6.0
> > > Bundle-RequiredExecutionEnvironment: JavaSE-1.6
> > > Bundle-Activator: viewer.system.themes.freemarker.FmBundleActivator
> > > Private-Package: viewer.system.themes.freemarker.*
> > > Import-Package:
> > > org.osgi.framework;version="1.5",org.osgi.*,org.slf4j,fr.reflexe.viewer.api.*;version="[0.6,2.0)",javax.el.*;resolution:=optional,javax.servlet.*;resolution:=optional,javax.swing.*;resolution:=optional,javax.xml.*;resolution:=optional,com.sun.org.apache.*;resolution:=optional,org.apache.commons.logging.*;resolution:=optional,org.apache.log.*;resolution:=optional,org.apache.log4j.*;resolution:=optional,org.apache.tools.ant.*;resolution:=optional,org.apache.xml.*;resolution:=optional,org.apache.xpath.*;resolution:=optional,org.dom4j.*;resolution:=optional,org.jaxen.*;resolution:=optional,org.jdom.*;resolution:=optional,org.mozilla.*;resolution:=optional,org.python.*;resolution:=optional,org.slf4j.spi.*;resolution:=optional,org.w3c.dom.*;resolution:=optional,org.xml.*;resolution:=optional,org.zeroturnaround.javarebel.*;resolution:=optional
> > > #Export-Package: freemarker.*;version=2.3.19
> > > Bundle-ClassPath: ., lib/freemarker.jar
> > > Include-Resource: lib=lib
> > > -removeheaders: Include-Resource, TODAY, EXEC_LOG_LEVEL, TEST_LOG_LEVEL
> > > ________________________________________
> > > 
> > > 
> > > Then, for fragment "T" which declares "B" as its host:
> > > ________________________________________
> > > 
> > > Bundle-Version: 0.6.0
> > > Bundle-RequiredExecutionEnvironment: JavaSE-1.6
> > > Private-Package: viewer.system.themes.freemarker.*
> > > Import-Package:
> > > org.osgi.framework;version="1.5",org.osgi.*,org.slf4j,fr.reflexe.viewer.api.*;version="[0.6,2.0)",javax.el.*;resolution:=optional,javax.servlet.*;resolution:=optional,javax.swing.*;resolution:=optional,javax.xml.*;resolution:=optional,com.sun.org.apache.*;resolution:=optional,org.apache.commons.logging.*;resolution:=optional,org.apache.log.*;resolution:=optional,org.apache.log4j.*;resolution:=optional,org.apache.tools.ant.*;resolution:=optional,org.apache.xml.*;resolution:=optional,org.apache.xpath.*;resolution:=optional,org.dom4j.*;resolution:=optional,org.jaxen.*;resolution:=optional,org.jdom.*;resolution:=optional,org.mozilla.*;resolution:=optional,org.python.*;resolution:=optional,org.slf4j.spi.*;resolution:=optional,org.w3c.dom.*;resolution:=optional,org.xml.*;resolution:=optional,org.zeroturnaround.javarebel.*;resolution:=optional,freemarker.template.*,junit.framework,viewer.system.test.*;version="[0.6,2.0)"
> > > -removeheaders: Include-Resource, TODAY, EXEC_LOG_LEVEL, TEST_LOG_LEVEL
> > > Fragment-Host: system.themes-freemarker; bundle-version="0.6.0"
> > > ________________________________________
> > > 
> > > If it's any use, I can provide the resulting MANIFEST.MF files (but
> > > they're a bit big, due to all the packages in freemarker.jar, when I
> > > enable the export directive).
> > > 
> > > If I drop (for the .bnd file for the test fragment) the Import-Package
> > > value "freemarker.template.*", BND chokes with this message:
> > > [bnd] Unresolved references to [freemarker.template] by class(es)
> > > on the Bundle-Classpath[Jar:dot]:
> > > [viewer/system/themes/freemarker/MockStringModel.class]
> > > [bnd] /Users/cbr/dev/build/temp/Viewer/0.6.0/bnd-tmp/themes-freemarker/fragment/system.themes-freemarker-test-fragment.bnd:
> > > bnd failed
> > > 
> > > That's why I added the "import" in the fragment, but I can't see how
> > > to avoid this (in other words, tell BND that it's OK, it'll magically
> > > find the freemarker packages when the fragment is merged with the host
> > > which has all that stuff in private packages available from the bundle
> > > classpath).
> > > 
> > > For completeness, here's the source code for the class that BND
> > > complains about in the above error message:
> > > ________________________________________
> > > 
> > > package viewer.system.themes.freemarker;
> > > 
> > > import java.util.ArrayList;
> > > import java.util.List;
> > > import freemarker.template.TemplateModelException;
> > > import freemarker.template.TemplateScalarModel;
> > > 
> > > public class MockStringModel implements TemplateScalarModel
> > > {
> > > private final String _value;
> > > 
> > > static List<TemplateScalarModel> args(String... args)
> > > {
> > > List<TemplateScalarModel> list = new
> > > ArrayList<TemplateScalarModel>(args.length);
> > > for (String arg : args)
> > > {
> > > list.add(new MockStringModel(arg));
> > > }
> > > return list;
> > > }
> > > 
> > > MockStringModel(String value)
> > > {
> > > assert value != null;
> > > _value = value;
> > > }
> > > 
> > > @Override
> > > public String getAsString() throws TemplateModelException
> > > {
> > > return _value;
> > > }
> > > }
> > > ________________________________________
> > > 
> > > As you can see, the class (from my test fragment bundle) DIRECTLY
> > > refers to classes from FreeMarker in order to create a mock object
> > > required by a test case, specifically:
> > > 
> > > ________________________________________
> > > 
> > > public void test001_PlainFunctionAdapter() throws Exception
> > > {
> > > MockFunction tf = new MockFunction("fn");
> > > MockDataContext td = new MockDataContext();
> > > FunctionAdapter fa = new FunctionAdapter((ITemplateFunction)tf, td);
> > > 
> > > assertEquals(tf.getName(TEMPLATE_SYSTEM_NAME), fa.getName());
> > > assertEquals(0, fa.getUsageCount());
> > > assertEquals("fn( [foo, bar] )", fa.exec(MockStringModel.args("foo", "bar")));
> > > assertEquals(1, fa.getUsageCount());
> > > }
> > > ________________________________________
> > > 
> > > If I drop the use of "MockStringModel" and comment out the direct
> > > references to FreeMarker, it works. I use a similar approach for
> > > other bundles, with bundle classpaths and so on; the problem only
> > > occurs here because of the mock object's direct use of classes on the
> > > bundle classes (I need it here to build callback-style test cases).
> > > 
> > > Thanks,
> > > Christopher
> > > 
> > > 
> > > 
> > > On 14 March 2012 14:06, Richard S. Hall<heavy@ungoverned.org (mailto:heavy@ungoverned.org)>
wrote:
> > > > On 3/14/12 05:00 , Neil Bartlett wrote:
> > > > > It certainly is possible to use fragments this way, it fact it's
almost
> > > > > the sole purpose of fragments. So there must be something else going
on.
> > > > > Please show what kind of error messages you're seeing.
> > > > > 
> > > > 
> > > > 
> > > > Agree with Neil. Fragment classes are loaded by the same class loader
as the
> > > > classes in the host to which they are attached, so they should have the
same
> > > > visibility to other classes.
> > > > 
> > > > -> richard
> > > > 
> > > > 
> > > > > Rgds Neil
> > > > > 
> > > > > Sent from my iPhone
> > > > > 
> > > > > On 14 Mar 2012, at 08:35, Christopher BROWN<brown@reflexe.fr (mailto:brown@reflexe.fr)>
wrote:
> > > > > 
> > > > > > Hello,
> > > > > > 
> > > > > > The software I'm creating uses Felix to separate one API bundle
(a set
> > > > > > of "official" interfaces) from various implementation bundles.
> > > > > > Generally, to discourage customers (who aren't OSGi experts)
from
> > > > > > creating dependencies on JARs upon which we require, as we want
to be
> > > > > > able to keep them as hidden implementation details that we're
free to
> > > > > > change over time. There's only a few JARs we've " promoted"
or shared
> > > > > > as proper bundles.
> > > > > > 
> > > > > > Our testing strategy involves binding fragment bundles with
tests, and
> > > > > > I hit a problem, given the approach outlined above. In short,
although
> > > > > > the fragment bundle is in the same package, it doesn't seem
possible
> > > > > > to share access to the Bundle-Classpath without exporting from
the
> > > > > > host and importing it from the Fragment. It's therefore available
to
> > > > > > world+dog as an unwanted side effect, and yet I thought Fragments
were
> > > > > > supposed to share classloader access with the host..?
> > > > > > 
> > > > > > Is there another way to do this without having to export "private
> > > > > > dependency JARs"?
> > > > > > 
> > > > > > Thanks,
> > > > > > Christopher
> > > > > > 
> > > > > 
> > > > > 
> > > > 
> > > > 
> > > 
> > > 
> > 
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe@felix.apache.org (mailto:users-unsubscribe@felix.apache.org)
> > For additional commands, e-mail: users-help@felix.apache.org (mailto:users-help@felix.apache.org)
> > 
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org (mailto:users-unsubscribe@felix.apache.org)
> For additional commands, e-mail: users-help@felix.apache.org (mailto:users-help@felix.apache.org)
> 
> 



Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message