loading from JAR files during deployment vs development - java

when i am loading some data into my java program, i usually use FileInputStream. however i deploy the program as a jar file and webstart, so i have to use getRessource() or getRessourceAsStream() to load the data directly from the jar file.
now it is quite annoying to always switch this code between development and deployment?
is there a way autmate this? i.e. is there a way to know if the code is run from a jar or not?
when i try to load it withoug jar like this:
InputStream is = this.getClass().getResourceAsStream("file.txt");
the returned inputstream is simply null, although the file is definitely in the root directory of the application.
thanks!

Why do you use FileInputStream during development? Why not just use getResourceAsStream from the very start? So long as you place your files in an appropriate place in your classpath, you shouldn't have any problems. It can still be a file in the local filesystem rather than in a jar file.
It's helpful to develop with the final deployment environment in mind.
EDIT: If you want something in the root directory of your classpath, you should either use:
InputStream x = getClass().getResourceAsStream("/file.txt");
or
InputStream x = getClass().getClassLoader().getResourceAsStream("file.txt");
Basically Class.getResourceAsStream will resolve relative resources to the package containing the class; ClassLoader.getResourceAsStream resolves everything relative to the "root" package.

You could read your data always as a ressource. You only have to add the path where the data lies to your classpath.
If your data stays in WEB-INF/somewhere/mydata.txt inside your jar file, you will access it with:
getClass().getResourceAsStream( "/WEB-INF/somewhere/mydata.txt" )
Now, if you create a development directory /devel/WEB-INF/somewhere/mydata.txt and put /devel to your classpath, your code will work in development and production.
EDIT after explanation in question:
In your case this.getClass().getResourceAsStream( "mydata.txt" ) the resource is taken from the same position where the classfile of this is taken from. If you want to keep this, then you have to create a directory /devel/<path of package>/mydata.txt and again add /devel to your classpath.

How about setting a system property in your dev environment, via the -D switch? e.g. java -D:mypropertyname=mypropertyvalue
You could set the property in ant scripts in your dev environment, other environments don't get the property:
e.g.
public static boolean isDevEnvironment(){ return System.getProperty("mypropertyname")!=null;}
You might find a better way to hack it from one of the existing System Properties

If a file is considered part of your deployed application (as opposed to be part of the installation specific files) and can be located through the classpath then consider simply always using getResourceAsStream since it works regardless of the actual deployment scheme as long as it is in the classpath.
You might also find the information available from the JVM relevant (if allowed by the security manager):
// Get the location of this class
Class cls = this.getClass();
ProtectionDomain pDomain = cls.getProtectionDomain();
CodeSource cSource = pDomain.getCodeSource();
URL loc = cSource.getLocation(); // file:/c:/almanac14/examples/
http://www.exampledepot.com/egs/java.lang/ClassOrigin.html?l=rel

There shouldn't be any difference between development vs deployment, IHMO.
Classloader.getResource or getResourceAsStream works well, you can read resources and even write them.You can write your own Protocol handles and access everything as an URL/URI, which allows you to read and write resources and also allows proper identification of who actually provide the resource.
The only problem is if an URLStreamHandlerFactory is already registered(in a J2EE application the container could install a factory and you don't have any way to go over and install your own) and you cannot use your handlers "anywhere".
Knowing that, it is preferred to implement your own "resources". At that time when I need it I couldn't find something like that so I had to implement my own ResourceManager. For me it looks more intuitive to access a resource like
Resource layout = ResourceManager.resolve("view://layout/main.jsp")
instead of
URL layout = Classloader.getResource("some_package/view/layout/main.jsp")

Related

Reach External Resource With ClassLoader.getResourceFromStream on WebSphere

I'm working with a local WebSphere server configured in IntelliJ Idea, and the application I'm working on is using a third-party library that loads a properties file with:
ThirdPartyClass.class.getClassLoader().getResourceAsStream(fileNameParameter);
It uses the default bootstrapClassLoader.
I've been instructed to make sure the properties file is in a config directory so that it can be edited without deploying a code change. My project looks something like this:
ProjectName
Configs
my.properties
src
java (sources root)
packages, .java files, etc
main (resources root)
schemas, web docs, etc
I have tried several of paths to make it work but it always returns null. Since I initially thought it was reaching from within the third party library package, I tried adding several ..\'s to the file path, but then I learned that this method loads from the classpath, so I pulled a
String test = System.getProperty("java.class.path");
and upon inspection, my classpath is all made up of websphere directories and jars within them:
C:\Users\me\Programs\IBM\AppServer\profiles\AppSrv01/properties
C:\Users\me\Programs\IBM\AppServer\AppSrv01/properties
and several jar files in C:\Users\me\Programs\IBM\AppServer/lib/
So just as a test I stuck the file in C:\Users\me\Programs\IBM\AppServer\AppSrv01/properties, then tried to grab it with just its file name (my.properties), but still couldn't reach it. I've also tried moving the file into the src directory and the main directory, but no matter what I do it just can't seem to find the file.
I'm aware that this method is typically used to grab resources from within a jar file, but from my understanding it seems like it should be possible to reach my file from outside of one as long as it's in a directory in the classpath... but apparently not since that didn't work.
I have the absolute path on my hard drive and will have said path on the server; is there a way to derive the path that ClassLoader.getResourceFromStream() wants with that info? Failing that, is there some obvious mistake I'm making with the resource url?
I think your fileNameParameter simply needs to start with / to indicate that it is in the root level of the classpath. Otherwise it will be searched relative to the class it is loaded from, i.e. the package of ThirdPartyClass in your example.

How can I make a file visible both when project is deployed on a server and when its classes are run from test classes?

If I use a file calling it directly:
FileInputStream fileInputStream = new FileInputStream("SR02_pattern.xls");
( the file is in \apv\main-app directory), it won't be deployed, and of course, it won't be seen when the project will be run on the server.
If I put the file in the /apv/main-web/WEB-INF/classes/ directory, it will be deployed and I can call it by
InputStream inStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("SR02_pattern.xls")
when the project is deployed on the server, but that line won't read the file in the case the class was run from the test.
Probably, the place where the file will be looked for by getResourceAsStream("SR02_pattern.xls"), is set by some system properties and I can use them, but I don't know which properties can help.
How can I read the file in both cases by the same code without passing it as a parameter into the class?
There are many answers on SO for either of those cases, but I couldn't find one that works for both. The default paths for both cases are different.
Of course, I can put the file in both places, and in case the file is not in the first folder, look it in the second, as I am doing now, but upkeeping two copies is prone to errors and I desire to use better style.
You should use this.getClass().getResourceAsStream('/SR02-pattern.xl') for all parts in test as well in production code. The / defines the root directory for the resources.
The files you would like to read should be located in src/main/resources. This will result in the final war package at the location WEB-INF/classes.

How to avoid hard code full path in Paths#get method

I want to save a copy of Primefaces UploadedFile to my project directory. I have been searching the internet for the solution, what I have found is using Paths#get method. The example given in this answer is Paths.get("/path/to/uploads");, the problem is, where is the exact path of /path/to/uploads? I can't find it. I mean where should I create the path /path/to/uploads? Under my project directory? but which folder? I solve this issue temporary by hard coding the full path like Paths.get("C:/uploads/");
FacesContext.getCurrentInstance().getExternalContext().getRealPath("/") will return you the current installation directory of your project.
And as #Kukeltje suggested, never ever save an uploaded file to your project directory, ... save it outside the webapps or even outside your container.
Therefore create a directory outsite your container (where you want to place your uploaded copies) and append ../ to the above path for each back step.
Say, if your application is deployed at D:/Tools/Tomcat7/webapps/your-application-name (e.g. on Windows using Tomcat) and you want to save copies to D:/Tools/uploads then following will give you required file path:
String uploadsFilePath = FacesContext.getCurrentInstance().getExternalContext()
.getRealPath("../../../uploads");
Use it with the Paths.get(uploadsFilePath) and develop your download logic (I am not sure which library you are using for the Paths class).
How about getClassLoader().getResource(Path/to/file)
So like
MyClass.class.getResource(bla/bla)
Which are now nested in src/resources
Like this You are system independent
#profit
You have several options:
For very quick development, you can use a hardcoded path, but be sure that it exists in your SUT (system under test).
You can define it as a static final string in your module, but this means that each time you want to change that path, you will need to recompile...
You can read that value from a property/config file.
There are more options (like using the registry if you are on Windows, or using an environment variable).

Java file path in web project

I need to access the resource files in my web project from a class. The problem is that the paths of my development environment are different from the ones when the project is deployed.
For example, if I want to access some css files while developing I can do like this:
File file = new File("src/main/webapp/resources/styles/some.css/");
But this may not work once it's deployed because there's no src or main directories in the target folder. How could I access the files consistently?
You seem to be storing your CSS file in the classpath for some unobvious reason. The folder name src is typical as default name of Eclipse's project source folder. And that it apparently magically works as being a relative path in the File constructor (bad, bad), only confirms that you're running this in the IDE context.
This is indeed not portable.
You should not be using File's constructor. If the resource is in the classpath, you need to get it as resource from the classpath.
InputStream input = getClass().getResourceAsStream("/main/webapp/resources/styles/some.css");
// ...
Assuming that the current class is running in the same context, this will work regardless of the runtime environment.
See also:
getResourceAsStream() vs FileInputStream
Update: ah, the functional requirement is now more clear.
Actually I want to get lastModified from the file. Is it possible with InputStream? –
Use getResource() instead to obtain it as an URL. Then you can open the connection on it and request for the lastModified.
URL url = getClass().getResource("/main/webapp/resources/styles/some.css");
long lastModified = url.openConnection().getLastModified();
// ...
If what you're looking to do is open a file that's within the browser-visible part of the application, I'd suggest using ServletContext.getRealPath(...)
Thus:
File f = new File(this.getServletContext().getRealPath("relative/path/to/your/file"));
Note: if you're not within a servlet, you may have to jump through some additional hoops to get the ServletContext, but it should always be available to you in a web environment. This solution also allows you to put the .css file where the user's browser can see it, whereas putting it under /WEB-INF/ would hide the file from the user.
Put your external resources in a sub-directory of your project's WEB-INF folder. E.g., put your css resources in WEB-INF/styles and you should be able to access them as:
new File("styles/some.css");
Unless you're not using a standard WAR for deployment, in which case, you should explain your setup.
Typically resource files are placed in your war along with your class files. Thus they will be on the classpath and can be looked up via
getClass.getResource("/resources/styles/some.css")
or by opening a File as #ig0774 mentioned.
If the resource is in a directory that is not deployed in the WAR (say you need to change it without redeploying), then you can use a VM arg to define the path to your resource.
-Dresource.dir=/src/main/webapp/resources
and do a lookup via that variable to load it.
In Java web project, the standard directory like:
{WEB-ROOT} /
/WEB-INF/
/WEB-INF/lib/
/WEB-INF/classes
So, if you can get the class files path in file system dynamic,
you can get the resources file path.
you can get the path ( /WEB-INF/classes/ ) by:
this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()
so, then the next ...

Loading application properties in a Java desktop application

What is the best way to store and load application level properties in Java.
Is there anything simulare to .net where I would just put something in the app.config
<appSettings>
<add key="emailAddress" value="me#example.com" />
</appSettings>
And then retrieve it like this:
string AdminEmail = ConfigurationManager.AppSettings["emailAddress"];
Do I have to load properties files into file streams and such? seems like unnecessary work.
I have tried this:
Properties props = new Properties();
FileInputStream fis = new FileInputStream("myProps.properties");
props.load(fis);
fis.close();
But this is give me a java.io.FileNotFoundException exception. Where does the properties file need to go to in relation to the class?
The Preferences API provides this functionality. It has many warts, but if you are looking to do this in an OS-agnostic fashion, this is the only way to accomplish this using the standard Java runtime libraries. You can of course always write your own OS-specific code to meet your needs. Yes, you can write simple code to load a properties file, but the location of that file can become a problem across multiple operating systems. I assume since you are writing a desktop app in Java, you care about OS portability. Otherwise Java might not be the best choice for a desktop app.
If you use a FileInputStream like that, your path is relative to the current directory of the OS, which usually is the startup directory.
If you instead use the Java built in resources mechanism (as described in the API, getResourceAsStream() et al), the path will be relative to the location of your class. With this approach you can also load resources from within jars and even over networks (for Applets for instance). The concept which is used is a sort of virtual filesystem, which is called the 'classpath' in Java jargon. There is a devx article covering it a litte more in detail.
In short, this sort of code works well:
Properties prop = new Properties();
//with properties in the same dir as current class
prop.load(getClass().getResourceAsStream("my.properties"));
//with properties in the root dir of your jar, or in base of classpath
prop.load(getClass().getResourceAsStream("/my.properties"));
You will need to add error handling...
Typically it will attempt to load from the application's current directory, which can vary depending on how you run it. You should be able to determine this at runtime by doing:
String currentFolder = System.getProperty("user.dir");
The file path it would be looking for in that case is relative to where you started your java application from. This is not where the main class is or the jar file but where you called Java from. If you are starting your application with a script that calls Java, then it is that directory.
Say for example, you application is bundled in a jar file 'app.jar'. Put 'myProps.properties' in the same directory and run 'java -jar app.jar' from that directory. It should find your properties file that way.
You can use Properties with a ResourceBundle. I use this in a application to store labels, buttons and messages in different languages
First you create a properties file, like test.properties. It´s a text file and inside it you put your information like this:
propertyname=value
In your case
emailAddress=me#example.com
email2=blablabla#example.com
and so on...
To get this properties in the code, create a ResourceBundle object with the name of your property file to call the properties.
ResourceBundle rb = ResourceBundle.getBundle("test");
To get an specific value from a properties file, just call the ResourceBundle
String value = rb.getString("emailAddress");
This way, the String named value contains the value of the property named "emailAddress", located in the test.properties file
String value2 = rb.getString("email2");
Likewise, the String named value2 contains the value of the property named "email2", located in the test.properties file
When you do not specify an absolute path, the one chosen is the current one.
It's not exactly what you asked, but if you want to use XML files as configuration, you could have a look at Apache Commons Configuration

Categories

Resources