Accessing properties file in a JSF application programmatically - jsf

I am trying to access the i18n properties file I'm using in my JSF application in code. (The idea is to have a page that displays its keys and values as a table actually.)
The project is a maven project, and in the src/resources/localization folder, and deployed in the war file in WEB-INF\classes\localization\
java.util.Properties prop = new java.util.Properties();
String path = "localization/stat_codes.properties";
InputStream foo = prop.getClass().getResourceAsStream(path);
But the variable foo turns out to be null whatever I set the path variable to, /WEB-INF/classes/localization/stat_codes.properties, "localization.stat_codes.properties" etc. A similar question is here, but there is no helpful answer there as well.

The Class#getResourceAsStream() can take a path which is relative to the location of the Class which you're using there as starting point. So, for example, if the class is located in the com.example package and you request the path foo/filename.properties, then it will actually load the com/example/foo/filename.properties file. But if you use /foo/filename.properties, then it will actually load foo/filename.properties from the classpath root.
So, your code
java.util.Properties prop = new java.util.Properties();
String path = "localization/stat_codes.properties";
InputStream foo = prop.getClass().getResourceAsStream(path);
will actually look for java/util/localization/stat_codes.properties file.
But in applications with a complex multiple classloader hierarchy, the one classloader isn't the other. The classloader which loaded the core Java classes does not necessarily have knowledge about files which are in the webapp's /WEB-INF/classes. So prefixing the path with / will not necessarily be the solution, it would still return null.
If you can guarantee that the current class is visible by the same classloader as the properties files (because they're in the same sub-root of the classpath, e.g. /WEB-INF/classes, then you should indeed use
String path = "/localization/stat_codes.properties";
InputStream foo = this.getClass().getResourceAsStream(path);
But if at some point, the properties files will be externalized because of more easy maintenance/editing during runtime so that you don't need to rebuild/redeploy/restart the webapp whenever you want to edit the files, then the above line of code will likely fail as well. The externalized location would be only accessible by a different classloader. The canonical solution is to use the thread's context classloader as starting point instead, it has access to all resources in the classpath.
String path = "localization/stat_codes.properties";
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream foo = loader.getResourceAsStream(path);
(note that this one cannot take a path starting with /, it's always relative to the common root)
See also:
Where to place and how to read configuration resource files in servlet based application?
ExternalContext#getResourceAsStream() returns null, where to place the resource file?

It seems that the culprit is the prop object, I supposed any object would work, but it has to be the current object (this) on which the method getClass() is invoked, it seems. Also, the path should start with a / since the localization directory resides in WEB-INF/classes.
String path = "localization/stat_codes.properties";
InputStream foo = this.getClass().getResourceAsStream(path);

Related

GroovyClassLoader Hierarchy and CompilerConfiguration

Problem:
Create GroovyClassLoader GCLA with explicitly set CompilerConfiguration
Create another GroovyClassLoader GCLB with different CompilerConfiguration that sets the BaseScriptClass and uses GCLA as parent
-> a script loaded in GCLB will not have the BaseScriptClass set correctly (but uses the potentially set basescript of GCLA)
Long Story:
My application uses four Groovy scripts to allow customization of certain actions. Each script provides a small DSL, where the DLSs are different for each script. When the action is excecuted in the application, the corresponding script will be called. Additionally some common groovy scripts can be loaded at application startup for storing of common data or definition of helper functions.
The scripts are heavily typechecked at the start of the application.
My first approach was to have one GroovyClassLoader which first loads the common groovy scripts and then does a loadClass for each of the scripts. The DSL is created by simply adding corresponding elements to the binding of each script befor the script is run. The GroovyClassLoader uses a CompilerConfiguration with TypeCheck-Extensions to typecheck the scripts.
This works quite well but has two severe limitations:
the typechecking has to be performed based on the name of the script (because the DSLs for each script is different)
the typechecking script gets quite complicated because it has to handle all four DSLs
To get rid of the named limitations I tried to use a distinct GroovyClassLoader (with my actual ClassLoader as parent) for each of the script (i. e. one per DSL) and set a corresponding ScriptBaseClass which provides the functionality for the DSL. This works very well: the typechecking code is reduced drastically, I can have distinct typechecking scripts for each DSL and I don't have to mess with the name of the script.
But I don't get this to work with the common groovy scripts. As soon as I try to use the GroovyClassLoader of the common scripts as parent for the GroovyClassLoader of the DSL scripts, the DSL no longer gets the correct BaseScriptClass although it's explictly set in the CompilerConfiguration. It seems that the child GroovyClassLoader uses the BaseScriptClass of the parent GroovyClassLoader.
Any ideas of how to get this working?
UPDATE
In my original post I did not mention that I'm using scala. Actually I tried the following code snippet:
val rootConfig = {
val cf = new CompilerConfiguration(CompilerConfiguration.DEFAULT)
cf.setSourceEncoding("UTF-8")
cf.addCompilationCustomizers(new ASTTransformationCustomizer(classOf[CompileStatic]))
cf
}
val childConfig = {
val cfg = new CompilerConfiguration(CompilerConfiguration.DEFAULT)
cfg.setSourceEncoding("UTF-8")
cfg.setScriptBaseClass("NonExisting")
cfg.addCompilationCustomizers(new ASTTransformationCustomizer(classOf[CompileStatic]))
cfg
}
val rootGCL = new GroovyClassLoader(getClass.getClassLoader, rootConfig, false)
val childGCL = new GroovyClassLoader(rootGCL, childConfig, false)
This does not work and the child ClassLoader seems to ignore the CompilerConfiguration completely: it does not complain about the non-exiting BaseScriptClass and if I switch off the static-compilation in the rootConfig it will not even perform the static checks.
If I move the ClassLoader creation to a Java file everything works as expected
GroovyClassLoader has several constructor. For example one for ClassLoader and one for GroovyClassLoader. The GroovyClassLoader version will take the configuration from it. But if you do for example new GroovyClassLoader((ClassLoader) parent) or go with giving the configuration yourself. And for that it is even enough to give null as configuration. The constructor logic will take CompilerConfiguration.DEFAULT then to configure the GroovyClassLoader: new GroovyClassLoader(parent,null) and if you want to be very sure no strange paths are added to the GroovyClassLoader, use the variant with a boolean new GroovyClassLoader(parent,null,false)

How to create predictable logging locations with sbt-native-packager

I am using sbt-native-packager with the experimental Java Server archetype. I am trying to identify a conventional way to access my log files, and I'm wondering if anyone knows of a common approach here. Since I am using the Java Server archetype, I am getting a symlink /var/log/$app -> install_dir/$app/log, but it feels a little dirty and less portable to just have log4j open /var/log/$app/error.log directly.
[Update]
I ended up creating an object with run time path information:
object MakaraPaths {
def getLogPath = new File(getJarPath, "../logs").getPath
def getConfigPath = new File(getJarPath, "../conf").getPath
def getJarPath = {
val regex = new Regex("(/.+/)*")
val jarPath = Makara.getClass.getProtectionDomain.getCodeSource.getLocation.getPath
(regex findAllIn jarPath).mkString("")
}
}
In my main method, I established a system property based on the new MakaraPaths object:
System.setProperty("logPath", MakaraPaths.getLogPath)
I also used this for my config file:
val config = ConfigFactory.parseFile(new File(MakaraPaths.getConfigPath, "application.conf"))
Ultimately, to load the log file, I used a System Property lookup:
<RollingFile name="fileAppender" fileName="${sys:logPath}/server.log" filePattern="${sys:logPath}/server_%d{yyMMdd}.log">
This gets me most of the way where I needed to be. It's not completely portable, but it does technically support my use case. (Deploying to Ubuntu)
You could use relative path in log4j configuration. Just write logs in logs/filename.log.
During installation symlink install_dir/$app/logs -> /var/log/$app will be created, and all logs will be written in /var/log/$app/filename.log

JBoss equivalence of glassfish alternate docroot

This is very easy using Glassfish:
Consider my absolute path on unix /apps/static_content/.
Using Glassfish, I will simply define alternate doc root as:
<property name="alternatedocroot_1"
value="from=/static/* dir=/apps/static_content/"/>
When I upload my images and other data files, I can save them to the /apps/static_content directory, and within my JSF page I can display my static content normally as:
<p:graphicsimage value="/static/external_web_app.png"/>
I really need to achieve the same functionality in JBoss AS7
How can I do this?
This question is a little bit old, but answering if someone need to do this with newer versions of JBoss/Wildfly.
JBoss AS was renamed to Wildfly from version 8 (i.e. Wildfly 8 is JBoss AS 8) and Red Hat supported version of JBoss was renamed to JBoss EAP. So this applies to:
Wildfly (any version)
JBoss EAP (from version 7)
First thing to note is that "Alternate doc root" feature in glassfish doesn't work like that. Please take a look at this question for an explanation of the behavior of this feature: Alternate docroot not working on glassfish 4
Now, to answer this question, JBoss/Wildfly is build upon Undertow, that let you do exactly what you need. Refer at this question on how to configure undertow as a web server for static content: How to configure Wildfly to serve static content (like images)?
Option 1: You could try to deploy a separate exploded .war file, and use that for your static content
In your case: In .../jboss-7/standalone/deployments/ there must be a static.war/.
So the uploads go into this directory, and the content is served back the normal way.
As for details, see Is it possible to deploy an exploded war file (unzipped war) in JBoss AS 7
As pointed out by BalusC: You must not redeploy/remove this directory, as soon as data has been uploaded. You should have a regular backup of this directory.
As far as I know this is the only possibility to do it by configuration/setup only.
Option 2: Create separate webapp with name static.war. Add a servlet to stream the static content
This way there is no need to upload/store the files into the file system below ../deployments/, it could be any directory, but you need an additional servlet, so it's solved programatically.
A simple streaming servlet could look like this (just streaming - no authentication etc.):
public class DownloadServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
final File dir = new File("/var/cms/storage/");
final String start = "/static/";
final String relativePath = request.getRequestURI().substring(
request.getRequestURI().indexOf(start) + start.length());
final File file = new File(dir, relativePath);
final String ct = URLConnection.guessContentTypeFromName(file.getName());
response.setContentType(ct);
final InputStream is =
new BufferedInputStream(new FileInputStream(file));
try {
final boolean closeOs = true;
org.apache.commons.fileupload.util.Streams.copy
(is, response.getOutputStream(), closeOs);
} finally {
is.close();
}
}
Map all URLs to this servlet:
<servlet-mapping>
<servlet-name>DownloadServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
The name static.war provides the /static/ web context, so that should make it compatible with the URLs in your code.
If you explore jboss directory you will find that there are many you can use to store different type of data like jboss.serer.data.dir .
You can try asking this directory path via system properties and store in a folder the data your services are using, under such directory.
String path = System.getProperty("jboss.server.data.dir");
Then you can use path as you want, if is just static as shown in your example you set directly the name of the directory.
This should work, I hope :p
ps: as the previous answer suggest the saved data will keep in the directory, and you must not redeploy/remove this directory.. It will keep your data there..

Java getResourceAsStream cannot load resource

I am trying to load a class whose name is specified in a properties file. Here is the code for the same.
try {
Properties properties = new Properties();
InputStream in = MyAbstractFactory.class.getResourceAsStream("/some.properties");
properties.load(in);
String impl = properties.getProperty("key");
MyAbstractFactory factories = (MyAbstractFactory) Class.forName( impl ).newInstance();
return factories;
} catch (Exception e) {
return new DefaultFactoriesImpl();
}
This code is part of a jar file. the properties file is just outside the jar. Its unable to load the properties file and is loading DefaultFactoriesImpl instead. I know this happens when MyAbstractFactory.class.getResourceAsStream cant find the resource in the class path but that doesn't seem to be the case here.
Dir Structure:-
com
myjar.jar
some.properties
Command i am executing is "java -jar myjar.jar"
Any feedback on why this might be happening. Could this have something to do with Clasloaders? I'd like to add that when i run this code from within eclipse it seems pick up some.properties just fine.
Remove the leading slash from the argument you pass to getResourceAsStream().
Put the folder outside the JAR into the CLASSPATH when you execute the JAR. I don't know if the manifest CLASSPATH overrides the one you might pass using -cp. Play with it; one of them will work.
It's not finding your .properties file because it's not in the JVM CLASSPATH. When you do it properly, the JVM will find it.

How to get handle to a resource within a JSF class?

I've put a properties file within src/main/resources in my JSF project.
How do I get a handle to it? I understand that EL doesn't work within a backing bean.
Note: The file is in src/main/resources - NOT src/main/webapps/resources, so the following doesn't work:
FacesContext context = FacesContext.getCurrentInstance();
File value = context.getApplication().evaluateExpressionGet(context, "#{resource['resources:email.properties']}", File.class);
It's thus in the classpath. You can just use ClassLoader#getResourceAsStream() to get an InputStream out of it. Assuming that src is the classpath root and that main/resources is the package:
InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream("main/resources/foo.properties");
Properties properties = new Properties();
properties.load(input);
// ...
Alternatively, if it's supposed to be specific to the webapp and thus isn't supposed to be overrideable by a file on the same path elsewhere in the classpath which has a higher classloading precedence (e.g. in appserver's lib or the JRE's lib), then use ExternalContext#getResourceAsStream() instead.
InputStream input = FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("main/resources/foo.properties");
Properties properties = new Properties();
properties.load(input);
// ...
As to the #{resource} syntax, this is indeed specifically for CSS/JS/image resources placed in /resources folder of public web content. See also How to reference CSS / JS / image resource in Facelets template?

Resources