Accessing filesystem from java within Spring and tomcat - java

I am attempting to do some xml marshalling from with spring/tomcat ... my app is deployed as normal as a war file. The file is indeed copied to the correct location WEB-INF/classes/myData.xml but I am unsure how to access this from with Java and specifically my spring service layer. As normally I access files from with the app context itself.
I want to do this :
final File xml = new File("WEB-INF/classes/myData.xml");
but in my dev build it goes to F:\eclipse\WEB-INF\classes\myData.xml and not the deployment directory inside tomcat

In Spring, a clean way to do this with Java is using ClasspathResource:
Resource myData = new ClasspathResource("myData.xml"):
Alternatively, if this is a Spring bean doing the work, then you can inject it from XML, e.g.
<property name="myResource" value="classpath:myData.xml"/>
... assuming that myResource is a javabean property on your Spring bean of type Resource.
The WEB-INF/classes directory is automatically on the server's classpath, you don't need to (not should you) specify that in the path explicitly.
The Spring Resource interface offers various ways to get hold of the data itself (e.g. getInputStream())

If you are determined to get the path leading to your resource, you can retrieve its URL and then parse it, like this:
URL url = getClass().getResource("/WEB-INF/web.xml");
String path = url.toString();
if (path.startsWith("file:/")) {
path = path.substring("file:/".length());
File file = new File(path);
...do something with the file...
}
There is, however, a caveat: your resource may be read directly from the JAR archive, not from a flat file in your filesystem, and thus not really accessible via a File object. The above snipped worked in JBoss (which includes Tomcat), but JBoss explodes a WAR archive before deploying it - not sure if a pure Tomcat will do this as well.
The main question is: why would you really want to get the resource in the form of a File object? Maybe getting its URL is enough for you? Or maybe you just need read access?
If all you need is read access, the simplest way to get any resource on your classpath (like the above web.xml) is by simply calling:
InputStream in = getClass().getResourceAsStream("/WEB-INF/web.xml")
If you want write access to the file, a much better solution would be to pre-configure a directory (for example, via the web.xml), unpack all your needed files there (for example, via the above getResourceAsStream method) and then edit and access them from your predefined directory which is independent from your application server.

Related

Tomcat use DefaultServlet for static content in external directory

I have a simple web app that allows the user to upload and access files. When the user accesses an uploaded file, the server needs to support all of the header types such as Accept-Ranges so that partial-content responses can be made on large media files. The DefaultServlet (in Tomcat) handles everything well in its serveResource() method called by doGet(), so I would like to use the DefaultServlet for the uploaded files. This is easy enough in normal circumstances since it is the DEFAULT servlet, but unfortunately for my case, I am unable to find a way to use the default servlet.
In order to prevent the uploaded files from being deleted when the webapp is redeployed, I need to store them outside of the webapp directory.
These files should only be accessible to the user that uploaded them, so I created a javax.servlet.Filter to handle resource access authorization. I know that if I add a new context in server.xml for the external resource directory, they will be accessible, and the DefaultServlet will be used.
<Context docBase="/path/to/resources" path="/resource" />
But I do not want to do that because then I am required to invasively modify server.xml which is not recommended (for reasons), and when a context exists for the /resource path, my filter for that url-mapping will not be invoked. So I do not think creating a new context is a good solution.
The only other solution I can think of would be to create a servlet for all requests at '/resource/*' which extends DefaultServlet, and somehow override functionality that would instead get the requested file at its actual external location rather than returning 404 on the non-existent resource in the webapp.
However, I have not been able to find an easy way to convert the DefaultServlet into one that can fetch files external to the webapp directory. Maybe there is a way?
How would I go about handling this?
Not an answer
In order to prevent the uploaded files from being deleted when the
webapp is redeployed
It means you are re-deploying your stuffs wrong(in a very bad manner), probably using war files, or worse(worst) tomcat manager.
I know that if I add a new context in server.xml for the external
resource directory, they will be accessible, and the DefaultServlet
will be used.
You are right, but you are wrong about having another context, it's not necessary.
Solutions:
Dear Michael-O specified the easiest and probably best answer.
You may also implement something like DefaultServlet too, sometimes(not for your case) it's better to implement things from zer0 rather than configuring and maintaining many too much complex stuffs.

Correct location to place the properties file for a struts web application

I am developing a Struts 2 web application, all the constant values and hardcoded values are moved to a properties file along with those, the constants which are specific to environment like Data source name, some of the server connection urls and few user ids are also placed in the properties file.
Initially I placed the properties file in the class path and accessed using resource bundle as below
ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle("config\appProps");
Problem with that is Because of those environment specific constants for ever environment(DEV / UAT / PROD) a separate war needs to be generated by changing the properties file environment specific constants value, to avoid that I am using below process
I kept the properties file absolute path in the context parameter of the web.xml and get the path from the context and reading the properties file as below
Properties prop = new Properties();
prop.load(new FileInputStream("<<file system absolute path from context param>>"));
This eliminated the process of generating different war for each environment as path on the server can be maintained same, but I came to know that security wise we should not use absolute paths like that which might expose the server file system details
Please let me know What is the correct way of loading the properties file in a web application by considering security as well as eliminating generation of different war files for each environment.
Thanks.
You could maybe hoist the whole properties object into JNDI, that would fix it, but implementations may be server specific. And now you've got a new problem; make sure that the properties are loaded before you read them.

How to store a file on a server(web container) through a Java EE web application?

I have developed a Java EE web application. This application allows a user to upload a file with the help of a browser. Once the user has uploaded his file, this application first stores the uploaded file on the server (on which it is running) and then processes it.
At present, I am storing the file on the server as follows:
try {
// formFile represents the uploaded file
FormFile formFile = programForm.getTheFile();
String path = getServlet().getServletContext().getRealPath("") + "/"
+ formFile.getFileName();
System.out.println(path);
file = new File(path);
outputStream = new FileOutputStream(file);
outputStream.write(formFile.getFileData());
}
where, the formFile represents the uploaded file.
Now, the problem is that it is running fine on some servers but on some servers the getServlet().getServletContext().getRealPath("") is returning null so the final path that I am getting is null/filename and the file doesn't store on the server.
When I checked the API for ServletContext.getRealPath() method, I found the following:
public java.lang.String getRealPath(java.lang.String path)
Returns a String containing the real path for a given virtual path. For example, the path "/index.html" returns the absolute file path on the server's filesystem would be served by a request for "http://host/contextPath/index.html", where contextPath is the context path of this ServletContext.
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).
So, Is there any other way by which I can store files on those servers also which is returning null for getServlet().getServletContext().getRealPath("")
By spec, the only "real" path you are guaranteed to get form a servlet container is a temp directory.
You can get that via the ServletContext.gerAttribute("javax.servlet.context.tempdir"). However, these files are not visible to the web context (i.e. you can not publish a simple URL to deliver those files), and the files are not guaranteed in any way to survive a web app or server restart.
If you simply need a place to store a working file for a short time, then this will work fine for you.
If you really need a directory, you can make it a configuration parameter (either an environment variable, a Java property (i.e. java -Dyour.file.here=/tmp/files ...), a context parameter set in the web.xml, a configuration parameter stored in your database via a web form, etc.). Then it's up to the deployer to set up this directory for you.
However, if you need to actually later serve up that file, you will either need a container specific mechanism to "mount" external directories in to your web app (Glassfish as "alternate doc roots", others have similar concepts), or you will need to write a servlet/filter to serve up file store outside of your web app. This FileServlet is quite complete, and as you can see, creating your own, while not difficult, isn't trivial to do it right.
Edit:
The basic gist is the same, but rather than using "getRealPath", simply use "getInitParameter".
So:
String filePath = getServletContext().getInitParameter("storedFilePath") + "/" + fileName;
And be on your way.
Edit again:
As for the contents of the path, I'd give it an absolute path. Otherwise, you would need to KNOW where the app server sets its default path to during exeuction, and each app server may well use different directories. For example, I believe the working directory for Glassfish is the config directory of the running domain. Not a particularly obvious choice.
So, use an absolute path, most definitely. That way you KNOW where the files will go, and you can control the access permissions at the OS level for that directory, if that's necessary.
Writing to the file system from a Java EE container is not really recommended, especially if you need to process the written data:
it is not transactional
it harms the portability (what if you are in a clustered environment)
it requires to setup external parameters for the target location
If this is an option, I would store the files in database or use a JCR repository (like Jackrabbit).

Passing parameters to AXIS web service

I have an AXIS servlet which deployed on an apache tomcat server on windows.
I wrote a web service which I want to run on AXIS.
When I want to deploy my web service, I make a jar file from the classes, and then I copy them to "axis\WEB-INF\lib" directory. Then I deploy the web service using a wsdd file.
My question is - how can I pass parameters to the web service, and how can I read them?
The only web.xml file that I have, is the AXIS web.xml file. Should I put them there?
I came across with exactly same issue. I have a not so perfect solution. I am using a properties file to store params and access this properties file in the service classes. I am facing problem when I put all my classes in to a jar file. I am able to access properties file in my service class if I place properties file inside the jar file. I am unable to access properties file (without hardcoding the path) when I place it outside jar file. For maintainance point of view it is good practice to keep properties file accessible easyly.
-Rao

What is the best way to allow both a servlet and client-side scripts read the same file?

We want to share user validation configuration between a Java validation class (for sanity checking) and a Javascript-enabled form web interface (for usability). What's the best way to deploy this static file in our web application so that it is both available to the server-side code, and available via a URL accessed by the client?
So far I've thought of putting the file in the application root and pointing the validation class at it when it is used, and putting the file in the WEB-INF/classes directory and somehow configuring the container to serve it.
Has anyone else configured a web application like this? What did you end up doing?
Yeah. Put it in the WEB-INF/classes and have a servlet serve out the relevant portion of the validation configurations based on something like a form-id. Better yet, have the servlet transform the configuration into a JSON object and then you can simply include a script tag and start using it :)

Categories

Resources