On Jan 3, 2011, at 11:51 AM, Richard S. Hall wrote:
On 1/3/11 9:51, Bjorn Roche wrote:
On Jan 2, 2011, at 10:58 PM, Richard S. Hall wrote:
On 1/2/11 20:03, Bjorn Roche wrote:
On Dec 31, 2010, at 12:26 PM, Richard S. Hall wrote:
On 12/31/10 11:28, Bjorn Roche wrote:
On Dec 30, 2010, at 2:51 PM, Richard S. Hall wrote:
On 12/30/10 14:41, Bjorn Roche wrote:
On Dec 28, 2010, at 4:54 PM, Richard S. Hall wrote:
On 12/28/10 13:58, Bjorn Roche wrote:
On Dec 28, 2010, at 12:24 PM, Richard S. Hall wrote:
That's gotten me some distance. The app actually launches
to a point. I'm still having two problems, though:
A. My app won't load any JNI stuff no matter what I do.
B. Putting that aside, I get this error:
Caused by: java.lang.NoClassDefFoundError: com/apple/eawt/
ApplicationListener
I don't know about this either. There are some issues with
Java and the Mac Java GUI implementation, something about
needing to use the right thread or something. Maybe it is
related...
Hmmm, well I'd love to know what that is exactly, otherwise
I may be SOL. In the meantime, I will try the "exploded
bundle" thing and see if that works any better.
Yeah, maybe someone else knows more.
-> richard
Okay, so I tried your suggestion of building using the
exploded bundle. It works about as well as the "assembly:"
and "wrap:" trick, and both techniques seem to have their
pros and cons. I got stuck at the same point:
java.lang.NoClassDefFoundError: com/apple/eawt/
ApplicationListener
To belabor the point, here's the code that failed:
if (os == MAC_OS_X) {
try {
Class<?> osxAdapter =
ResourceUtil.getClass(app,"xowave.util.OSXAdapter");
Class<?>[] defArgs = { OSXApp.class };
Constructor<?> constructor =
osxAdapter.getConstructor(defArgs);
if (constructor != null) {
Object[] args = { app };
constructor.newInstance(args);
}
} catch (Exception e) {
...
}
Now xowave.util.OSXAdapter implements
com.apple.eawt.ApplicationListener, which is only available
on mac OS X, so if the class were loaded directly, it would
cause class-loading problems on non-OSX platforms, so I added
the dynamic loading code. (I don't recall if this is exactly
the approach recommended by apple, but something like it.)
And your bundle imports the "xowave.util" package?
xowave.util is part of the bundle.
Does the mentioned class have a direct dependency on
com.apple.eawt.ApplicationListener? If so, is the bundle
importing that package?
I was able to get around this by following Richard's hunch: I
simply by putting the above code in the swing thread with a
call to SwingUtilities.invokeLater().
This strikes me as a bug in OSGi because I should not need to
be in a particular thread to implement an interface no matter
what the interface is.
I don't know if this is the issue, but if it is, the way I
understood it, it is a limitation of the Mac implementation of
AWT or something.
It works fine outside of OSGi.
That's doesn't mean that it isn't a Mac implementation issue.
I'm not saying it is or it isn't, though. Here is one example:
http://www.eclipsezone.com/eclipse/forums/m92141277.html
I am still stuck loading native code, though. I added this to
my MANIFEST.MF:
Bundle-NativeCode: native/libXOengine-DOUBLE.jnilib ; native/
libXOengine-FLOAT.jnilib ; native/libquaqua.jnilib ;
processor=x86 ;
processor=ppc ;
osname=mac os x
where the paths are relative to my bundle. I have some
indication that this is correct because if I deliberately
type change something I get
Native library does not exist
or
No matching native libraries found.
but when my code calls
System.loadLibrary( "XOengine-FLOAT" );
I get
Caused by: java.lang.UnsatisfiedLinkError: no XOengine-FLOAT
in java.library.path
Not sure. It should work. If you can create a simple bundle
that fails, I can try it, since I work on a Mac. Send it to me
privately.
If I can reproduce on a small scale, I will, thank you. In the
meantime, I just noticed I am getting this, apparently from
felix:
ERROR: Unable to create library directory.
What's more, System.load() works, where System.loadLibrary fails.
Some googling suggested that the install name of the library
might be the issue, but I mucked with that without any luck.
Well, it should work. Let me know.
It's my understanding that java.library.path is not used -- at
least directly -- during normal Felix/OSGi operation, but I
thought I'd see what its value was right before calling
System.loadLibrary to get a hint. When I run my code outside of
OSGi I get:
.:/Users/bjorn/Library/Java/Extensions:/Library/Java/Extensions:/
System/Library/Java/Extensions:/usr/lib/java
which seams reasonable. I use -Djava.library.path to set it to
just the path I care about with my native libs so that they will
load, and that's always worked.
Inside felix/OSGi, the same line of code gives:
:/usr/local/ImageMagick-6.3.9//lib:.:/Users/bjorn/Library/Java/
Extensions:/Library/Java/Extensions:/System/Library/Java/
Extensions:/usr/lib/java
which seemed whack, at least the part before the what I get out
of OSGi. It turned out my .profile was setting that ImageMagick
line, and, moreover, it was totally bogus:
.profile:MAGICK_HOME="/usr/local/ImageMagick-6.3.9/" ; export
MAGICK_HOME
arigato:~ bjorn$ grep MAGICK_HOME .*
.profile:MAGICK_HOME="/usr/local/ImageMagick-6.3.9/" ; export
MAGICK_HOME
.profile:#MAGICK_HOME="/usr/local/" ; export MAGICK_HOME
.profile:PATH="$PATH:$MAGICK_HOME/bin:":~/bin: ; export PATH
.profile:DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$MAGICK_HOME/
lib" ; export DYLD_LIBRARY_PATH
arigato:~ bjorn$ ls /usr/local/ImageMagick-6.3.9/
ls: /usr/local/ImageMagick-6.3.9/: No such file or directory
Once I removed that (I think this was from a failed gallery
remote install) and restarted my shell I got something reasonable
out of java.library.path, even inside OSGi:
.:/Users/bjorn/Library/Java/Extensions:/Library/Java/Extensions:/
System/Library/Java/Extensions:/usr/lib/java
Once that's fixed, I get a slightly different error when I run my
app:
ERROR: Extracting native library.
(java.io.FileNotFoundException: ./felix-cache/bundle3/version0.0/
xowave-lib/0/native/libXOengine-FLOAT.jnilib (No such file or
directory))
java.io.FileNotFoundException: ./felix-cache/bundle3/version0.0/
xowave-lib/0/native/libXOengine-FLOAT.jnilib (No such file or
directory)
java.io.FileNotFoundException: ./felix-cache/bundle3/version0.0/
xowave-lib/0/native/libXOengine-FLOAT.jnilib (No such file or
directory)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:179)
at java.io.FileOutputStream.<init>(FileOutputStream.java:131)
at
org
.apache
.felix
.framework
.util.SecureAction.getFileOutputStream(SecureAction.java:461)
at
org
.apache
.felix
.framework.cache.BundleCache.copyStreamToFile(BundleCache.java:310)
at
org
.apache
.felix
.framework
.cache
.DirectoryContent.getEntryAsNativeLibrary(DirectoryContent.java:
266)
at org.apache.felix.framework.ModuleImpl
$ModuleClassLoader.findLibrary(ModuleImpl.java:2081)
After I did a little digging I found the directory tree it
claimed to be looking for (felix-cache/bundle3/version0.0/xowave-
lib/0/native/), but it wasn't in the current directory; it was in
my home directory. By deleting the caches directory and
rerunning, I realized that felix is building two caches every
time I run it, one in my home dir and one in the current dir.
There seems to be some bug relating to this. Setting the
temporary dir explicitly to my home dir:
org.osgi.framework.storage=/Users/bjorn/felix-cache
works! Also works when I set the storage dir from the command
line rather than the conf file:
-Dorg.osgi.framework.storage=/tmp/$USER/felix-cache
Great, so I have a solution. Still, it seems there is a problem
with locating the cache dir (is it in the home dir or current
dir?). Also, it seems to me that even if a bogus path is added to
DYLD_LIBRARY_PATH, that shouldn't change anything.
If no cache directory is specified, the Felix framework will
create a "felix-cache" directory in the current directory (i.e.,
the directory you are in when you launch the framework). So, if
you are starting the framework from different directories, you'll
see it get created in different places. I don't think there is any
way a single execution of the framework will create multiple
copies of the cache.
when I ran felix, it would create cache directories in both my home
and current directories. I verified this by deleting "felix-cache"
in both the current and home dir, running felix once, and locating
these directories again. It built the felix-cache/bundle3/
version0.0/xowave-lib/0/native/ tree in my home directory, but then
complained that it couldn't find it. It put everything else in the
current directory. The solution to this issue seemed to be to
specify the org.osgi.framework.storage variable from the command
line rather than the configuration file, but I'm not really sure.
Maybe this is a bug in the code to support "exploded bundles". Can
you create a test case (framework configuration and/or bundle) that
demonstrates this? If so, open a bug an submit it.
That seems like the most likely explanation to me. I am working on a
minimal test case.
Regarding the java.library.path, the framework doesn't look at
this at all. This should only impact the JVM. The only thing the
framework does is create a custom class loader that overrides
findLibrary() and waits for the JVM to call it when a class loaded
by the class loader needs a native library.
I'm not really sure what the issue here was -- I only used
java.library.path to discover what was going on and it may only
have been related incidentally. Perhaps the issue has to do with
the $DYLD_LIBRARY_PATH variable -- it must at least indirectly
since that's what I changed to get it working.
Maybe, but I'm not sure how it would impact the framework, since it
never consults it.
Hmmm. That's odd. Maybe it has some indirect impact. I will see if I
can reproduce that on some small sample code as well. It's possible I
have a configuration issue on my system.
bjorn
-----------------------------
Bjorn Roche
http://www.xonami.com
Audio Collaboration