Create Leap Motion Java Application (including -Djava.library.path inside jar) [duplicate] - java

The library in question is Tokyo Cabinet.
I want is to have the native library, JNI library, and all Java API classes in one JAR file to avoid redistribution headaches.
There seems to be an attempt at this at GitHub, but
It does not include the actual native library, only JNI library.
It seems to be specific to Leiningen's native dependencies plugin (it won't work as a redistributable).
The question is, can I bundle everything in one JAR and redistribute it? If yes, how?
P.S.: Yes, I realize it may have portability implications.

It is possible to create a single JAR file with all dependencies including the native JNI libraries for one or more platforms. The basic mechanism is to use System.load(File) to load the library instead of the typical System.loadLibrary(String) which searches the java.library.path system property. This method makes installation much simpler as the user does not have to install the JNI library on his system, at the expense, however, that all platforms might not be supported as the specific library for a platform might not be included in the single JAR file.
The process is as follows:
include the native JNI libraries in the JAR file at a location specific to the platform, for example at NATIVE/${os.arch}/${os.name}/libname.lib
create code in a static initializier of the main class to
calc the current os.arch and os.name
look for the library in the JAR file at the predefined location using Class.getResource(String)
if it exists, extract it to a temp file and load it with System.load(File).
I added functionality to do this for jzmq, the Java bindings of ZeroMQ (shameless plug). The code can be found here. The jzmq code uses a hybrid solution so that if an embedded library cannot be loaded, the code will revert to searching for the JNI library along the java.library.path.

https://www.adamheinrich.com/blog/2012/12/how-to-load-native-jni-library-from-jar/
is great article, which solves my issue ..
In my case I've got the following code for initialize the library:
static {
try {
System.loadLibrary("crypt"); // used for tests. This library in classpath only
} catch (UnsatisfiedLinkError e) {
try {
NativeUtils.loadLibraryFromJar("/natives/crypt.dll"); // during runtime. .DLL within .JAR
} catch (IOException e1) {
throw new RuntimeException(e1);
}
}
}

Take a look at One-JAR. It will wrap your application up in a single jar file with a specialised class loader which handles "jars within jars" among other things.
It handles native (JNI) libraries by unpacking them to a temporary working folder as required.
(Disclaimer: I've never used One-JAR, haven't needed to as yet, just had it bookmarked for a rainy day.)

1) Include the native library into your JAR as a Resource. E. g. with Maven or Gradle, and the standard project layout, put the native library into main/resources directory.
2) Somewhere in static initializers of Java classes, related to this library, put the code like the following:
String libName = "myNativeLib.so"; // The name of the file in resources/ dir
URL url = MyClass.class.getResource("/" + libName);
File tmpDir = Files.createTempDirectory("my-native-lib").toFile();
tmpDir.deleteOnExit();
File nativeLibTmpFile = new File(tmpDir, libName);
nativeLibTmpFile.deleteOnExit();
try (InputStream in = url.openStream()) {
Files.copy(in, nativeLibTmpFile.toPath());
}
System.load(nativeLibTmpFile.getAbsolutePath());

JarClassLoader is a class loader to load classes, native libraries and resources from a single monster JAR and from JARs inside the monster JAR.

Solution for Kotlin:
build.gradle.dsl: copy kotlin runtime (kotlin-stdlib-1.4.0.jar) and native library (librust_kotlin.dylib) to JAR
tasks.withType<Jar> {
manifest {
attributes("Main-Class" to "MainKt")
}
val libs = setOf("kotlin-stdlib-1.4.0.jar")
from(configurations.runtimeClasspath.get()
.filter { it.name in libs }
.map { zipTree(it) })
from("librust_kotlin.dylib")
}
main method: copy library to a temporary file to load it using absolute path
with(createTempFile()) {
deleteOnExit()
val bytes = My::class.java.getResource("librust_kotlin.dylib")
.readBytes()
outputStream().write(bytes)
System.load(path)
}

You will probably have to unjar the native library to the local file system. As far as I know the bit of code that does the native loading looks at the file system.
This code should help get you started (I haven't looked at it in a while, and it is for a different purpose but should do the trick, and I am pretty busy at the moment, but if you have questions just leave a comment and I'll answer as soon as I can).
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class FileUtils
{
public static String getFileName(final Class<?> owner,
final String name)
throws URISyntaxException,
ZipException,
IOException
{
String fileName;
final URI uri;
try
{
final String external;
final String decoded;
final int pos;
uri = getResourceAsURI(owner.getPackage().getName().replaceAll("\\.", "/") + "/" + name, owner);
external = uri.toURL().toExternalForm();
decoded = external; // URLDecoder.decode(external, "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
catch(final FileNotFoundException ex)
{
fileName = null;
}
if(fileName == null || !(new File(fileName).exists()))
{
fileName = getFileNameX(owner, name);
}
return (fileName);
}
private static String getFileNameX(final Class<?> clazz, final String name)
throws UnsupportedEncodingException
{
final URL url;
final String fileName;
url = clazz.getResource(name);
if(url == null)
{
fileName = name;
}
else
{
final String decoded;
final int pos;
decoded = URLDecoder.decode(url.toExternalForm(), "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
return (fileName);
}
private static URI getResourceAsURI(final String resourceName,
final Class<?> clazz)
throws URISyntaxException,
ZipException,
IOException
{
final URI uri;
final URI resourceURI;
uri = getJarURI(clazz);
resourceURI = getFile(uri, resourceName);
return (resourceURI);
}
private static URI getJarURI(final Class<?> clazz)
throws URISyntaxException
{
final ProtectionDomain domain;
final CodeSource source;
final URL url;
final URI uri;
domain = clazz.getProtectionDomain();
source = domain.getCodeSource();
url = source.getLocation();
uri = url.toURI();
return (uri);
}
private static URI getFile(final URI where,
final String fileName)
throws ZipException,
IOException
{
final File location;
final URI fileURI;
location = new File(where);
// not in a JAR, just return the path on disk
if(location.isDirectory())
{
fileURI = URI.create(where.toString() + fileName);
}
else
{
final ZipFile zipFile;
zipFile = new ZipFile(location);
try
{
fileURI = extract(zipFile, fileName);
}
finally
{
zipFile.close();
}
}
return (fileURI);
}
private static URI extract(final ZipFile zipFile,
final String fileName)
throws IOException
{
final File tempFile;
final ZipEntry entry;
final InputStream zipStream;
OutputStream fileStream;
tempFile = File.createTempFile(fileName.replace("/", ""), Long.toString(System.currentTimeMillis()));
tempFile.deleteOnExit();
entry = zipFile.getEntry(fileName);
if(entry == null)
{
throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
}
zipStream = zipFile.getInputStream(entry);
fileStream = null;
try
{
final byte[] buf;
int i;
fileStream = new FileOutputStream(tempFile);
buf = new byte[1024];
i = 0;
while((i = zipStream.read(buf)) != -1)
{
fileStream.write(buf, 0, i);
}
}
finally
{
close(zipStream);
close(fileStream);
}
return (tempFile.toURI());
}
private static void close(final Closeable stream)
{
if(stream != null)
{
try
{
stream.close();
}
catch(final IOException ex)
{
ex.printStackTrace();
}
}
}
}

Related

Text and image files not included when exporting jar

I've created a project which utilizes image files as well as a text file when executed. Both the text and image files are in my project folder before I exported the project into a runnable jar, but when I ran the jar from the command line, I got a filenotfound exception caused by the program typing to read from the text file. I unzipped the jar to double check and the image and text files weren't there.
package application;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import javafx.collections.FXCollections;
public class Data {
private static Data instance=new Data();
private Map<String,String> saveEntries = new HashMap<>();
private static String fileName = "ResponseData";
public static Data getInstance() {
return instance;
}
public void exitSave() throws IOException {
Path path = Paths.get("ResponseData");
Iterator<Map.Entry<String, String>> iter = saveEntries.entrySet().iterator();
BufferedWriter bw = Files.newBufferedWriter(path);
try {
while(iter.hasNext()) {
Map.Entry<String, String> entry = iter.next();
bw.write(String.format("%s\t%s", entry.getKey(),entry.getValue()));
bw.newLine();
}
} catch (IOException e) {
new FileNotFoundException("Error when saving data");
}finally {
if(bw!=null)
bw.close();
}
}
public void updatedSaveEntry(String input, String response) {
saveEntries.put(input, response);
}
public Map<String,String> getSaveEntries(){
return this.saveEntries;
}
public void setEntry(Map<String,String> map) {
Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();
while(iter.hasNext()) {
Map.Entry<String, String> entry = iter.next();
saveEntries.put(entry.getKey(), entry.getValue());
}
}
public void loadEntries() throws IOException{
saveEntries = FXCollections.observableHashMap();
Path path = Paths.get(fileName);
BufferedReader br = Files.newBufferedReader(path);
String line;
try {
while((line=br.readLine())!=null&&!line.trim().isEmpty()) {
String[] parts = line.split("\t");
saveEntries.put(parts[0], parts[1]);
}
}finally {
if(br!=null) {
br.close();
}
}
}
}
Eclipse Runnable Jar Export
Project Folder
If you are both reading and writing to a file, then locating this file in the application jar is not appropriate as mentioned in the other answer: you should persist your data at an external location.
However, it is usual to keep the read-only resources files (such as images) in the jar. If you want to keep this approach for the images and possibly other resources, you are facing two problems:
Getting Eclipse to include the file in the jar using the Export Runnable Jar feature.
Finding the file in the jar
Including the file
The simplest is probably just to place the file in a source folder. In your project, do New -> Source Folder, give it a name (e.g., "resources"), and move your file there. Normally, if you re-run the export, the file should be in the jar.
Finding the file
Files in jar are accessed differently. See the accepted answer to Reading a resource file from within jar. Note that you don't need to include the name of your resource folder in the path, as this file will be placed at the root of your jar (you can verify this by unpacking it).
Your program is trying to read the file from your local file system and not from the jar file. So it should indeed not be included in the jar file. The program is expecting the file in the current working directory where you execute your program and that can be different if you run your project within Eclipse or if you execute the exported jar file.

Access public assets with Java in Play Framework

Is it possible to access Assets inside the Java code in Play Framework? How?
We access assets from the scala HTML templates this way:
<img src="#routes.Assets.versioned("images/myimage.png")" width="800" />
But I could not find any documentation nor code example to do it from inside the Java code. I just found a controllers.Assets class but it is unclear how to use it. If this is the class that has to be used, should it maybe be injected?
I finally found a way to access the public folder even from a production mode application.
In order to be accessible/copied in the distributed version, public folder need to be mapped that way in build.sbt:
import NativePackagerHelper._
mappings in Universal ++= directory("public")
The files are then accessible in the public folder in the distributed app in production form the Java code:
private static final String PUBLIC_IMAGE_DIRECTORY_RELATIVE_PATH = "public/images/";
static File getImageAsset(String relativePath) throws ResourceNotFoundException {
final String path = PUBLIC_IMAGE_DIRECTORY_RELATIVE_PATH + relativePath;
final File file = new File(path);
if (!file.exists()) {
throw new ResourceNotFoundException(String.format("Asset %s not found", path));
}
return file;
}
This post put me on the right way to find the solution: https://groups.google.com/forum/#!topic/play-framework/sVDoEtAzP-U
The assets normally are in the "public" folder, and I don't know how you want to use your image so I have used ImageIO .
File file = new File("./public/images/nice.png");
boolean exists = file.exists();
String absolutePath = file.getAbsolutePath();
try {
ImageInputStream input = ImageIO.read(file); //Use it
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("EX = "+exists+" - "+absolutePath);

Tomcat not loading new images from context path after server is already started

Inside server.xml of my tomcat folder, i have a virtual folder under <Host> tag:
<Context docBase="C:\app_files\" path="/app_files"/>
So i can access files from inside this folder through the url: http://localhost:8080/app_files/some_file.jpg
But this only works if the image or file was already there BEFORE the server was started. If i go to a URL pointing to an image created after the server was started, it gives the 404 error. After restarting the server, the image loads correctly.
How to sove this problem?
If you use Tomcat application manager you can undeploy/deploy your single application without restarting the whole server (and without impact on other webapps) or, more brutally, you can replace the desired war from the webapps dir (again undeploy/deploy will ensue). If you have to guarantee uptime for your application even in this case you have to go with parallel deployment (here a guide for tomcat 8)
try to add the attribute autoDeploy="true" to your context configuration, this will tell catalina to monitor your docbase location for changes
I actually managed to do what i wanted without using the Context on the server.xml.
It's based on the BalusC's solution to serve static files through servlets
Here's how:
First, i created an environment variable in my system (can be done in every os, just google for "how to create environment variable on windows, linux, etc"), called MANAGEMENT_FILES, the variable value in my case was c:/management_files/
Then, on the method that creates the image that should be shown to the user, i save the image on this folder (which is the value of the environment variable from the previous step):
public String imageUrl;
public void createAndShowImage() {
try {
String imageName = "/nice_images_folder/cool_image.jpg";
File imageFile = new File(System.getenv("MANAGEMENT_FILES") + imageName);
//Here goes your logic to create the file
createImage(imageFile);
//Here i use a fixed URL, you can do it as you see fit
this.imageUrl = "http://localhost:8080/MyCoolApp/" + CoolFileServlet.BASE_URL + imageName + "?delete=true";
} catch (Exception e) {
e.printStackTrace();
}
}
And this is the servlet you have to create, this servlet returns the image or any other file that you put inside the folder:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#WebServlet(name="CoolFileServlet", urlPatterns={CoolFileServlet.BASE_URL + "*"})
public class CoolFileServlet extends HttpServlet {
public static final String BASE_URL = "/shiny_happy_files/";
private static final int DEFAULT_BUFFER_SIZE = 10240;
private String filePath;
public void init() throws ServletException {
this.filePath = System.getenv("MANAGEMENT_FILES");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String requestedFile = request.getPathInfo();
if (requestedFile == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
File file = new File(filePath, URLDecoder.decode(requestedFile, "UTF-8"));
if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
return;
}
String contentType = getServletContext().getMimeType(file.getName());
if (contentType == null) {
contentType = "application/octet-stream";
}
response.reset();
response.setBufferSize(DEFAULT_BUFFER_SIZE);
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} finally {
close(output);
close(input);
try {
if ("true".equals(request.getParameter("delete"))) {
if (!file.delete()) {
throw new RuntimeException("File could not be deleted");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Notice that you can pass the parameter delete=true in the url when it is accessed, to delete it right after it is recovered (in cases when it will not be needed anymore).
In my case i needed to show the image on the page after the user performed some action, so all i had to do was show the image url:
<h:graphicImage url="#{myManagedBean.imageUrl}"/>
That's it, you can serve any type of file with this servlet, and it will return the file you want, instantly, and the file will remain active between server restart/redeploy (if it was not deleted through delete=true.
If you care for a different approach, you can also do this by mapping a function in a controller that returns a IOUtils object while specifying the media type, then calling the function's URL in your img's src.
#ResponseBody
#RequestMapping(value="/load_photo", params = {"myPhoto"}, method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public byte[] loadPhoto(#RequestParam(value = "myPhoto") String myPhoto) throws IOException {
File file = new File(servletContext.getRealPath("")+Constants.PATH_TO_FILE+myPhoto);
FileInputStream fis = new FileInputStream(file);
return IOUtils.toByteArray(fis);
}
Then you call your img in your JSP:
<img class="photo" src="/app/controller/load_photo?myPhoto=${myPhoto}">
With this, you can serve dynamically generated images.

Sound file not found, not in directory?

I'm coding this in java and put my sounds folder with the bgmusic.wav in there but it doesn't seem to still identify it. Am I doing something wrong?
Here is my Sound class:
import java.applet.Applet;
import java.applet.AudioClip;
import java.io.File;
import java.net.MalformedURLException;
public class Sound {
private AudioClip myClip;
public Sound(String fileName) {
try {
File file = new File(fileName);
if (file.exists()) {
myClip = (AudioClip) Applet.newAudioClip(file.toURI().toURL());
} else {
throw new RuntimeException("Sound: file not found: " + fileName);
}
} catch (MalformedURLException e) {
throw new RuntimeException("Sound: malformed URL: " + e);
}
}
public void play() {
myClip.play();
}
}
This is then ran as an Object in my other class to run the bgmusic.wav:
String fileName = "bgmusic.wav";
String soundDir = "." + File.separator + "sounds" + File.separator;
String filePath = soundDir + fileName;
Sound bgMusic = new Sound(filePath);
bgMusic.play();
If I'm not mistaken I think I have everything setup correctly but I get a Sound: file not found: ./sounds/bgmusic.wav which is returned from to throw exception in my Sound class. Since I have the sounds folder as a subdirectory of the main java folder passing ./sounds/bgmusic.wav should be correct right?
The new File(".") represents the base folder (the root folder) of your application.
So check your directory structure that where does the file appear with respect to the project base folder. else share your project structure.
If you are placing the file in the java classpath (The src folder) then you can load the sound file from class path (refer here)
I think you need to have the full path for File to recognize it.

How to bundle a native library and a JNI library inside a JAR?

The library in question is Tokyo Cabinet.
I want is to have the native library, JNI library, and all Java API classes in one JAR file to avoid redistribution headaches.
There seems to be an attempt at this at GitHub, but
It does not include the actual native library, only JNI library.
It seems to be specific to Leiningen's native dependencies plugin (it won't work as a redistributable).
The question is, can I bundle everything in one JAR and redistribute it? If yes, how?
P.S.: Yes, I realize it may have portability implications.
It is possible to create a single JAR file with all dependencies including the native JNI libraries for one or more platforms. The basic mechanism is to use System.load(File) to load the library instead of the typical System.loadLibrary(String) which searches the java.library.path system property. This method makes installation much simpler as the user does not have to install the JNI library on his system, at the expense, however, that all platforms might not be supported as the specific library for a platform might not be included in the single JAR file.
The process is as follows:
include the native JNI libraries in the JAR file at a location specific to the platform, for example at NATIVE/${os.arch}/${os.name}/libname.lib
create code in a static initializier of the main class to
calc the current os.arch and os.name
look for the library in the JAR file at the predefined location using Class.getResource(String)
if it exists, extract it to a temp file and load it with System.load(File).
I added functionality to do this for jzmq, the Java bindings of ZeroMQ (shameless plug). The code can be found here. The jzmq code uses a hybrid solution so that if an embedded library cannot be loaded, the code will revert to searching for the JNI library along the java.library.path.
https://www.adamheinrich.com/blog/2012/12/how-to-load-native-jni-library-from-jar/
is great article, which solves my issue ..
In my case I've got the following code for initialize the library:
static {
try {
System.loadLibrary("crypt"); // used for tests. This library in classpath only
} catch (UnsatisfiedLinkError e) {
try {
NativeUtils.loadLibraryFromJar("/natives/crypt.dll"); // during runtime. .DLL within .JAR
} catch (IOException e1) {
throw new RuntimeException(e1);
}
}
}
Take a look at One-JAR. It will wrap your application up in a single jar file with a specialised class loader which handles "jars within jars" among other things.
It handles native (JNI) libraries by unpacking them to a temporary working folder as required.
(Disclaimer: I've never used One-JAR, haven't needed to as yet, just had it bookmarked for a rainy day.)
1) Include the native library into your JAR as a Resource. E. g. with Maven or Gradle, and the standard project layout, put the native library into main/resources directory.
2) Somewhere in static initializers of Java classes, related to this library, put the code like the following:
String libName = "myNativeLib.so"; // The name of the file in resources/ dir
URL url = MyClass.class.getResource("/" + libName);
File tmpDir = Files.createTempDirectory("my-native-lib").toFile();
tmpDir.deleteOnExit();
File nativeLibTmpFile = new File(tmpDir, libName);
nativeLibTmpFile.deleteOnExit();
try (InputStream in = url.openStream()) {
Files.copy(in, nativeLibTmpFile.toPath());
}
System.load(nativeLibTmpFile.getAbsolutePath());
JarClassLoader is a class loader to load classes, native libraries and resources from a single monster JAR and from JARs inside the monster JAR.
Solution for Kotlin:
build.gradle.dsl: copy kotlin runtime (kotlin-stdlib-1.4.0.jar) and native library (librust_kotlin.dylib) to JAR
tasks.withType<Jar> {
manifest {
attributes("Main-Class" to "MainKt")
}
val libs = setOf("kotlin-stdlib-1.4.0.jar")
from(configurations.runtimeClasspath.get()
.filter { it.name in libs }
.map { zipTree(it) })
from("librust_kotlin.dylib")
}
main method: copy library to a temporary file to load it using absolute path
with(createTempFile()) {
deleteOnExit()
val bytes = My::class.java.getResource("librust_kotlin.dylib")
.readBytes()
outputStream().write(bytes)
System.load(path)
}
You will probably have to unjar the native library to the local file system. As far as I know the bit of code that does the native loading looks at the file system.
This code should help get you started (I haven't looked at it in a while, and it is for a different purpose but should do the trick, and I am pretty busy at the moment, but if you have questions just leave a comment and I'll answer as soon as I can).
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class FileUtils
{
public static String getFileName(final Class<?> owner,
final String name)
throws URISyntaxException,
ZipException,
IOException
{
String fileName;
final URI uri;
try
{
final String external;
final String decoded;
final int pos;
uri = getResourceAsURI(owner.getPackage().getName().replaceAll("\\.", "/") + "/" + name, owner);
external = uri.toURL().toExternalForm();
decoded = external; // URLDecoder.decode(external, "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
catch(final FileNotFoundException ex)
{
fileName = null;
}
if(fileName == null || !(new File(fileName).exists()))
{
fileName = getFileNameX(owner, name);
}
return (fileName);
}
private static String getFileNameX(final Class<?> clazz, final String name)
throws UnsupportedEncodingException
{
final URL url;
final String fileName;
url = clazz.getResource(name);
if(url == null)
{
fileName = name;
}
else
{
final String decoded;
final int pos;
decoded = URLDecoder.decode(url.toExternalForm(), "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
return (fileName);
}
private static URI getResourceAsURI(final String resourceName,
final Class<?> clazz)
throws URISyntaxException,
ZipException,
IOException
{
final URI uri;
final URI resourceURI;
uri = getJarURI(clazz);
resourceURI = getFile(uri, resourceName);
return (resourceURI);
}
private static URI getJarURI(final Class<?> clazz)
throws URISyntaxException
{
final ProtectionDomain domain;
final CodeSource source;
final URL url;
final URI uri;
domain = clazz.getProtectionDomain();
source = domain.getCodeSource();
url = source.getLocation();
uri = url.toURI();
return (uri);
}
private static URI getFile(final URI where,
final String fileName)
throws ZipException,
IOException
{
final File location;
final URI fileURI;
location = new File(where);
// not in a JAR, just return the path on disk
if(location.isDirectory())
{
fileURI = URI.create(where.toString() + fileName);
}
else
{
final ZipFile zipFile;
zipFile = new ZipFile(location);
try
{
fileURI = extract(zipFile, fileName);
}
finally
{
zipFile.close();
}
}
return (fileURI);
}
private static URI extract(final ZipFile zipFile,
final String fileName)
throws IOException
{
final File tempFile;
final ZipEntry entry;
final InputStream zipStream;
OutputStream fileStream;
tempFile = File.createTempFile(fileName.replace("/", ""), Long.toString(System.currentTimeMillis()));
tempFile.deleteOnExit();
entry = zipFile.getEntry(fileName);
if(entry == null)
{
throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
}
zipStream = zipFile.getInputStream(entry);
fileStream = null;
try
{
final byte[] buf;
int i;
fileStream = new FileOutputStream(tempFile);
buf = new byte[1024];
i = 0;
while((i = zipStream.read(buf)) != -1)
{
fileStream.write(buf, 0, i);
}
}
finally
{
close(zipStream);
close(fileStream);
}
return (tempFile.toURI());
}
private static void close(final Closeable stream)
{
if(stream != null)
{
try
{
stream.close();
}
catch(final IOException ex)
{
ex.printStackTrace();
}
}
}
}

Categories