I am writing an upload and a download function, and I try to have this two methods to write to or read from the same folder, and I ran into some problem with getResourceAsStream. (The software is run on glassfish)
upload: The method upload to this folder: /home/phamtn8/glassfishv3/glassfish/domains/domain1/applications/Documents/Documents-war_war/drawings/Liandro.jpg --> work great
download: stream = the above path
input = this.getClass().getResourceAsStream(stream); //This return null
The location of the class files that contain these upload and download methods is at:
/home/phamtn8/glassfishv3/glassfish/domains/domain1/applications/Documents/Documents-war_war/WEB-INF/classes/org/xdrawing/web. If I put the jpg file here, the getResourceAsStream work.
NOTE: this.getClass.getName() return org.xdrawing.web.FileName
Please help !!!
getResourceAsStream(..) treats paths from the root of the classpath. And yours seems to be the root of the machine. So use new FileInpuStream(fullPath) instead.
In fact, there is another getResourceAsStream method that belongs to the ServletContext. It treats paths from the root of the web application, and is more suitable for web applications. (your web app root is Documents-war_war/)
But the best practice with file uploads and downloads is to store them in a totally different location from your web application - say /home/appname/uploads, so that you can deploy and undeploy the web-app without losing any data. You will just need a configuration option (a <context-param> in web.xml for example) that points to the absolute location of the uploads, and use the FileInputStream approach (or OutputStream respectively)
Related
I use web fragments (servlet 3 spec) and thus can load e.g. META-INF/resources/access.xml file which is in a library in /WEB-INF/lib/ of my WAR via ServletContext.getResourceAsStream("access.xml").
Doing the same with ServletContext.getRealPath("access.xml") doesn't work (=> null).
The spec states:
The getRealPath method takes a String argument and returns a String representation of a file on the local file system to which a path corresponds. Resources inside the META-INF/resources directory of JAR file must be considered only if the container has unpacked them from their containing JAR file when a call to getRealPath()
is made, and in this case MUST return the unpacked location.
My container (Tomcat) didn't unpack the jars, this seems to be the problem? How can Tomcat unpack the jars. Should I unpack the jars when packaging the WAR?
So it depends on what you are trying to do. If you are trying to get the location of the file in the included library dependency, then I am not sure. If you are wanting to read the contents of the access.xml file then you can use
new InputStreamReader(context.getResourcesAsStream("access.xml"));
and then work with the InputStreamReader to get the file's contents.
Yes, getResourcesAsStream() always works. But getRealPath() doesn't.
Answer: Don't try to use getRealPath() together with web fragments.
How do you read a .jks file from a rest web application deployed with Tomcat server ? I am using FileInputStream to read the file. I am currently having difficulty dealing with the relative paths used to read a file in a web application. I know the file will be under WEB-INF/classes. What will be the best way to read the file using FileInputStream. I know using classLoader. but then it returns the InputStream.
It is a bad practice to use direct file access (FileInputStream) for reading resources that are bundled with the application; the reason is that it leads to precisely the sort of problems like you're experiencing. In a managed runtime environment, the developer has very little control over the paths where resources are actually located.
For servlet-based applications (which you are using, as you mentioned that you're using Tomcat), the best way to go about it is to use the context classloader:
Thread.currentThread().getContextClassLoader()
and load the resource from there, getting an InputStream. In other words - you're doing things correctly at the moment. Don't use FileInputStream. Unless you have an absolutely good reason for doing so, in which case I'm going to be extremely surprised.
The best way to access files which are not bundled with EAR / WAR is to use java.util.Properties. I am sure that files like jks files are never bundled with EAR , they are in domain folder of the server or server dir ( weblogic , websphere.). Properties file should be placed on file location independent of the server installed directory.
Here is the solution I can think of :
1. Initialize a Servlet with init-param in web.xml
2. The init-param can be the absolute file location
<param-name>porperies-file</param-name>
<param-value>/usr/properties/abc.jks</param-value>
3. In the static block of the Servlet , load the properties file / jks
file and store it in parameter
This look complex but many frameworks give the option of locating files like ResourceBundle files through Absoulute path. Check the documentation for Spring's FileSystemResourceLoader.
The advantage of such a process is if the "jks" file changes you just need to start the server. In the case where you have the propeties file in EAR , you need to deploy the application and then restart the server. Consider this also , you can have logic to check the freshness of the file. In this case the system need not be re-started at all but you have to put extra bit of logic of synchronization.
if you make a KeyStore(w/o password,and defaultType)
InputStream is = this.getClass().getClassLoader().getResourceAsStream("jskFileName");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(is, null);
but FileInputStream is really good if you...
Please note that when you use the cluster servers.
for example
/contextPath
/WEB-INF
/pathA/
/sample.jks
ServletContext sc
String path="/pathA/sample.jks";
String realPath = sc.getRealPath(path);
FileInputStream fis = new FileInputStream(new File(realPath));
I would like to create an xml file and store in a folder within my spring Mvc web application.
I can get the root of my application with request.getContextPath()
but
how do i get the application's relative path so it will work on any machine indipendently by the location of the application's folder?
Like C:/folder/folder/MYAPPLICATIONROOTFOLDER
You want to do this.
First, you need to get the ServletContext. I don't know how this is done in Spring MVC, but it's there somewhere.
Then you can do:
ServletContext ctx = getServletContextFromSpringSomehow();
String path = ctx.getRealPath("/folder/filename.txt");
FileWriter fw = new FileWriter(path);
The key here is ServletContext.getRealPath. It gives you the local file system path of a resource from within your webapp. Observer that you use "/" here, as it's a URL, not a file name. The container will give you a valid file name in return. Note, this only works if your container explodes your WAR, or you deploy an exploded WAR. If the WAR is NOT exploded, you will get a null back from the container.
Also note, this WILL work for non-existent files. The container does not check for the actual existence of the file. But it will be up to you to actually create any missing intermediate directories, etc.
Finally, of course, that even if you get a file path back, doesn't mean you can actually write to that path. That's a OS permission issue outside of the scope of the container.
One solution is to bundle the XML with the clases in the JAR/WAR and then use the getResourceAsStream() to leverage the ClassLoader to locate the file.
If I put the file foo.xml with the classes in com/stackoverflow/example, I could then locate the resources from objects in that bundle with
InputStream is = MyClass.getResourceAsStream( "com/stackoverflow/example" );
and from here process the file with a XML parser or whatever else you wanted to do to read the file.
i want to create a photo album.
But I want to organize on the server the albums so I want to create new folders :
/myapp
/myapp/albums
/myapp/albums/1
/myapp/albums/2
...
How can I do that on tomcat with Grails ? It create all new folder in tomcat/bin not in tomcat/webapps/myapp/
When I had to do something similar I defined a root path in my Config.groovy like
environments {
production {
rootPath="/home/user/reports"
}
development {
rootPath="c:\\reports"
}
test {
rootPath="c:\\reports"
}
Then create a directory like the following.
import org.codehaus.groovy.grails.commons.ConfigurationHolder as Conf
tempFile=new File(Conf.config.rootPath+"dirName")
tempFile.mkdir()
I don't do Grails, but since it runs on top of the Servlet API, you may find this answer (a steering in the right direction) useful as well.
First, get a handle of the ServletContext. Normally you would use the GenericServlet-inherited getServletContext() method for this. Then make use of the ServletContext#getRealPath() method to convert a relative web path to an absolute local disk file system path (because that's the only which java.io.File reliably understands).
String absolutePath = getServletContext().getRealPath("albums/1");
File file = new File (absolutePath);
// ...
If you use relative paths in java.io.File stuff, then it will become relative to the current working directory which depends on the way how you startup the server and which indeed may be Tomcat/bin as you experienced yourself.
That said, there's another major problem with this approach: if you create folders in an exploded webapp, they will get lost whenever you redeploy the webapp or even restart the server! Rather create folders outside the webapp's context, in a fixed path somewhere else at the disk file system. Or if you want better portability (but poorer metadata information), then consider storing it in a database instead.
I want to read a file from a java web application. I don't want to give the absolute path of the file. I just want to put the file in some directory of my web application.
Or
It can be placed along with .war file (packaged web application).
What relative path to give for the file. I tried ./filename.csv but it didn't work.
========Updated========
I will deliver a WAR file (packaged web application) to my client. This web application will read a file (lets say SuppliedFile.csv) which will be copied to the server by the client. So I need a mechanism (that will work irrespective of whether the application server will unpak the WAR or not) so that web application can read that file.
Note:
I am not using the SuppliedFile.csv in a servlet... I am using it in a plain Java class...
Do you really need to load it from a file? If you place it along your classes (in WEB-INF/classes) you can get an InputStream to it using the class loader:
InputStream csv =
SomeClassInTheSamePackage.class.getResourceAsStream("filename.csv");
You may be able to simply access a pre-arranged file path on the system. This is preferable since files added to the webapp directory might be lost or the webapp may not be unpacked depending on system configuration.
In our server, we define a system property set in the App Server's JVM which points to the "home directory" for our app's external data. Of course this requires modification of the App Server's configuration (-DAPP_HOME=... added to JVM_OPTS at startup), we do it mainly to ease testing of code run outside the context of an App Server.
You could just as easily retrieve a path from the servlet config:
<web-app>
<context-param>
<param-name>MyAppHome</param-name>
<param-value>/usr/share/myapp</param-value>
</context-param>
...
</web-app>
Then retrieve this path and use it as the base path to read the file supplied by the client.
public class MyAppConfig implements ServletContextListener {
// NOTE: static references are not a great idea, shown here for simplicity
static File appHome;
static File customerDataFile;
public void contextInitialized(ServletContextEvent e) {
appHome = new File(e.getServletContext().getInitParameter("MyAppHome"));
File customerDataFile = new File(appHome, "SuppliedFile.csv");
}
}
class DataProcessor {
public void processData() {
File dataFile = MyAppConfig.customerDataFile;
// ...
}
}
As I mentioned the most likely problem you'll encounter is security restrictions. Nothing guarantees webapps can ready any files above their webapp root. But there are generally simple methods for granting exceptions for specific paths to specific webapps.
Regardless of the code in which you then need to access this file, since you are running within a web application you are guaranteed this is initialized first, and can stash it's value somewhere convenient for the rest of your code to refer to, as in my example or better yet, just simply pass the path as a paramete to the code which needs it.
If you have a path for that file in the web server, you can get the real path in the server's file system using ServletContext.getRealPath(). Note that it is not guaranteed to work in every container (as a container is not required to unpack the WAR file and store the content in the file system - most do though). And I guess it won't work with files in /WEB-INF, as they don't have a virtual path.
The alternative would be to use ServletContext.getResource() which returns a URI. This URI may be a 'file:' URL, but there's no guarantee for that.
Many popular Java webapps, including Jenkins and Nexus, use this mechanism:
Optionally, check a servlet context-param / init-param. This allows configuring multiple webapp instances per servlet container, using context.xml which can be done by modifying the WAR or by changing server settings (in case of Tomcat).
Check an environment variable (using System.getenv), if it is set, then use that folder as your application data folder. e.g. Jenkins uses JENKINS_HOME and Nexus uses PLEXUS_NEXUS_WORK. This allows flexible configuration without any changes to WAR.
Otherwise, use a subfolder inside user's home folder, e.g. $HOME/.yourapp. In Java code this will be:
final File appFolder = new File(System.getProperty("user.home"), ".yourapp");
The alternative would be to use ServletContext.getResource() which returns a URI. This URI
may be a 'file:' URL, but there's no guarantee for that.
You don't need it to be a file:... URL. You just need it to be a URL that your JVM can
read--and it will be.
there is another way,
if you are using a container like Tomcat :
String textPath = "http://localhost:8080/NameOfWebapp/resources/images/file.txt";