Uploading and saving files in JSP - java

I'm trying to upload images in JSP using Apache Common FileUpload with Spring/hibernate. Uploading of images works well.
My project folder is located by the following path.
E:\Project\SpringHibernet\wagafashionNew\wagafashion
After parsing the request, I'm trying to save the uploaded image into the following folder.
E:\Project\SpringHibernet\wagafashionNew\wagafashion\web\images
I've tried in various ways to get this path but I couldn't succeed.
Specifying a relative path something like the following
File f=new File("wagafashion/web/images/image_file.xxx");
would not work.
Is there a way to retrieve the following path?
E:\Project\SpringHibernet\wagafashionNew\wagafashion\web\images
or specify a relative path with the new File("relative_file_path") constructor?
Am I saving files into a wrong directory? In that case in which project folder files are to be saved?

Maybe.
One way it to ask the the ServletContext to getRealPath("/web/images"), and see if that returns something -- it doesn't have to, but it likely will. If it does, then you can put the images there.
However.
If you're deploying like most folks using a WAR, then all of those images will Go Away as soon as you redeploy, as most containers take the WAR to be deployed and explode it on to the file system. Whatever was in the directory before you did this (i.e. the code and artifacts from when you last deployed) will be going bye bye, and so you will "lose" your images.
You can mitigate this by doing a directory deploy, that is deploy an already exploded directory. Then you KNOW where the application is located (since you put it there). Then it's up to you to sync that directory with your new code as you make changes (notably it's up to you to delete old stuff you don't want any more).
Other than that, different containers have different mechanisms for mapping in an external directory in to the application space. Glassfish has the concept of "alternate doc roots" that you can use. This allows you to have a place out side of the deployment where static stuff can live and still be served by the container, but isn't wiped out when you redeploy.
Finally, you can always do that yourself, stream your own images, etc. without relying on the container at all. This way you can put the images on the file system, in the database, in memory, whatever.

Related

Read a file from same folder as JAR file but still read resources folder when loading from IDE

I've been trying to make jar application that can read a csv file in the same directory as it. This is, however, proving difficult as my means for accessing the file currently is:
InputStream is = getClass().getClassLoader().getResourceAsStream(filename);
Which works for my program running in the IDE and for my tests but doesn't work when I run the program from the compiled jar file. I have no idea how to get it to work for both. I seriously can't understand this path stuff, it seems like there are a million ways to do it and only one of them work for only one specific scenario.
I've been trying to make jar application that can read a csv file in the same directory as it.
Ah, there's your problem. That just isn't a thing.
There are only 2 types of files:
Application Resources
These are read only, and are as much part of your app as your class files are. It is not in any way relevant to think about 'editing' them - that's not the kind of thing they are. It is reasonable to assume that if this resource is somehow missing, the app is as corrupt / misinstalled as it would be if class files are missing.
For this, you use .getResource and .getResourceAsStream. And note that getClass().getClassLoader() is wrong, you want MyClass.class.getResource and then add a slash if you want to go from root (because getClass() potentially breaks when you subclass, and going via classloader is [A] just typing for no reason, and [B] breaks in bootload scenarios. MyOwnClassName.class.getResource never breaks, so, always use that).
This asks java to look in the same place class files are and nowhere else. Your class files are inside the jar files, and not next to them, therefore, it won't find a text file that is sitting next to jar files.
it does not make sense that it does work during development: That means you shoved a file inside the resources folder, which is equivalent to having a CSV file inside the jar file. You must have gone out of your way to tell your build system to do weird things. Don't do that.
If that CSV file is not intended to be user editable it should be inside the jar file and not next to it: That makes it an application resource. Examples of application resources:
You have a GUI, and you need to store the icon files and splash screen art and such someplace.
You ship static data with your app, such as a table of all US states along with the zipcodes they use (could be a text or csv file for example).
Templates of config files. Not config files themselves.
DLLs and the like that you need to unpack (because windows/linux/mac isn't going to look inside jars for them).
You're a webapp and you want to ship the HTML static files along with your webapp.
If this is what your CSV file is, the fix is to put it in the jar, not next to it, then load it with MyClass.class.getResource(name).
Config files and project files
For example:
For a rich text editor (like, say, LibreOffice Writer), the .odt files representing your writings.
Save games for a game.
A config file, which can be edited by the user, or is edited by your own app in a 'preferences' dialog. This stores for example whether to open the app full screen or not, or authentication info for a third party API you're using.
These should not be in the jar, should not be loaded with .getResource at all, and should not be in src/main/resources in the first place.
They also should not be next to your jar! That's an outdated and insecure model (the idea that editable files sit in the same place the app itself sits): A proper OS configuration means that an app cannot write to itself which is most easily accomplished by having it be incapable of writing to its directory. Some OSes (notably, windows) did this wrong for a while.
For example on windows, your app lives in C:\Program Files\MakorisAwesomeApp\makori.jar, and the data files for it live somewhere in C:\Users\UserThatInstalledIt\Documents\MakorisAwesomeApp.
oh linux, your app might be /usr/bin/makori and the data lives somewhere in the home dir. Config data might live in /etc/.
You don't "ship" your config files, you instead make installers that create them. You can do this part in-app by detecting that the relevant config file does not exist, load in a template (that is a resource, shipped inside your jar, loaded with getResource), and write it out, and tell the user to go look at it and edit it.
I really want a CSV file next to my jars!
Well, that's wrong, so, there are no libraries that make this easy. When you want to do silly things its good that APIs don't make that easy, right?
There are really hacky ways to do this. You can use .getResource to get a URL and then 'parse' this. This breaks the classloader abstraction concept (because in java, you can write your own classloaders and they can load from anywhere, not just files or entries in jars), but you can ask for 'yourself' (MyClass.class.getResource("MyClass.class")), pull the URL apart and figure out what's happening - does it start with file://? Then it is a file, so turn it into a j.i.File object, and go from there. Does it start with jar://? find the !, substring out the jar part, and now you know the jar. Make that a java.io.File, ask for the parent dir, and look there for the CSV.
You have to write all this. It's complicated code that is hard to test. You should not do this.

Java: Universally accessing resource files regardless of application server

I'm looking for the 'best practice' way to access resource files (for example a bunch of .xml files) as well as the folder structure in which they reside, regardless of the application server used.
Right now I'm using Wildfly 8 server and I access all src/main/resources/xxxx by getting the application real path then using Paths.get(resourcePath) as well as Files.walk(Paths.get(folderPath)) if I want to access a folder's files.
However, I faced a problem when I tried to deploy to Weblogic 12c, because this app server actually takes everything under WEB-INF/classes and creates a .jar file and adds it to WEB-INF/lib. I can still access singular resources using classLoader.getResource(resourcePath) but for some reason when I try to create a new File(Paths.get(resourcePath) or use Files.walk(Paths.get(folderPath)) it doesn't seem to be working. It throws an exception saying to file doesn't exist which I'm guessing is because it is not accessible since it is packaged inside a jar file.
I could potentially use classLoader.getResource(resourcePath) to access all my resources but unfortunately in my case I cannot know what resources will be available at compile time. I specifically NEED to be able to go through a selected folder's files and subfolders but I haven't found a common way to do it on both app servers, or ALL app servers for that matter.
Bonus points if the solution uses the new File api instead of creating a bunch of FileReaders but I'm ok with that too.
You could place the XML files in a folder /WEB-INF/xml and then use the ServletContext to obtain a File or Path for that location.
Variant 1:
call servletContext.getResourceUrl("/WEB-INF/xml") to obtain a URL and convert this URL to a File or Path. But depending on the server this might return a non-file resource URL, e.g. a jndi:/ url.
Variant 2:
call servletContext.getRealPath("/WEB-INF/xml") to obtain a file string and convert this URL to a File or Path.

Add virtual folder to web dynamic project

Right now I am trying to accomplish a project on Eclipse Juno and Tomcat 7 that requires to have a "virtual folder" to hold multimedia files (like images, other sub-pages,etc.). I already have some methods to give out the file path in a URI based syntax (lets say I want to access images in /Content/Image) and I want to map that URI to C:\Users\MyUser\Content\image (I am aware that I am binding the project to Windows systems but I will workaround later on in this issue).
Currently my project is called pj, and Eclipse created a context called pj inside the eclipse's tomcat instance (and thats makes a lot of sense). When i test my project with
> http://localhost:8080/pj
it works fine (and it's supposed to).
But there is a problem here: until now I haven't found a way to create a URI in tomcat to actually go to the Content/Image path to grab content to add to my pages (read somewhere that is unhealthy to keep content on WEB-INF folder, so i'm trying to actually get it done the right way). Also read somewhere that to accomplish this objective, I have to do something like this in the contexts:
<context docbase="d:/images" path="/Content/Images"></context>
Also read there that in tomcat, to resolve URIs you have to use contexts to achieve that goal (giving a bridge between the meaning of he URI and it's location in the file system).
Still, as from tomcat 4 (if not mistaken) it is not supposed to fiddle around server.xml, so in ANOTHER attempt to make this right, i try to actually add a context in META-INF inside context.xml with the code shown before. But there is here ANOTHER problem! It seems that adding the path tag makes tomcat go nuts, as said here: http://tomcat.apache.org/tomcat-7.0-doc/config/context.html .
So I am really in a bind here.... What I want to ask is:
What is the best way to actually add an external folder in a web project to fetch multimedia content and
How it is supposed to make it work inside Eclipse?
PS: I am asking this because in one of my methods inside my project I am using the getLoader method to return the InputStream (java.io InputStream NOT Corba) and it return nulls (which means it doesnt find it).
EDIT: Tried to actually fiddle around server.xml by inserting the conext by hand but didn't work, inserting the relative URI doesn't work on the server (local:8080/Content/Image with valid files inside) or going inside my main project and do getstream doesnt work too
After some fiddling around, tweaking, etc. I came up with a workaround for this situation. Like I stated, it IS possible to actually have an outside folder hold all the multimedia and/or pages as you wish. One of the references to that solution is here: http://harkiran-howtos.blogspot.pt/2009/08/map-external-directory-into-your.html .
Still, for some reason, this is not quite possible to make it work inside Eclipse (or I have failed something and wasn´t unable to make it work). But there is an alternate solution for this. It is also feasible to actually have a folder for that purpose INSIDE the web app but OUTSIDE the WEB-INF and META-INF folder. In other words, a folder that is located in the ROOT of the web app.To access those files in that folder you can use something called ServletContext. That context has actually inside all possible references to the folder structure of your web app. To access those files with the context give, you have to use getResourceAsStream from the Servlet context (or use getRealPath if it is necesary and/or you can guarantee that the web app is exploded inside Tomcat). So in other words, to access folders inside the web app but outside the WEB-INF and META-INF you have to use ServletContext and their given methods to get files/streams.
PS: Ty wds for pointing out ServletContext
I made the harkiran's solution work but it's not very good solution.
People discourage use of getRealPath. Mapping external folder is good thing to do for many reasons.
But to do it in Eclipse, you need to go to deployment folder.
In my case it's hidden folder inside Eclipse workspace.
workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/
Inside that folder you shoud make directory structure and file from harkiran's solution. I works until you delete and recreate server in Eclipse.
After that you need to make it again.

How make working directory files available to WebStart application?

We have to make a Java application demo available on Internet using JWS. It goes pretty well; all that's missing is making working directory files available for the application.
We know about the getResource() way... The problem is that we have different plugins for the same application and each one require different files (and often different versions of the same files) in their working directory to work properly. So we just change the working directory when we want the application to have a different behavior.
Currently, the demo is packaged in a signed jar file and it loads correctly until it requires a file from the working directory. Obviously, the Internet users of this demo don't have the files ready. We need a way to make these files available to the WebStart application (read/write access) in its working directory.
We've thought of some things, like having the application download the files itself when it starts, or package them in the jar and extract them on startup.
Looking for advices and/or new ideas. I'll continue working on this... I'll update if I ever find something reliable.
Thank you very much!
I said I would share what I found in my research for something that would fit my needs. Here's what I have so far.
I have found that the concept of current working directory (CWD) does not really make sense in the context of a Java Web Start (JWS) application. This had for effect that I stopped trying to find the CWD of a JWS and started looking for other options.
I have found that (no, I didn't know that) you can refer (using getResource()) to a file in the root directory of a JAR file by simply adding a '/' in front of its name. ("/log4j.properties", for example.) The impact of this is that I can now take any file which is only referred to in a read-only manner in the root of that JAR file (which is really only a ZIP file). You can refer to any file in the root of the JAR file using AnyClass.class.getResourceAsStream. That rules out the problem with read-only files required to run the application, at the cost of a switch in the code telling whether the application is run from a valid CWD or from a JWS context. (You can very simply set a property in the JNLP file of the JWS application and check if that property is set or not to know where to look for the file.)
For write-only files (log files in my case), I used the property , adding a directory with the name of the application: <user.home>/.appname and added log files to it.
Read/write files (which I don't have in my case) would probably simply go at the same place than write-only files. The software could deal with uploading them somewhere if needed, once modified, I guess.
That's the way I deal with the problem for now.
Note there is a service you can explicitly ask for, to get file access to the computer (unless you go all the way and ask for full access (which requires signed jar files)).
Then you need to determine where these files need to go - basically you have no idea what is where and whether you may actually write anywhere. You can create tmp-files but those go away.
Would a file system abstraction talking to the JNLP-server do so you store the users data on the server?

What is the best place to store a configuration file in a Java web application (WAR)?

I create a web application (WAR) and deploy it on Tomcat. In the webapp there is a page with a form where an administrator can enter some configuration data. I don't want to store this data in an DBMS, but just in an XML file on the file system. Where to put it?
I would like to put the file somewhere in the directory tree where the application itself is deployed. Should my configuration file be in the WEB-INF directory? Or put it somewhere else?
And what is the Java code to use in a servlet to find the absolute path of the directory? Or can it be accessed with a relative path?
What we do is to put it in a separate directory on the server (you could use something like /config, /opt/config, /root/config, /home/username/config, or anything you want). When our servlets start up, they read the XML file, get a few things out of it (most importantly DB connection information), and that's it.
I asked about why we did this once.
It would be nice to store everything in the DB, but obviously you can't store DB connection information in the DB.
You could hardcode things in the code, but that's ugly for many reasons. If the info ever has to change you have to rebuild the code and redeploy. If someone gets a copy of your code or your WAR file they would then get that information.
Putting things in the WAR file seems nice, but if you want to change things much it could be a bad idea. The problem is that if you have to change the information, then next time you redeploy it will overwrite the file so anything you didn't remember to change in the version getting built into the WAR gets forgotten.
The file in a special place on the file system thing works quite well for us. It doesn't have any big downsides. You know where it is, it's stored seperatly, makes deploying to multiple machines easy if they all need different config values (since it's not part of the WAR).
The only other solution I can think of that would work well would be keeping everything in the DB except the DB login info. That would come from Java system properties that are retrieved through the JVM. This the Preferences API thing mentioned by Hans Doggen above. I don't think it was around when our application was first developed, if it was it wasn't used.
As for the path for accessing the configuration file, it's just a file on the filesystem. You don't need to worry about the web path. So when your servlet starts up it just opens the file at "/config/myapp/config.xml" (or whatever) and it will find the right thing. Just hardcodeing the path in for this one seems pretty harmless to me.
WEB-INF is a good place to put your config file. Here's some code to get the absolute path of the directory from a servlet.
public void init(ServletConfig servletConfig) throws ServletException{
super.init(servletConfig);
String path = servletConfig.getServletContext().getRealPath("/WEB-INF")
Putting it in WEB-INF will hide the XML file from users who try to access it directly through a URL, so yes, I'd say put it in WEB-INF.
I would not store it in the application folder, because that would override the configuration with a new deployment of the application.
I suggest you have a look at the Preferences API, or write something in the users folder (the user that is running Tomcat).
The answer to this depends on how you intend to read and write that config file.
For example, the Spring framework gives you the ability to use XML configuration files (or Java property files); these can be stored in your classpath (e.g., in the WEB-INF directory), anywhere else on the filesystem, or even in memory. If you were to use Spring for this, then the easiest place to store the config file is in your WEB-INF directory, and then use Spring's ClassPathXmlApplicationContext class to access your configuration file.
But again, it all depends on how you plan to access that file.
If it is your custom config WEB-INF is a good place for it. But some libraries may require configs to reside in WEB-INF/classes.

Categories

Resources