Launching phantomjs as a local Resource when using an Executable Jar - java

Need a little bit of help with this one.
My goal is to have an executable jar file that takes a screen-capture of a webpage and works on both windows and linux machines. I have tried using html2image but the results from phantomjs were exponentially better.
I have code that looks like this:
RESOURCE_PATH = MyClass.class.getClassLoader().getResource("resources").getPath();
public static void main (String[] args) {
String url = args[1];
String outFilePath = args[0];
final String phantomjsHome = RESOURCE_PATH + "/phantomjs/";
ProcessBuilder pb = new ProcessBuilder(phantomjsHome + "phantomjs.exe", phantomjsRasterizeScript, url, outFilePath);
Process process = pb.start();
process.waitFor();
}
Now I have tests which assure me when I'm running this as a java application it works fine but when I build an executable jar I get an error. I have checked and double checked that the RESOURCE_FOLDER is pointing at the correct location. But when I run the jar using
java -jar MyProject.jar "google.png" "https://google.com"
I get a
java.io.Exception: Cannot run program "file:/C:/Users/Joe/MyProject.jar/resources/phantomjs.exe": CreateProcess error=2, The system cannot find file specified
By the way this is my first time asking a question on SO, so if you need additional info or have any suggestions or comments on phrasing comment with some feedback. Thank You!
UPDATE
After some more searching I found that an executable could not be executed from within the jar. I have created a method to copy the executable to outside the jar which seems to work.
private static String loadPhantomJS() {
String phantomJs = "phantomjs.exe";
try {
InputStream in = WebShot.class.getResourceAsStream("/resources/phantomjs/" + phantomJs);
File fileOut = new File(storePath + phantomJs);
OutputStream out = FileUtils.openOutputStream(fileOut);
IOUtils.copy(in, out);
in.close();
out.close();
return fileOut.getAbsolutePath();
} catch (Exception e) {
return "";
}
}
please note that this method only works for windows machines, change the file path for linux.

The above method works for Windows machines, note though that any file you want to run must also exist unpacked, outside the jar file. A similar method to loadPhantomJS can be used to unpack other resource files from the jar file. I used this method:
private static void makeLocalFile(String outPath, InputStream is) {
try {
InputStream is;
File fileOut = new File(outPath);
OutputStream out;
out = FileUtils.openOutputStream(fileOut);
IOUtils.copy(in, out);
in.close();
out.close();
} catch (Exception e) {
System.out.println(e);
}
}
I get an InputStream from my resources using, MyClass.class.getResourceAsStream("jsFile.js"). The only way I was able to get it to work so far on linux is by actually installing phantomjs the linux instillation first. Will update this answer if/when I find a better solution.

Related

Export in standalone app not working while functionning in Eclipse

I'm working on a standalone app where results are exported in an excel sheet. I use Jxls for the export. All is working in Eclipse, but the exported jar just gives me a non-working sheet. Is it a problem with the output stream that doesn't write anything, or is it something with the absolute path? I'm a bit confused here.
The export is made with the required libraries packed in the jar.
The code of the exporting part :
private void exportDataDet(File file) throws ParseException, IOException, ParsePropertyException, InvalidFormatException {
String path = System.getProperty("user.home") + File.separator + "tempFile";
File IdGenreXLS = new File(path + ".xlsx");
List<ResultsDetails> detRes = generateResultsDetails();
try(InputStream is = IdGenre.class.getResourceAsStream("/xlsTemplates/IdGenre/IdGenre_20-29-et=12.xlsx")) {
try (OutputStream os = new FileOutputStream(IdGenreXLS)) {
Context context = new Context();
context.putVar("detRes", detRes);
JxlsHelper.getInstance().processTemplate(is, os, context);
}
}
Thanks for any suggestion.
Alright, the hypothesis that nothing was written on disk was the good one, as eventually nothing was written on disk.
A simple
os.flush();
at the end makes everything working. There's nothing for it but to close the input and output stream after.

how to read .properties file from particular location using java in linux os

Hi all I am having 2 jar files(read.jar, write.jar) in the following folder structure:
app/read/read.jar
app/write/write.jar
The write.jar writes the values to the properties file present in app/important.properties and the read.jar reads from the app/important.properties. In the Java code I am calling the properties file using
FileOutputStream out = new FileOutputStream("/app/important.properties");
This is working fine in Windows OS, but when I put this app in Linux OS in /home/workspace/app a FileNotFoundException is thrown. Then I changed the reading of file to:
FileOutputStream out = new FileOutputStream("./important.properties")
which also produced a FileNotFoundException. Can anyone help me please? Thanks.
FileOutputStream will create the file if it does not exist but it will not create any directory parts and fail with an FileNotFoundException if the directory does not exist. You should check if the directory exist or not before writing.
Also check the write permissions on that directory in unix.
Do it like this:
public static void loadProperFile(String fileName){
try {
String url=ReadProperties.class.getResource("/").toURI().getPath();
String path=url+fileName;
properties.load(new FileInputStream(path));
} catch (Exception e) {
log.error(e.getMessage());
}
}
It works on mac and linux.I hope this will help you!

Unzipping an archive won't work when using Java, works in Terminal - Linux

I'm trying to unpack/extract an archive, which is supplied in my program, containing binaries.
The copy from within the jar to the file works just fine, but when I try to extract the zip, it returns unexpectedly and only copies half of a file, and ignores the other file completely.
Here's a bit more detailed description:
I'm trying to unzip an archive copied to a folder, from within the program's .jar.
The program I'm using to unzip is "unzip" (comes with Linux).
The command used to extract is:
unzip -o <file>.zip
which is exactly what I'm using in following code:
ProcessBuilder process = new ProcessBuilder();
process.command("unzip", "-o", adb_tools.toString());
process.redirectErrorStream(true);
Process pr = process.start();
String line;
BufferedReader processReader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
while ((line = processReader.readLine()) != null)
log(Level.INFO, "Extracting Android Debugging Bridge: " + line, true);
log(Level.INFO, "Android Debugging Bridge has been extracted and installed to system. Marking files as executable...", true);
pr.destroy();
processReader.close();
When I use the command directly via the Terminal, everything works fine, both files are extracted and inflated, and are executable, however, as mentioned above, when I use the command in Java, only one file gets copied (and even that only goes half way), and the other file is completely ignored.
How can I fix this problem, and prevent this happening again, with different programs?
Thanks in advance!
If you need to do a common task in Java, there is always a library out there which does what you need better than yourself. So use an external library for unzipping. Check here:
What is a good Java library to zip/unzip files?
It looks like you can use zip4j like this (from djangofan's answer):
public static void unzip(){
String source = "some/compressed/file.zip";
String destination = "some/destination/folder";
String password = "password";
try {
ZipFile zipFile = new ZipFile(source);
if (zipFile.isEncrypted()) {
zipFile.setPassword(password);
}
zipFile.extractAll(destination);
} catch (ZipException e) {
e.printStackTrace();
}
}

How to get the download file path on linux?

I have finished developing a java web app using spring and hibernate. In my app, there's a download function. The function runs well on windows env. But when I deploy and run the app on linux env, using Tomcat as the server, the function return zero byte file. The file type is excel (xls). But the browser returns this as pdf file.
Download Function Failed:
Xls File Path on Linux:
and here is the code:
#RequestMapping("downloadXlsTemplate")
public String downloadTemplate(HttpServletRequest request, HttpServletResponse response) {
try {
String filename = "Template.xls";
File onLinux = new File("/opt/tomcat7/webapps/xls/" + filename);
response.setContentType("application/vnd.ms-excel");
response.addHeader("Content-Disposition", "attachment; filename=" + filename);
response.setContentLength((int) onLinux.length());
InputStream inputStream = new FileInputStream(onLinux);
OutputStream responseOutputStream = response.getOutputStream();
int bytes;
while((bytes = inputStream.read()) != -1) {
responseOutputStream.write(bytes);
}
inputStream.close();
responseOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
I have tried various ways, but none were successful.
I will really appreciate any idea, help, or solution
Regards
Yunus
The problem you are facing is a file permission problem. The file is owned by 'root' and your tomcat runs on other user.
Try to move the files to a shared location where the tomcat user can access it. Try the /tmp location or any other shared location.
If it is permission issue, try using chmod unix command giving required permission on file .
e.g., chmod u+rwx
As a good practice, try to refer the file using relative path (using class path resource) instead of absolute path (so it is environment independent).

Sams Teach Yourself Java in 24 Hours 6th Ed. Chap. 20 ConfigWriter.java error

Sams Teach Yourself Java in 24 Hours Sixth Edition by Rogers Cadenhead Chapter 20 ConfigWriter.java error
I am a Java beginner. I am going through the Java book listed in the title of this post. I am super stumped at how this cannot work. The code is supposed to create a file called program.properties and put the text in lines 10 through 12 in it.
import java.io.*;
class ConfigWriter {
String newline = System.getProperty("line.separator");
ConfigWriter() {
try {
File file = new File("program.properties");
FileOutputStream fileStream = new FileOutputStream(file);
write(fileStream, "username=max");
write(fileStream, "score=12550");
write(fileStream, "level=5");
} catch (IOException ioe) {
System.out.println("Could not write file");
}
}
void write(FileOutputStream stream, String output)
throws IOException {
output = output + newline;
byte[] data = output.getBytes();
stream.write(data, 0, data.length);
}
public static void main(String[] arguments) {
ConfigWriter cw = new ConfigWriter();
}
}
Instead it does absolutely nothing. Its completely blank. I would most appreciate any help at all with this error!
There is no error or exception in your code. The snippet actually created the file. Try testing the src by giving a test path.
File file = new File("C:\\Test\\test.txt");
The above modification created the file properly. And as was mentioned, you can use fileStream.flush(); too.
The most likely problem is that you are confused about where the file will be written.
If you write to a file using a relative pathname (like "program.properties"), Java will attempt to open / create the file in the application's "current directory".
If you run the code directly from the command prompt / shell, the current directory will be the shell's current directory ... at the point that you ran the program.
If you launch using a wrapper script, then the script could change the current directory before starting the program.
If you launch from an IDE, then the IDE determines what the current directory will be.
And so on.
To avoid this problem, use an absolute pathname.
It would also be instructive to figure out where that file was actually written. On Windows you could try using the Search tool. On Linux, the find command is a good choice; e.g.
$ sudo find / -name properties.properties | less
... and wait.
Note that flushing and closing are not necessary in this particular example. You are using a FileOutputStream which is not buffered. However, if you wanted to do that, your code would need to look like this:
File file = new File("program.properties");
try (FileOutputStream fileStream = new FileOutputStream(file)) {
write(fileStream, "username=max");
write(fileStream, "score=12550");
write(fileStream, "level=5");
fileStream.flush();
} catch (IOException ioe) {
System.out.println("Could not write file");
}
Note that the fileStream is implicitly closed because we declared it as a "resource" following the try

Categories

Resources