I have a directory of arbitrary files I want to include in my jar - however, I cannot figure out a way to do so that works with export -> "Runnable jar". I've tried the trick of making the directory a 'source path' but it is still absent when I build the jar. I realize I can manually add them into the jar (it is just a zip, after all) - or I could use an ant script or other build system - but I'm looking for something that works for an out-of-the-box Eclipse "Java project".
Here's an example. I want to try to load log4j.properties if it exists. If not, I want to write it out from an included 'default' in my jarfile. Finally, it loads the defaults if that fails.
Note that I have no idea yet if the code below works, it will likely need tweaking. I'm not asking for help with that, I'm just giving context for what I want to do.
// initialize logging libraries
File log4jFile = new File("log4j.properties");
if (log4jFile.exists() & log4jFile.canRead()) {
PropertyConfigurator.configure(log4jFile.getAbsolutePath());
}
else {
try {
InputStream log4jJarstream = Main.class.getResourceAsStream(sepd + "resources" + sep + "log4j.properties");
OutputStream outStream = new FileOutputStream(new File("log4j.properties"));
int read = 0;
byte[] bytes = new byte[1024];
while ((read = log4jJarstream.read(bytes)) != -1) {
outStream.write(bytes, 0, read);
}
log4jJarstream.close();
outStream.flush();
outStream.close();
}
catch (Exception e) {
BasicConfigurator.configure();
log.warn("Error writing log4j.properties, falling back to defaults.");
}
}
I added the log4j.properties to my src folder, and exported the jar as a runnable. It worked.
Simply try Export --> JAR file instead of exporting Runnable JAR file: it allows you to select multiple resources to include in the generated archive.
You can also specify the Main-Class property, just like with the latter option.
BTW it is more convenient if you use some kind of build tool (like Ant <jar> target or the Maven Jar plugin). If you use Eclipse to generate the JAR file, there is also an option to save an Ant buildfile that can do the task for you later on.
There was an error in the code loading the file as a resource... which it seems Eclipse "saw" and as such was refusing to package the file. I put the file along side the class files and altered the way I search for the file, and it packaged it with the .class files and was able to be read during execution. New code snippet:
// initialize logging libraries
File log4jFile = new File("log4j.properties");
if (log4jFile.exists() & log4jFile.canRead()) {
PropertyConfigurator.configure("log4j.properties");
}
else {
try {
InputStream log4jJarstream = Main.class.getResourceAsStream("log4j.properties");
OutputStream outStream = new FileOutputStream(new File("log4j.properties"));
int read = 0;
byte[] bytes = new byte[1024];
while ((read = log4jJarstream.read(bytes)) != -1) {
outStream.write(bytes, 0, read);
}
log4jJarstream.close();
outStream.flush();
outStream.close();
PropertyConfigurator.configure("log4j.properties");
}
catch (Exception e) {
BasicConfigurator.configure();
log.warn("Error writing log4j.properties, falling back to defaults.");
log.warn(e);
log.warn("STACK TRACE:");
int i = 0;
StackTraceElement[] trace = e.getStackTrace();
while (i < trace.length) {
log.warn(trace[i]);
i++;
}
}
}
Related
Java programmer here.
I'm trying to make a "plugin system" in java, and I would like ot make it so that the user can import their own java libraries if they needed to so they are not limited to only have my plugin loading application in their build path.
I was planning on allowing the user to make a folder called "lib" in their project, which is where they would put all the other libraries they needed, so they can then add those to the build path with the application erroring when loading all the necessary plugins. But, I am having trouble to do so.
Here is an example plugin jar file I have, that is structured the way I want it to be:
Plugin.jar
|---org
|---pluginpackage
|---PluginMainClass.class
|---lib
|---user-lib.jar
|---libpackage
|---InterfaceA.class
|---ClassB.class
|---...
|---plugin-description.xml
What I was wondering is this: What would be the most efficient way to load all the libraries the user has loaded inside the "lib" folder?
This is the current code I have, but it takes longer than desired to load the libraries:
private void readLibraryInJar(JarInputStream jarLibraryInputStream, File dirOut) throws IOException {
if (jarLibraryInputStream == null)
return;
JarEntry entry = null;
while ((entry = jarLibraryInputStream.getNextJarEntry()) != null) {
final String jarPath = entry.getName().trim();
if (jarPath.endsWith(".class")) {
File f = new File(dirOut, jarPath);
if (!f.exists()) {
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
f.createNewFile();
}
byte[] buffer = new byte[1024 * 100];
FileOutputStream out = new FileOutputStream(f);
int len;
while ((len = jarLibraryInputStream.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
out.close();
}
}
}
The above code reads each class file inside the desired library and copy's its content's into a new file. I know that a more efficient way is out there somewhere (e.g. Apache Tomcat project can have a "lib" folder), so I was wondering if I could load the library jar file more effeciently than I currently do (planning on using URLClassLoader to load it, so if you could transform it into a URL that would be awesome, but if that is impossible, I am still okay with any way more efficient than my current one.)
Thanks in advance!
I am trying to extract few files contained in the java project into a certain path, lets say "c:\temp".
I tried to use this example :
String home = getClass().getProtectionDomain().
getCodeSource().getLocation().toString().
substring(6);
JarFile jar = new JarFile(home);
ZipEntry entry = jar.getEntry("mydb.mdb");
File efile = new File(dest, entry.getName());
InputStream in =
new BufferedInputStream(jar.getInputStream(entry));
OutputStream out =
new BufferedOutputStream(new FileOutputStream(efile));
byte[] buffer = new byte[2048];
for (;;) {
int nBytes = in.read(buffer);
if (nBytes <= 0) break;
out.write(buffer, 0, nBytes);
}
out.flush();
out.close();
in.close();
I think I am doing it wrong and, this code probably looking for a specific jar but not in my project directory. I prefer to figure a way that can retrieve my files from resources package, inside the project folder and extract it to specific folder i choose.
I am using Eclipse, 1.4 J2SE library.
Well, it's hard to guess what's wrong without any code examples.
But as for pair of random guesses I could tell that sometimes you get this kind of error when the file is locked by earlier instance of your program which is still running. Make sure you've got only one running instance of Eclipse.
Also you can try to refresh the project folder by right click --> refresh to sync your file system with Eclipse's internal file system: when it comes to Eclipse, multiple refresh/rebuild someway magically solves project problems :)
I want to read the file in my resource folder in my Java project. I used the following code for that
MyClass.class.getResource("/myFile.xsd").getPath();
And I wanted to check the path of the file. But it gives the following path
file:/home/malintha/.m2/repository/org/wso2/carbon/automation/org.wso2.carbon.automation.engine/4.2.0-SNAPSHOT/org.wso2.carbon.automation.engine-4.2.0-SNAPSHOT.jar!/myFile.xsd
I get the file path in the maven repository dependency and it is not getting the file. How can I do this?
You need to give the path of your res folder.
MyClass.class.getResource("/res/path/to/the/file/myFile.xsd").getPath();
Is your resource directory in the classpath?
You are not including resource directory in your path:
MyClass.class.getResource("/${YOUR_RES_DIR_HERE}/myFile.xsd").getPath();
A reliable way to construct a File instance from the resource folder is it to copy the resource as a stream into a temporary File (temp file will be deleted when the JVM exits):
public static File getResourceAsFile(String resourcePath) {
try {
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath);
if (in == null) {
return null;
}
File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp");
tempFile.deleteOnExit();
try (FileOutputStream out = new FileOutputStream(tempFile)) {
//copy stream
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
return tempFile;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
It is not possible to access resources of other maven modules. So you need to provide your resource myFile.xsd in your src/main/resources or src/test/resources folder.
The path is correct, though not on the file system, but inside the jar. That is, because the jar was running. A resource never is guaranteed to be a File.
However if you do not want to use resources, you can use a zip file system. However Files.copy would suffice to copy the file outside the jar. Modifying the file inside the jar is a bad idea. Better use the resource as "template" to make an initial copy in the user's home (sub-)directory (System.getProperty("user.home")).
In maven project, lets assume that, we have the file whose name is "config.cnf" and it's location is below.
/src
/main
/resources
/conf
config.cnf
In IDE (Eclipse), I access this file by using ClassLoader.getResource(..) method, but if I ran this application by using jar, I always across "File not found" exception. Finally, I wrote a method which accessing the file by looking at where app works.
public static File getResourceFile(String relativePath)
{
File file = null;
URL location = <Class>.class.getProtectionDomain().getCodeSource().getLocation();
String codeLoaction = location.toString();
try{
if (codeLocation.endsWith(".jar"){
//Call from jar
Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
file = path.toFile();
}else{
//Call from IDE
file = new File(<Class>.class.getClassLoader().getResource(relativePath).getPath());
}
}catch(URISyntaxException ex){
ex.printStackTrace();
}
return file;
}
If you call this method by sending "conf/config.conf" param, you access this file from both jar and IDE.
I have a simple parsing program that takes a few files and combines them. It then generates a few output files to the working directory. When I run this program in eclipse it generates all the required output files. However, when I run it using a jar generated in eclipse it only creates two of the three output files. It makes me think something is wrong in how the jar file is generated but can't seem to find any answers to this.
I've tried updating some of the java, it was written using java 5 I believe. I just changed the Vectors to ArrayLists and the FileOutputStream to FileWriter.
I had to download javax.mail to get the required libraries and added those jar files to the java6 library I was using in Eclipse. I've tried deleting the classes and generating new classes. I tried to check the permissions on the jar file to make sure that I had access with it. I guess I am just not sure where to start.
I've also tried packing this as a jar file and not as a runnable jar file because it gave me more options on what to include. However, I could not run this type of jar file even though it was an executable. I've recreated the jar file numerous times without any luck.
There were quite a few problems people had with UTF-8 not displaying properly in a jar file but being fine in eclipse. However their jar files were generating the text files where as mine just does not generate one.
Update: Interestingly if I move the block of code to its own class and run it as a separate jar it will work. So the solution for now is to have two jar files.
This is the code for the ungenerated file:
private static void parseCRNOnly() {
try {
//file to write to
File new_file = new File("CRNOnlyClean.txt");
FileWriter out = new FileWriter(new_file);
//file to read from
File file = new File("CRNOnly.txt");
FileReader reader = new FileReader(file);
BufferedReader buf = new BufferedReader(reader);
try{
String str;
String temp = "\r";
String nl = "\r\n";
String tab = "\t";
str = buf.readLine();
while (str != null && !str.isEmpty()) {
StringTokenizer tokenizer = new StringTokenizer(str," \t");
int column = 0;
while(tokenizer.hasMoreTokens()) {
column++;
temp = tokenizer.nextToken();
if(column == 8){
break;
}
out.write(temp);
out.write(tab);
}
out.write(nl);
str = buf.readLine();
}
out.close();
} catch(IOException e0){
System.out.println("Error Reading From CRNOnly.txt");
JOptionPane.showMessageDialog(null, "Error Reading From CRNOnly.txt");
}
} catch(FileNotFoundException e1){
System.out.println("File CRNOnly.txt Not Found");
JOptionPane.showMessageDialog(null, "File CRNOnly.txt Not Found");
} catch (IOException e) {
System.out.println("Error Reading from FileWriter");
JOptionPane.showMessageDialog(null, "Error Reading from FileWriter");
}
For some reason the jar file was not including some old libraries that I had to add from javax.mail, so I tried making a jar file using netbeans instead and it worked. Netbeans didn't pack the javax.mail libraries into the jar file either but included them in a file with the jar file. Therefore to use the jar file this file must be in the directory as well.
Basically my problem is a that I need to copy an uploaded file (which is placed in a temporary folder on my server providers Tomcat ie. not a local Tomcat).
The code I'm using works when I deploy my project on my local machine but stops working when I deploy it live.
I've found out that it has something to with my permissions in java.policy.
What I need to find out is how do I get access to the folder in which Tomcat stores the temporary file using Java.
When reading catalina.out this is the clue that the log gives me.
/usr/local/tomcat/work/Catalina/project name here/context of project here/upload_490341a6_12b1d397355_76ce_00000001.tmp
I'm thinking somewhere along the lines (note: this is not an actual method :P )
ServletActionContext.getContext().getSuperHiddenTemporaryCatalog();
The code snippet at the bottom has one flaw.
sourceFile and targetFile points to the same directory at the moment.
I want the sourceFile path to be the temporary tomcat-folder.
Thanks in advance! :D
public String saveImage(File file, String uploadedFileName) {
String path = ServletActionContext.getServletContext().getRealPath("images");
System.out.println(path);
String fullFileName = path + "/" + uploadedFileName;
System.out.println(fullFileName);
boolean successful = false;
try {
File sourceFile = new File(fullFileName);
File targetFile = new File(path + "/" + uploadedFileName);
InputStream in = new FileInputStream(sourceFile);
OutputStream out = new FileOutputStream(targetFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
} catch (Exception e) {
successful = false;
e.printStackTrace();
}
if (successful) {
return "context of project/images/" + uploadedFileName;
} else {
return "";
}
}
File tempDir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
should give you access to your temporary directory in Tomcat. It would be strange if you could not at least read files from there.
The code I'm using works when I deploy my project on my local machine but stops working when I deploy it live. I've found out that it has something to with my permissions in java.policy.
Yes. This is an example of a Java security sandbox.
What I need to find out is how do I get access to the folder in which Tomcat stores the temporary file using Java.
You cannot circumvent the security sandbox (modulo some unpatched bug in your JVM). What you need to do is change the "java.policy" settings so that your webapp has permission copy the file to where it needs to be copied. You may need to discuss this with whoever has done the security design, etc for your production Tomcats.