How do I access a file inside an OSGi bundle?
Asked Answered
H

3

17

I am new to OSGi and created an OSGi-bundle which I run in the Apache Felix OSGi-container. There is a file resource contained in the bundle, which I need to pass to a method as a java.io.File. To instantiate a File-object, either an URI in the "file"-scheme or the path as string is necessary. How do I retrieve any of those in a clean way?

I tried using the context.getBundle().getResource("/myfile") (where context is of type org.osgi.framework.BundleContext) which returns the URI bundle://6.0:0/myfile. But this URI can't be converted to a File-instance using the File(URI uri) constructor since it has the "bundle"-scheme.

One could try to construct a path to the location knowing the working directory and exploiting the bundleId of my bundle, but I doubt this is the best practice.

Any ideas?

Hobby answered 24/6, 2011 at 23:11 Comment(1)
Equinox has special utility class to do such conversions in future-proof way, but I don't know about Felix. If you want to code against clean OSGi API, you would need to copy this file somewhere, where you can easily retrieve the corresponding File object (for example in your Bundle.getDataFile() storage).Conversable
R
17

Since the file is inside your bundle, there is no way for you to get to it using a standard File. The URL you get from Bundle.getResource() is the correct way to get to these resources, since the OSGi APIs are intended to also work on systems without an actual file system. I would always try to stick to the OSGi API instead of using framework-specific solutions.

So, if you have control over the method, I would update it to take a URL, or maybe even an InputStream (since you probably just want to read from it). For convenience, you can always provide a helper method that does take a File.

If you don't have control over the method, you will have to write some helper method that takes the URL, streams it out to a file (for instance, File.createTempFile() will probably do the trick.

Revisionist answered 25/6, 2011 at 10:41 Comment(4)
Thanks for your answer. I have no control over the method, since it is a dependency I cannot modify and this dependency dictates an argument of type File. To paraphrase your answer: You suggest to access the File via InputStream and write it as a temporary file in the private area of the bundle referenced via the OSGi-API. Is this the best practice in general? Because with this technique the resources are doubled in the physical memory. Assume you have multiple files, they all would be doubled, which can be a problem on small devices. Or am I missing a point?Hobby
You're absolutely right, this is an inefficiency, brought on by the difference in philosophy between OSGi ("every resource has a URL, even when we don't have files") and your library ("I must have a file"). You could use temp files, or use your bundle storage; whatever suits your situation best.Revisionist
Angelo is correct... the library you are using is badly designed. It insists you give it a file, but what you have is NOT a file, it is a fragment of a file (technically, an entry of a ZIP). The inefficiency is therefore unavoidable.Limpkin
@Namphibian, Yup, fixed it.Revisionist
N
7

Maybe the API is confusable, but You can access a file inside an OSGI bundle like this:

URL url = context.getBundle().getResource("com/my/weager/impl/test.txt");

// The url maybe like this: bundle://2.0:2/com/my/weager/impl/test.txt
// But this url is not a real file path :(, you could't use it as a file.
// This url should be handled by the specific URLHandlersBundleStreamHandler, 
// you can look up details in BundleRevisionImpl.createURL(int port, String path)
System.out.println(url.toString());

BufferedReader br =new BufferedReader(new InputStreamReader(url.openConnection().getInputStream()));
while(br.ready()){
    System.out.println(br.readLine());
}
br.close();

getResource will find the resource through the whole OSGI container just like OSGI classloader theory.
getEntry will find the resource from local bundle. and the return url could be convert to file but inputStream.
Here is a question same with this: No access to Bundle Resource/File (OSGi) Hope this helping you.

Northrop answered 26/5, 2013 at 8:20 Comment(0)
A
2

What I use is getClassLoader().getResourceAsStream():

InputStream inStream = new java.io.BufferedInputStream(this.getClass().getClassLoader().getResourceAsStream(fileName));

This way the file will be loaded from your resource dir. FileName should contain the path after "src/main/resources".

Full example here:

static public byte[] readFileAsBytes(Class c, String fileName) throws IOException {
    InputStream inStream = new java.io.BufferedInputStream(c.getClassLoader().getResourceAsStream(fileName));
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    int nbytes = 0;
    byte[] buffer = new byte[100000];

    try {
        while ((nbytes = inStream.read(buffer)) != -1) {
            out.write(buffer, 0, nbytes);
        }
        return out.toByteArray();
    } finally {
        if (inStream != null) { 
            inStream.close();
        }
        if (out != null) {
            out.close();
        }
    }
}
Alignment answered 29/5, 2015 at 14:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.