How to copy directory that's injected as Resource? - java

My Spring application has a Maven dependency on app-resources.jar which contains the directory app-resources (as well as the META-INF dir, which I don't care about).
I need to copy the full contents of that folder, without knowing the list of contained files and subfolders.
My first instinct was to try, at runtime, to inject the folder as a Spring resource :
// This is actually injected from app-resources.jar
#Value("classpath:/app-resources/")
private Resource appResource;
/** Copies the static resources to the NFS target folder. */
private void publishResources(final File targetPath) {
File appResourceDir = getFileFromResource???(appResource);
FileUtils.copyDirectory(appResourceDir, targetPath);
}
But I couldn't find a way to view that Resource as a directory. I also considered injecting the jar itself as a resource, and unpacking it (using a GzipInputStream). But I don't know if that is possible either.
Does anyone have a good solution to that problem ? Compile-time solutions (using maven) are welcome too.
EDIT to reply to a comment. The architecture of this application is a bit unusual but it's not in my power to change. We have a frontend project that generates a static html/js website at compile time (that's what the app-resources.jar is). At runtime we want to publish multiple instances of this static site, each with different data files (so we copy the static content, and put specific data files in the site's data/ directory).

Off the cuff answer, perhaps you could get the full class path.
System.out.println(System.getProperty("java.class.path"));
You can then parse out the path for the jar you are interested in and then unzip the required paths to your desired directory.

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 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).

How do I access the resources directory for a calling program in Java

I have a library which is used by a program. This library loads a special directory in the resources folder.
in the library I have the method
public class DataRegistry{
public static File getSpecialDirectory(){
String resourceName = Thread.currentThread().getContextClassLoader().getResource("data").getFile().replace("%20", " ");
File file = new File(resourceName);
return file;
}
}
in my program I have the main method
public static void main(String args[]){
System.out.println(Data.getSpecialDirectory());
}
When I execute the getSpecialDirectory() in a junit test within the data program, the resource is fetched and all is well.
When I execute the getSpecialDirectory() in the main method outside the data program (imported jar) I get the jars data directory and not the directory the program executing the thread is expecting.
I figured getting the parent class loader would have solved this issue... I believe I may have a fundamental issue in my understanding here.
For clarity:
(library)
Line 15 of this file: https://gist.github.com/AnthonyClink/11275442
(Usage)
Line 31 of this file:
https://gist.github.com/AnthonyClink/11275661
My poms may have something to do with it, so sharing them is probably important:\
(Library)
https://github.com/Clinkworks/Neptical/blob/master/pom.xml
(Usage)
https://github.com/Clinkworks/Neptical-Maven-Plugin/blob/master/pom.xml
Maven uses the target/classes and target/test-classes directories to compose the classpath used to run unit tests. The content of your src/main/resources and src/test/resources gets copied to these locations together with the compiled java sources (the .class files).
java.lang.ClassLoader.getResource returns a java.net.URL.
In the unit test situation, ClassLoader.getResource returns a file:// schemed URL, and your code works as expected.
When your code is executed when packaged in a jar file, ClassLoader.getResource no longer returns a file:// schemed URL. It can't because the resource is no longer a separate entity in a file system - it's buried inside the jar file. What you actually get is a jar:file:// schemed URL.
jar: URLs cannot be accessed through a [java.io.File] object.
If you only need to read the content of the resource you should use java.lang.ClassLoader.getResourceAsStream(...) and read the content from that.
Note that it is not possible to update the content of class loader resources.
Do you want the directory where the Java program was loaded from ? Can try
File f = new File(".").getCanconicalFile();
Or if you want all the places could try parsing the classpath from System.env or use the default class loader
If you want a directory relative to the jar from where your classes were loaded: Quoting from http://www.nakov.com/blog/2008/06/11/finding-the-directory-where-your-java-class-file-is-loaded-from/
URL classesRootDir = getClass().getProtectionDomain().getCodeSource().getLocation();
The above returns the base directory used when loading your .class
files. It does not contain the package. It contains the classpath
directory only. For example, in a console application the above
returns someting like this:
file:/C:/Documents%20and%20Settings/Administrator/workspace/TestPrj/bin/
In a Web application it returns someting like this:
file:/C:/Tomcat/webapps/MyApp/WEB-INF/classes/
FYI This might apply if the user id running program cannot read all folders: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getProtectionDomain%28%29
or pass a .class object of the calling class as a parameter and get its classloader
There is no guarantee that you have a directory for your resources as far as I know. Java provide methods to get a resource as a InputStream, but nothing that can easily get the File for a resource, although it is possible to get the URL for a given resource.
If you need a special working directory in your application, I recommend having that passed as a system property, a program parameter, a web application parameter, or something else that lets you know where your application files are. You can even populate this directory with a ZIP file that you include as a resource in your application, as the ZIP libraries in Java do accept input streams as parameters.
While user #tgkprog is right and his answer correct, I can hardly imagine that you really want what you seem to have asked for and what he correctly answered in (3). Please edit your question and explain
what the output should look like if resourceName would be printed to the console,
if you really want the JAR file's location (in my test case that would be something like file:/C:/Users/Alexander/.m2/repository/com/clinkworks/neptical/0.0.1-SNAPSHOT/data, which does not make sense because you do not want to read from or even write to the local Maven cache),
or if you maybe rather want to read a resource directly from the JAR file or any other location such as the current working directory etc.
Otherwise I am afraid there is no good way to answer the question.

How to use ClassLoader.getResources() in jar file

Problem statement:
I have a jar file with a set of configuration files in a package mycompany/configuration/file/.
I don't know the file names.
My intention is to load the file names at runtime from the jar file in which they are packaged and then use it in my application.
As far as I understood:
When I use the ClassLoader.getResources("mycompany/configuration/file/") I should be getting all the configuration files as URLs.
However, this is what is happening:
I get one URL object with URL like jar:file:/C:/myJarName.jar!mycompany/configuration/file/
Could you please let me know what I am doing wrong ?
For what you are trying to do I don't think it is possible.
getResource and getResources are about finding named resources within the classloader's classpath, not listing values beneath a directory or folder.
So for example ClassLoader.getResources("mycompany/configuration/file/Config.cfg") would return all the files named Config.cfg that existed in the mycompany/configuration/file path within the class loader's class path (I find this especially useful for loading version information personally).
In your case I think you might almost have half a solution. The URL you are getting back contains the source jar file (jar:file:/C:/myJarName.jar). You could use this information to crack open the jar file a read a listing of the entries, filtering those entries whose name starts with "mycompany/configuration/file/".
From there, you could then fall back on the getResource method to load a reference to each one (now that you have the name and path)

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 ...

Categories

Resources