Opening PDF file stored in resources folder raises Exception - java

I wrote a program in which a pdf file should be opened on an Action Event (you can have a look at my code below).
menuElementHilfe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
File hilfe = new File ("src\\resources\\Hilfe.pdf");
try {
java.awt.Desktop.getDesktop().open(hilfe);
} catch (IOException e) {
e.printStackTrace();
}
}
});
If I execute the program via Eclipse everything works, but after exporting as a runnable jar I get following Exception:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: The file: src\resources\Hilfe.pdf doesn't exist.
Any Feedback is appreciated

The way you're retrieving resources may be the problem. try this :
menuElementHilfe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
File hilfe = new File(getClass().getResource("/resources/Hilfe.pdf").getFile());
try {
java.awt.Desktop.getDesktop().open(hilfe);
} catch (IOException e) {
e.printStackTrace();
}
}
});
When running in Eclipse, you are targeting a file in your build path.
When running from JAR/WAR, the URL is different and look like "jar:file:/your-path/your-jar.jar!/Hilfe.pdf" which is not what you set when calling new File(...) So to get the right URL for internal resources, you have to use methods like getResource or getResourceAsStream depending on your needs.
Check out following explanations for more information :)
https://docs.oracle.com/javase/8/docs/technotes/guides/lang/resources.html
[EDIT]
I assume you're working on some Swing app, but I dont know if you're aware that doing some task like that in your AWT-EventQueue thread will freeze your UI.
To prevent that you have to run UI-unrelated stuff in another thread.
This is made using SwingUtilities.invokeLater (Java 5 and prior) method and/or the SwingWorker class (since Java 6).
as mentionned in this answer
You should put the previous solution in something like that :
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Your UI unrelated code here
}
});

The resource can be packed in the application jar, hence File (physical disk file)
is not possible. Copy it to a temporary file, so that the desktop can open it.
menuElementHilfe.addActionListener(evt -> {
Path tmp = Files.createTempFile("hilfe-", ".pdf");
Files.copy(getClass().getResourceAsStream("/Hilfe.pdf"), tmp);
try {
Desktop.getDesktop().open(tmp.toFile());
tmp.toFile().deleteOnExit();
} catch (IOException e) {
e.printStackTrace();
}
});
An other difference is the forward slash, and that the path is case-sensitive, opposed to Windows File.
After problems
menuElementHilfe.addActionListener(evt ->
SwingUtilities.invokeLater(() -> {
Path tmp = Files.createTempFile("hilfe-", ".pdf");
Logger.getLogger(getClass().getName()).log(Level.INFO, "actionPerformed "
+ tmp + "; event: " + evt);
Files.copy(getClass().getResourceAsStream("/resources/Hilfe.pdf"), tmp);
try {
Desktop.getDesktop().open(tmp.toFile());
//tmp.toFile().deleteOnExit();
} catch (IOException e) {
Logger.getLogger(getClass().getName()).log(Level.WARN, "Error with " + tmp,
e);
}
}));
I did not delete, so the Desktop access can live longer than the java app.
I did an invokeLater in order to have no frozen GUI on the actionPerformed.
I added logging to see every call to actionPerformed

Related

Move and replace file in a loop problem showing is being used by another process problem

I'm creating every time a file moving and replacing it from source folder to a destination folder with the same name
in a loop and this is the problem :
For the first move and replace, it works well then it yells the process cannot access the file because it is being used by another process. when replacing the file in the destination folder
and this is the method moving the file and replacing it every time
public static void moveAndReplaceFile(String source, String destination) {
try {
Files.move(
Paths.get(source),
Paths.get(destination),
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
LOGGER.error("Fail when moving and replacing");
}
}
can you help me guys? thanks in advance
If its a network storage that you are using, then this can happen. As a workaround, you can try adding a sleep of 60seconds before executing the Files.Move API.
I suggest you to add the ATOMIC_MOVE option if supported :
public static void moveAndReplaceFile(String source, String destination) {
try {
Files.move(
Paths.get(source),
Paths.get(destination),
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.ATOMIC_MOVE);
} catch (IOException e) {
LOGGER.error("Fail when moving and replacing");
}
}
See : https://docs.oracle.com/javase/tutorial/essential/io/move.html

Why should I use Platform.runlater on javafx main thread in this code?

I'm making java application with javaFx ui in kind of tiny machine. I wanted to show loading page, and load data files during the progress indicator going on.
I know it could work well if I added Platform.runlater on the code loading fxml file and controller, but it's weird for me to use Platform.runlater on javaFx main app thread. I checked threads' name but they were same. Also it works if it run separately using annotation.
Why do i need to use Platform.runlater ?
If I don't add that, loading image turns white screen and skip image, and just show menu view.
//Process
//1. Set loading page image
//2. Load data files
//3. Load next page(menu)
public void loadHomeMenuPage() {
setLoadingImage();
execLoadingData();
execLoadingView(this);
}
private void setLoadingImage() {
System.out.println("Load -> " + Thread.currentThread());
File file = new File("Resources/images/load.png");
InputStream is;
try
{
is = new FileInputStream(file);
this.logoImageView.setImage(new Image(is));
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
}
private void execLoadingData() {
// load openCv files
new LoadOpenCV();
// load protocol files
new ProtocolLoader().load();
// load language pack here
}
private void execLoadingView(IController loadController) {
//Load homeMenu after loading all data
//Platform.runLater(() -> {
System.out.println(Thread.currentThread());
IController controller = (IController) FxmlUtils.LOAD
.fxmlPath(PathFxml.ABS_PATH_HOME_MENU_VIEW)
.pane("BorderPane")
.set2BaseBorderPane(this.baseBorderPane, "center")
.exec();
controller.setBaseBorderPane(this.baseBorderPane);
//});
}

Resources not being released

We have a legacy system that has a admim module that allows users to upload jar files. After the upload, the jar file is validated and if not compliant to internal rules, it is deleted.
The problem is that windows is throwing an exception telling that the file "is already being used by another process." (when I call Files.delete(tmpJar);). I'm not able to identify why the file is open. Seems to me that I have closed everything.
First, we are using primefaces (4.0) to upload the file. Primefaces relies on commons-fileupload (1.3.1). It call the following method:
public void handleFileUpload(FileUploadEvent event) {
Path tmpJar = null;
try {
tmpJar = Files.createFile(Paths.get(event.getFile().getFileName()));
Files.write(tmpJar, event.getFile().getContents());
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
if (tmpJar != null) {
try {
this.validateJar(tmpJar.toString());
Files.delete(tmpJar);
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
Before NIO Files.write, I was using "standard" java IO classes. The problem isn't related to the above code, because if I comment the call to validateJar, Files.delete(tmpJar) is executed without problems and the file is removed. So, the problem is related with the code below, but I can't find where...
Job is an internal class, basically a simple POJO. "jobAnnotation" is a custom annotation to identify Jobs. I have shortened the code, but the essencial parts are preserved.
private List<Job> validateJar(final String jarPath) throws IOException {
List<Job> jobs = new ArrayList<Job>();
try (JarFile jarFile = new JarFile(jarPath)) {
URL[] jars = { new URL("file:" + jarPath) };
ClassLoader jobClassLoader = URLClassLoader.newInstance(jars, this.getClass().getClassLoader());
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String className = jarEntry.getName();
Class<?> classToLoad;
try {
classToLoad = Class.forName(className, true, jobClassLoader);
} catch (Exception e1) {
LOGGER.error(e1.getMessage(), e1);
continue;
}
if (classToLoad.isAnnotationPresent(jobAnnotation)) {
String vlr = null;
try {
Class<?> jobClass = (Class<?>) Class.forName(classToLoad.getCanonicalName(), true, jobClassLoader);
Annotation annotation = jobClass.getAnnotation(jobAnnotation);
Method method = annotation.getClass().getMethod("getValue");
vlr = ((String) method.invoke(annotation, new Object[0]));
} catch (Exception e1) {
LOGGER.error(e1.getMessage(), e1);
}
Job job = new Job();
job.setEnabled(true);
job.setJarfile(jarPath);
job.setClassName(classToLoad.getName());
Parameter parameter = new Parameter();
parameter.setRequired(true);
parameter.setName("name");
parameter.setValue(vlr);
job.addParameter(parameter);
jobs.add(job);
}
}
} catch (IOException e) {
throw e;
}
return jobs;
}
Before using try-with-resources, I was using regular try-catch-finally to close the JarFile, thats the only thing that has a explicit close method. Probably is the classloading that is holding the file open, but I don't know how to close it.
I did some searches, and I found that I can't unload classes (Unloading classes in java?).
So, the problem is, how do I release it? Or how can I remove the file?
BTW, I'm using java 1.7.0_71, jboss 7.1.1, windows 7 (64).
The URLClassLoader class already has a close() method. The close() method will close any Jar file that are opened with the URLClassLoader. This should prevent the "file already in use" exception.
File is already being used by another process. says that it could be not your fault, maybe just another application is used that file. You can check this question to find a process which is used your file.
Some Virus scanner software take a long time in checking JARs. Try to disable the Virusscanner. Other candidates can be the Windows indexer process, or the explorer.exe itself. When you don't find any reason for the file lock, try a delay between the validation and the deletion. Maybe you need a loop with multiple tries.

Java Eclipse "process" not ending after closing application

I am writing an application that displays webcam connected to my computer.
I will just write code here since the code is very simple.
public static void main(String[] args) {
JFrameImageDisplayer _window = new JFrameImageDisplayer();
//webcamGrabber _wg = new webcamGrabber();
//commented out because I am having trouble with this class.
}
JFrameImageDisplayer opens a frame, pretty much that's all it does.
When I run this code, I open a simple application with a JLabel in the frame. If I close the application, then the whole process terminates( and the process at the Windows Task Manager Process tab processes as well).
However once I create _wg, the process at the Task Manager does not terminate even after I close the application ending up just burning processing power until I manually go to process bar to end it.
Below is the construction code for the webcamGrabber.
{
OpenCVFrameGrabber _grab = new OpenCVFrameGrabber(0);
try{
_grab.start();
} catch (Exception e){
e.printStackTrace();
}
}
Well I was not so sure what do. So I manually released the resources.
protected void processWindowEvent(WindowEvent e){
if(e.getID() == WindowEvent.WINDOW_CLOSING) {
try{_wg._grab.release();}
catch(Exception ee){}
}
super.processWindowEvent(e);
}
Not the prettiest way to do it, but it works.

Accessing a PDF in Jar

I'm creating a Java application using Netbeans. From the 'Help' Menu item, I'm required to open a PDF file. When I run the application via Netbeans, the document opens, but on opening via the jar file, it isn't opening. Is there anything that can be done?
m_aboutItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Runtime rt = Runtime.getRuntime();
URL link2=getClass().getResource("/newpkg/Documentation.pdf");
String link=link2.toString();
link=link.substring(6);
System.out.println(link);
System.out.println(link2);
String link3="E:/new/build/classes/newpkg/Documentation.pdf";
try {
Process proc = rt.exec("rundll32.exe url.dll,FileProtocolHandler " + link3);
} catch (IOException ex) {
Logger.getLogger(Menubar1.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
The two outputs are as follows:
E:/new/build/classes/newpkg/Documentation.pdf
file:/E:/new/build/classes/newpkg/Documentation.pdf
Consider the above code snippet. On printing 'link',we can see that it is exactly same as the hard coded 'link3'. On using the hard coded 'link3' , the PDF file gets opened from jar application. But when we use link, though it is exactly same as 'link3', the PDF doesn't open.
This is most likely related to the incorrect PDF resource loading. In the IDE you have the PDF file either as part of the project structure or with a directly specified relative path. When a packaged application is running it does not see the resource.
EDIT:
Your code reveals the problem as I have described. The following method could be used to properly identify resource path.
public static URL getURL(final String pathAndFileName) {
return Thread.currentThread().getContextClassLoader().getResource(pathAndFileName);
}
Pls refer to this question, which might provide additional information.
Try out this:
m_aboutItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
URL link2=Menubar1.class.getResource("/newpkg/Documentation.pdf");
String link=link2.toString();
link=link.substring(6);
System.out.println(link);
File file=new File(link);
System.out.println(file);
try {
desktop.open(file);
} catch (IOException ex) {
Logger.getLogger(Menubar1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});

Categories