Applet's getCodeBase returns null - java

I have an applet, and need to open a stream to a file. This file is a local file located where the applet and HTML file are:
URL localURL = new URL(getCodeBase(), "pixs/icons.zip");
InputStream localInputStream =localURL.openStream();
It used to work fine, but after upgrading to java 1.7 build 25, getCodeBase() always return null.
This is actually documented!, Alas - there is no recommendation how to overcome it.
One things that had worked is to use full path:
URL localURL = new URL("file:c:/myFolder/pixs/icons.zip");
Is there another option to resolve that without using full path?

Perhaps you can use getDocumentBase instead. Depends on the structure of your setup, whether there is a close relation between the code base and the documents. No permanent solution: getDocumentBase was modified in the same way in 7u40, according to bug #8019177.
If not, then you can try using getResource to obtain a URL from your JAR, e.g. the class file of the applet, and then disassemble that URL to get at the location of the JAR and hence the code base. This is untested, so feel free to edit this post if you tried this.
Last but not least, since that change only affects local applets, you could run a (local or public) web server to serve that applet.
If you want a more official statement on this, I'll quote the #8017250 bug report:
If applet need to load resource:
if the resource is in applet JAR(s), they should be able to load it with ClassLoader.getResoruceAsStream directly, without needing the codebase information.
if the resource is in arbitary location, not inside applet JAR, they should have other ways to get to that location, since it's not part of the applet resource anyway. (e.g. user.home java system property, provided that their applet has all-permissions)
http://www.duckware.com/tech/java-security-clusterfuck.html (thanks to this post) mentions some other alternatives. The least likely one to be affected by future Oracle modifications apprers to be the use of location.href in the containing HTML page, e.g. writing the <applet> tag from JavaScript.

Related

Java : getClass().getResource().toURI() Vs getClass().getResourceAsStream()

I have a java multiple modules sbt project and some of them contains a resources folder.
module-1
resources
template.xls
module-2
resources
other.xls
After packaging I got :
lib/module-1.jar
lib/module-2.jar
And I run my program like any other java application : java -cp "lib/*" MainClass.
My problem is accessing the template.xls from module-2.jar.
At first, I've tried the lines below to get my template :
URI template = getClass().getResource("/template.xls").toURI();
Files.newInputStream(Paths.get(template), StandardOpenOption.READ);
In development mode it works. But not on the server (after deployment), it cannot find the resource.
java.nio.file.FileSystemNotFoundException: null
[jar:file:/.../lib/module-1.jar!/template.xls]
After some research I modified my accessing code like the following to get it works in both modes (development and deployed) :
InputStream templateIS = getClass().getResourceAsStream("/template.xls");
I cannot understand why !
What is the difference between the two methods ?
Files.newInputStream, as the name suggests, can open files. It cannot open anything else. It's just for files.
The concept of an InputStream is much more abstract. When you open a file for reading, you get an inputstream, yup. But you also get inputstreams for many other things: Reading from a network connection; reading the unpacked contents of zip files. Reading the output of a decryption operation. The name says it all really: It's input, and it's a stream of data. Which applies to so much more than 'file on a filesystem'.
Paths.get(template) produces a path object, which represents a file on the file system. If template is derived from a URI, this does not work unless the URI that you have so happens to be a URI to a file object; most URIs are not to file objects.
Putting it all together, in your first sample, you find a resource on the classpath (which can be files, but don't have to be. For example, they could be entries in a jar file), you then ask its URI, feed it to the Paths API to turn it into a Path object, and then ask the Files API to turn this into an InputStream, which only works if the URI represents a file.
In the second snippet, you just ask the classloader system to get you an inputstream. It knows how to do that (after all, java has to load those class files!). If the resource you're asking for so happens to be represented by a file, it's going to do, internally, more or less the same thing as your first snippet: Use the Files API to open the file for reading. But if it's anything else, it knows how to do that too – it also knows how to get resources across a network, from inside jar files, generated on-the-fly – the concept of class loading (which is what class.getResource lets you access) is abstracted away.
NB: You're using it wrong. The proper way is ClassYouAreWritingIn.class.getResource and ClassYouAreWritingIn.class.getResourceAsStream; getClass().getResource is not correct; that breaks when subclassing, whereas the correct form doesn't.
From docs,
The method getResource() returns a URL for the resource. The URL (and
its representation) is specific to the implementation and the JVM
(that is, the URL obtained in one runtime instance may not work in
another). Its protocol is usually specific to the ClassLoader loading
the resource. If the resource does not exist or is not visible due to
security considerations, the methods return null.
If the client code wants to read the contents of the resource as an
InputStream, it can apply the openStream() method on the URL. This is
common enough to justify adding getResourceAsStream() to Class and
ClassLoader. getResourceAsStream() the same as calling
getResource().openStream(), except that getResourceAsStream() catches
IO exceptions returns a null InputStream.
So, getResourceAsStream() the same as calling getResource().openStream(), except that getResourceAsStream() catches IO exceptions returns a null InputStream.
Your first scenario doesn't work because the template.xls is packaged within a jar file. It's not a file on the filesystem (whereas it likely is in your development env prior to packaging as a file). As such the Files API can't find it.
Class.getResourceAsStream() makes use of the classloading mechanism, and the class (obviously) is loaded from the .jar file.

Referencing a file in Eclipse without hard-coding the path?

I'm creating a dynamic web project in Eclipse where I frequently have write and read to and from an XML file. The file is in my project workspace in a folder called xml. I was wondering if Java provided some way to access the file without hard coding the file path. I've been looking around for a while for a solution but I haven't really founding anything that's really clear. Thanks!
You could just drop it in the classpath as suggested by others, but you won't be able to write to it.
Rather supply the absolute path as a VM argument or environment variable so that you don't need to hardcode it.
E.g.
-Dconfig.location=/path/to/config/file
with
File xmlFile = new File(System.getProperty("config.location"), "some.xml");
// ...
As a completely different alternative, you could consider a database.
You can get the proper path using the following from your Servlet:
String filename = getServletContext().getRealPath("/xml/config.xml");
NOTE:
getRealPath may return null if the file is inside a WAR file. In that case, if your file is in WEB_INF/classes, then you could use ServletContext.getResourceAsStream("/config.xml").
See this link:
I don't think the Servlet API gives you anything that would result in a reliable, writable, path to put work files in all containers. If your container runs the WebApp right out of the WAR, getRealPath() couldn't possibly point to something you can actually write to. I think that your only option here that is supported regardless of container is to hard code some path in the web.xml. Do it as a Context Parameter and you may be able to change it at deployment time. At the end of the day, you must declare a fully qualified path in either code or configuration to get the effect you seek.
Alternatively, do you really need to know the name of the file? In some Servlet apps I've managed to get the effect of dynamically writable storage through plain-jane java.io.file.createTempFile: http://docs.oracle.com/javase/1.4.2/docs/api/java/io/File.html#createTempFile(java.lang.String, java.lang.String)

Servlet : What exactly the use of context.getRealPath(" ");

As i know it returns the application path? But what exactly the use of it.
In many environments the application user is not allowed to read any files outside of the deployment directory. This is mostly done for security purposes - for example if someone hacks your application they won't be able to read a passwords file.
And in professionally managed environments developers often don't have a say in which directory the application will be placed.
So if you need to read a file like properties, images, certificates, etc. you can place it in the application directory (or .war file) and use getRealPath("") to get the path you need to load.
As an alternative you can place the external files on the classpath but there are sometimes issues with this. For large files most app servers will try to load the entire file into memory and cache it if it is on the classpath.
The getRealPath() gives the absolute path (on the file system) leading to a file specified in the parameters of the call. It returns the path in the format specific to the OS.
The getContextPath() on the other hand returns the URI or the relative path to the resource.
As far as I remember, I've used it to save images or other data files, since it allows you to see where your application is deployed at the moment. For example, Eclipse and Tomcat will create a temporary folder that's buried deep somewhere within your Eclipse profile and deploy the app there.
This is a real path in file system.
From javadoc:
The real path returned will be in a form appropriate to the computer and operating system on which the servlet container is running, including the proper path separators. This method returns null if the servlet container cannot translate the virtual path to a real path for any reason (such as when the content is being made available from a .war archive).
I think it is very clear. Why do we need this? Sometimes web applications perform some manipulation in file system. For example read stuff from files, write files etc. This API allows you to access the place where your JSPs and other stuff is really stored.

How to preview a file on the server in JBoss

I need some ideas on how I can best solve this problem.
I have a JBoss Seam application running on JBoss 4.3.3
What a small portion of this application does is generate an html and a pdf document based on an Open Office template.
The files that are generated I put inside /tmp/ on the filesystem.
I have tried with System.getProperties("tmp.dir") and some other options, and they always return $JBOSS_HOME/bin
I would like to choose the path $JBOSS_HOME/$DEPLOY/myEAR.ear/myWAR.war/WhateverLocationHere/
However, I don't know how I can programatically choose path without giving an absolute path, or setting $JBOSS_HOME and $DEPLOY.
Anybody know how I can do this?
The second question;
I want to easily preview these generated files. Either through JavaScript, or whatever is the easiest way. However, JavaScript cannot access the filesystem on the server, so I cannot open the file through JavaScript.
Any easy solutions out there?
Not sure how you are generating your PDFs, but if possible, skip the disk IO all together, stash the PDF content in a byte[] and flush it out to the user in a servlet setting the mime type to application/pdf* that responds to a URL which is specified by a link in your client or dynamically set in a <div> by javascript. You're probably taking the memory hit anyways, and in addition to skipping the IO, you don't have to worry about deleting the tmp files when you're done with the preview.
*****I think this is right. Need to look it up.
Not sure I have a complete grasp of what you are trying to achieve, but I'll give it a try anyway:
My assumption is that your final goal is to make some files (PDF, HTML) available to end users via a web application.
In that case, why not have Apache serve those file to the end users, so you only need your JBOSS application to know the path of a directory that is mapped to an Apache virtual host.
So basically, create a file and save it as /var/www/html/myappfiles/tempfile.pdf (the folder your application knows), and then provide http://mydomain.com/myappfiles (an Apache virtual host) to your users. The rest will be done by the web server.
You will have to set an environment variable or system property to let your application know where your folder resides (/var/www/html/myappfiles/ in this example).
Hopefully I was not way off :)
I agree with Peter (yo Pete!). Put the directory outside of your WAR and setup an environment variable pointing to this. Have a read of this post by Jacob Orshalick about how to configure environment variables in Seam :
As for previewing PDFs, have a look at how Google Docs handles previewing PDFs - it displays them as an image. To do this with Java check out the Sun PDF Renderer.
I'm not sure if this works in JBoss, given that you want a path inside a WAR archive, but you could try using ServletContext.getRealPath(String).
However, I personally would not want generated files to be inside my deployed application; instead I would configure an external data directory somewhere like $JBOSS_HOME/server/default/data/myapp
First, most platforms use java.io.tmpdir to set a temporary directory. Some servlet containers redefine this property to be something underneath their tree. Why do you care where the file gets written?
Second, I agree with Nicholas: After generating the PDF on the server side, you can generate a URL that, when clicked, sends the file to the browser. If you use MIME type application/pdf, the browser should do the right thing with it.

JAR multiple download

I have this code on an applet. The applet works ok, but I get a lot of unnecessary duplicate download. In particular, I have noticed that each "getResource" triggers a download of the .JAR file.
static {
ac = new ImageIcon(MyClass.class.getResource("images/ac.png")).getImage();
dc = new ImageIcon(MyClass.class.getResource("images/dc.png")).getImage();
//...other images
}
How can this be avoided?
Simply removing all instances of URLConnection.setDefaultUseCaches(false) will solve the problem.
Please refer for more details.
http://java-junction.blogspot.com/2009/11/applet-jar-caching-not-working.html
Do you include the applet to a HTML page? If so, try to enable the JAR caching, as is described here: http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/applet_caching.html
If that does not help for some reason :) perhaps expose your resources / images along your applet JAR on a web server and reach them using separate HTTP requests (yes, its ugly and yes, it does not reduce number of needed downloads, but it at least reduces the amount of data that need to be transferred).
Only a workaround:
You could put your images in a zip file inside the jar, get that using a ZipInputStream and extract the images from there.
Which Java VM do you use? And which Server do you use?
There is a bug in the browser plugin on Linux.
If the server does not send the modified date then Java can not cache the jar file.
If your applet always downloads the jar even though jar is cached, make sure you have not disabled the URLConnection's caching via the API: URLConnection.setUseCaches and URLConnection.SetDefaultUseCaches.
ImageIcon's underlying mechanism for fetching the resource is a URLConnection. Calling URLConnection.setDefaultUseCaches(false), sets a "part of the static state of all URLConnections" which cause the JRE to ignore the cache and redownload the entire jar every time it accessed.
Simply removing all instances of setDefaultUseCaches will solve the problem.
this is a repost from: http://java-junction.blogspot.com/2009/11/applet-jar-caching-not-working.html

Categories