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<he...@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<br...@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