Read a file from Tomcat webapps on different Tomcats - java

Consider the following:
I got a csv-file. This file is stored in the tomcat wepapps directory. The path to this directory is dependent of the computer used. There are users that use different locations for their Tomcats and use different names. I want to achieve the following.
Via Spring i did the following:
I got an action which imports some data from the csv to the database.
<bean id="setCsvPathAction" class="custom.action.importcsv.SetCsvPathAction">
<property name="csvPath" value="C:/temp/test.csv"/>
</bean>
This works fine for me. To make this path more configurable for others i got a system.properties file. With this file you can easily overrite properties:
setCsvPathAction.csvPath=#{tomcat_home}/webapps/test.csv
That is what i want. I want the path to be on the Tomcat webapps directory. The above doesn't work. Do you have any hint how to achieve this?

Most people who use tomcat would have set CATALINA_HOME environment variable. You can query this environment variable and retrieve value.
String tomcat_home = System.getenv("CATALINA_HOME");
if(tomcat_home){
setCsvPathAction.csvPath=tomcat_home+"/webapps/test.csv"
}
Note: There's no guarantee that this environment variable is set on every system using tomcat
More on getenv() - http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#getenv%28%29

If it is going to be in the web apps folder you could also just use the class loader to get the local path so you do not have to configure anything.
someObject.getClass().getClassLoader().getResourceAsStream("path/refferenced/to/app/root/");

The solution for the .properties file was: ${catalina.home}
Next i need a FileInputStream independent of the system environment. I tried the following:
public class environmentTest {
public static void main(final String[] args) {
System.out.println(System.getenv("CATALINA_BASE"));
}
}
null gets printed on the console.
The class Person contains the name of the jpg file. This file is located at the webapps folder. I want the path to be independent of the computer used. I tried the following:
File file = new File(System.getenv("CATALINA_HOME") + "/webapps/" + person.getPhoto());
FileInputStream fileInputStream = new FileInputStream(file);
Sadly this doesn't work because, as unekwu said, this environment variable is not set on all systems. Do you have any idea what i can do in this situation?

Related

Access property/environment variables without launching Eclipse?

I want to set the log4j configuration file path/other folder paths that can be used across other class files, without hard-coding the folder path.
Rightnow, I have set the variables as Environment variable. But It can only be modified if I launch Eclipse. How do I set this variable in such away that anyone (doesn't want to launch Eclipse) can modify it, from outside. Also, it will be used in test configurations. So it's better to not hard-code it and have all the file paths etc. easy to refactor.
final static String log4jpath = System.getenv("LOG4J_PATH");
Paraphrasing a comment:
[How to get value from] outside of the Java program such as a separate file, that contains all other filepaths?
That is called a configuration file.
It is often a properties file, similar to a Log4j configuration file, but it can be any types of file, e.g. XML, JSON, YAML, ...
To identify a single such file, you can use:
An environment variable (like you are right now)
A system property (more common)
A specifically named file in the current directory
...
The entries in that file will identify all the values you really want.
For example, Spring, which is a populate Java framework, will look for configuration values in many places. See 24. Externalized Configuration for full detail, but here is a summary of the most common ones:
Command line arguments, e.g. java -jar MyApp.jar --foo=bar
Java System properties, e.g. set using -Dfoo=bar on the command-line
OS environment variables, e.g. SET foo=bar (Windows) or export foo=bar (Linux)
Application properties outside of your packaged jar, i.e. relative to current directory.
Name and location can be overridden on command-line.
config/application.properties
config/application.yaml
application.properties
application.yaml
Soni, If you want to put the log4j configuration file in one place so that everybody can access. Follow the steps.
Create a project with some name and inside src/main/resources folder keep the log4j configuration file.
Create a jar file which must contain this log4j configuration file.
Use this created jar file wherever it is required. Log4j will automatically use the configuration for desired logging. If you want, you can distribute this jar file to anybody who wants to use it.
The above option is if you do not want to change the configuration file.
Now if there is a situation where someone wants to modify the configuration file.
In this case, simply put the configuration in any project classpath, means inside resource folder. As long as log4j jar files are there in the classpath and configuration files. It will log everything.
However, if you want, you can extend the functionality of Log4j by passing configuration as an object. You can refer below the link to access pro grammatically.
https://howtodoinjava.com/log4j/how-to-programmatically-configure-appenders-in-log4j/
I have added all file and folder paths inside the properties file (example config.properties) and then used it inside the testsetup method by InputStream input = new FileInputStream("Path to//config.properties");
Properties prop = new Properties();
prop.load(input);
System.setProperty("log4j2.configurationFile", prop.getProperty("log4j.path"));
this way, all files/folder paths can be modifies from outside and there's no need to set environment variable from inside the project.

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

Get absolute path of a property file

My Java EE application includes many sub-projects, which should use a single one configuration file to connect to the database. I intend to write a Java class and make it an independent jar to read the database connection parameters from datasource.xml, which will be put on the path of the independent jar.
The questions I want to ask:
How to dynamic get the absolute path of the datasource.xml?
Can the solution of the first question work in all operating systems like UNIX, etc?
The first subject you have to deal with is where you store that file.
According to your question, you are going to be storing the file somewhere on the file system, externally to the actual application package. Therefore, you absolutely must know where the file is really located on the file system in order to access it; you can't conclude it in advance, unless you use environment variables that will instruct your code where the file is located.
A better approach is to package your XML file with the JAR. Then, you need not worry about absolute paths anymore. Simply use Thread.currentThread().getContextClassLoader().getResource(), providing the package-style path to the resource and you'll get a reference to it wherever it may be found.
If you can't package your file along with the JAR, you might be able to store it in a directory on the file system and add that directory to your server's classpath lookup sequence; some application servers support that. Then, you can still use the classloader to look up the resource, without requiring to know its absolute location.
What about this? Converting a relative path to absolute during runtime.. I guess that should work on all enviroments...
File a = new File("/some/abs/path");
File parentFolder = new File(a.getParent());
File b = new File(parentFolder, "../some/relative/path");
String absolute = b.getCanonicalPath(); // may throw IOException
regards
You can make use of Environment Variables
String path = System.getEnv("MYVARIABLE");
File datasource = path + "/datasource.xml";
Or read in the location from a properties file available in a constant location
Properties props = new Properties();
try {
props.load("MyFixed.properties");
} catch(Exception e) {
e.printStackTrace(); // Can do better
}
String path = props.getProperty("datasource.path");
File datasource = path + "/datasource.xml";
Or pass in a VM argument when starting the Jar with -D
String path = System.getProperty("datasource.path");
File datasource = path + "/datasource.xml";
and call with
java -jar -Ddatasource.path=/my/path/to/datasource.xml my.jar

Java - Get server absolute path

How to get the absolute path of server location in my machine?
Suppose I am using glassfish server then I need to get absolute path of glassfish docroot location as below:
C:\glassfish3\glassfish\domains\domain1\docroot
At run time, I need to create file on that location using java io package like:
C:\glassfish3\glassfish\domains\domain1\docroot\myfile.txt
If you use GlassFish to start GlassFish, i.e. use asadmin start-domain|start-instance then we offer the following iron-clad guarantee:
The current working directory of the JVM is absolutely, positively guaranteed to be the config directory of the domain or server. In the default case that would be:
c:/glassfish3/glassfish/domains/domain1/config
If you want to write something to (the default) docroot, you can do this:
File f = new File("../docroot/yourfile");
Another option that is guaranteed to always work in every scenario even if you start the server with java directly (e.g. java -jar glassfish.jar) is to use the value of the System Property like so:
File f = new File(System.getProperty("com.sun.aas.instanceRoot") + "/docroot/yourfile");
I don't know if this is the best way, but it works for me :)
String path = new File("").getAbsolutePath() + File.separator + "docroot";
you can try following:
System.getProperty("catalina.base");
And you can find other properties by watching following variable in debug mode.
Properties properties = System.getProperties();
I had an similar problem and ended up with using
path = getClass().getProtectionDomain().getCodeSource().getLocation()
because I needed the path on a static function. This points somwhere to the WEB-INF/classes directory. With this you could point to something like path.subString(0,path.indexOf("WEB-INF")).
One problem that I had with this: When running a test from Eclipse, it pointed me to the "build" directory of the project.
This is a very bad idea. If you are running in a WAR or EAR file the docroot will not be on a writable filesystem. Assuming this is the case may lead to headaches later.
Use a different method, such as a servlet initialization parameter, to specify a writable filesystem location.
For that you need not to go for complete path because
when you are creating file than by default it will create at ROOT of you server
which is C:\glassfish3\glassfish\ here.
hope this will help you.

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