Reading System Properties in Web.XML - java

in order to access global values stored in the file src/resources/settings.properties from web.xml on a JBoss EAP 7 Server, I implemented the following class from a similar Stack Overflow topic:
public class ConfigurationWebFilter implements ServletContextListener {
protected static final Properties properties = new Properties();
#Override
public void contextInitialized(final ServletContextEvent event){
try {
try (InputStream stream = new FileInputStream("/settings.properties")) {
properties.load(stream);
}
for (String prop : properties.stringPropertyNames())
{
if (System.getProperty(prop) == null)
{
System.setProperty(prop, properties.getProperty(prop));
}
}
} catch (IOException ex) {
logger.error("Failed loading settings from configuration file for web.xml", ex);
}
}
}
Then I added the according listener to web.xml:
<listener>
<listener-class>
com.product.util.ConfigurationWebFilter
</listener-class>
</listener>
The code gets called properly and I can verify by debugging that the system variables get set correctly. However, the properties of my web.xml do not seem to be replaced/interpreted. The following parameter does still evaluate to ${serverName}, even after restarting the server and/or republishing:
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>(...)</filter-class>
<init-param>
<param-name>serverName</param-name>
<param-value>${serverName}</param-value>
</init-param>
</filter>
All the other topics on this issue were of no use because no solution worked for me. How can I replace web.xml parameters by values stored in a properties file?

Works now, I had to set a parameter related to the replacement of variables to true (was false) in the Wildfly standalone.xml.

Related

Exception on library in Tomcat Apache web application no TLDs found

I just started learning Apache Tomcat and I just even recently Installed it, Am trying to run a particular Java program/class that waits/listens for data from a php post request and below is the code. I call this class Listener.java
package matchfaces;
public class Listener {
public static final String JAVABRIDGE_PORT = "1699";//8080
static final php.java.bridge.JavaBridgeRunner runner =
php.java.bridge.JavaBridgeRunner.getInstance(JAVABRIDGE_PORT);
public static void main() {
// TODO code application logic here
try {
System.loadLibrary("facesdk");
int res = FSDK
.ActivateLibrary("LICENCE KEY");
FSDK.Initialize();
FSDK.SetFaceDetectionParameters(true, true, 384);
FSDK.SetFaceDetectionThreshold(5);
if (res == FSDK.FSDKE_OK) {
System.out.println("FaceSDK activated\n");
} else {
System.out.println("Error activating FaceSDK: " + res + "\n");
}
} catch (java.lang.UnsatisfiedLinkError e) {
System.out.println("exception " + e.getMessage());
}
runner.waitFor();
}
}
After much research I tried a couple of things but now, it seems the libraries I need are not being load and thus throwing an exception. My web.xml is as follows
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<servlet>
<servlet-name>Match Faces</servlet-name>
<servlet-class>matchfaces.Listener</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Match Faces</servlet-name>
<url-pattern>/matchfaces</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<listener>
<listener-class>ViewHandler.handler</listener-class>
</listener>
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
So I used a listener so On Tomcat start server it would fire the web application java class Listener.java
public class handler implements javax.servlet.ServletContextListener{
#Override
public void contextInitialized(ServletContextEvent sce) {
try {
Listener listen = new Listener();
listen.main();
} catch (InterruptedException ex) {
Logger.getLogger(Listener.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
The error I get is this
exception no facesdk in java.library.path
The major problem you are having is fron the System.loadLibrary("facesdk"); It seems you have not provided a path to the facesdk.dll library. But rather than state the path in the loadLibrary method just head to your catalina.bat file and right under :noJuliManager
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER% add this set JAVA_OPTS="-Djava.library.path=%CATALINA_BASE%\lib"
This should work just fine.

How to run WebSockets with Spark Framework via Tomcat?

I've taken an Example from https://sparktutorials.github.io/2015/11/08/spark-websocket-chat.html and want to deploy it as war to Tomcat to run it on web server. I've found several examples with basic request (like get, for Ex.) but such way doesn't work with web sockets.
public class Chat implements SparkApplication{
static Map<Session, String> userUsernameMap = new HashMap<>();
static int nextUserNumber = 1; //Used for creating the next username
public static void main(String[] args) {
new Chat().init();
}
//Sends a message from one user to all users, along with a list of current usernames
public static void broadcastMessage(String sender, String message) {
userUsernameMap.keySet().stream().filter(Session::isOpen).forEach(session -> {
try {
session.getRemote().sendString(String.valueOf(new JSONObject()
.put("userMessage", createHtmlMessageFromSender(sender, message))
.put("userlist", userUsernameMap.values())
));
} catch (Exception e) {
e.printStackTrace();
}
});
}
//Builds a HTML element with a sender-name, a message, and a timestamp,
private static String createHtmlMessageFromSender(String sender, String message) {
return article().with(
b(sender + " says:"),
p(message),
span().withClass("timestamp").withText(new SimpleDateFormat("HH:mm:ss").format(new Date()))
).render();
}
#Override
public void init() {
String route = "/chat";
webSocket(route, ChatWebSocketHandler.class);
}
}
When I run it I get
org.apache.catalina.core.StandardContext.filterStart Exception starting filter SparkFilter
java.lang.IllegalStateException: WebSockets are only supported in the embedded server
at line webSocket(route, ChatWebSocketHandler.class); in void init() method.
If smth depends on my web.xml (i've not changed it), the list is here:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Messenger</display-name>
<filter>
<filter-name>SparkFilter</filter-name>
<filter-class>spark.servlet.SparkFilter</filter-class>
<init-param>
<param-name>applicationClass</param-name>
<param-value>com.barbarian.messenger.Chat</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SparkFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
If I put new SparkFilter(); before that line (just tried) I got
org.apache.catalina.core.StandardContext.filterStart Exception starting filter SparkFilter
java.lang.IllegalStateException: WebSockets are only supported in the embedded server
at the same line.
Does anybody have ideas of valid running it?
Based on the documentation (at least the current one):
WebSockets only works with the embedded Jetty server, and must be defined before regular HTTP routes......
http://sparkjava.com/documentation.html#websockets
Which is why you do not see any servlet config in web.xml in the sample code (https://github.com/tipsy/spark-websocket) since the embedded Jetty container can be run directly in the main method. Also it uses the org.eclipse.jetty.websocket.api.* package for websocket implementation.
If you need websocket to be run on Tomcat, you might want to consider using WebSocketServlet implementation in catalina package. I've found sample codes here (even though I haven't tested it yet): https://gist.github.com/chitan/3063774. Hope this helps.

Read properties file on glassfish 4

I need to read a properties file in a glassfish 4 application. The file needs to be somewhere in the application (i.e. not at some random place in the file system).
If it matters, I'm developing with eclipse, the project builds with maven, and the artifact is a war.
It seems to me there are three things I need to know to make this work.
1) Where does the original file need to be?
2) Where does the file need to end up?
3) How do I read it?
So far I created the file:
src/main/resources/version.properties
which ends up in
WEB-INF/classes/version.properties
I don't know if that is the correct location.
Based on similar questions, I have defined a ServletContextListener:
public class ServletContextClass implements ServletContextListener {
...
#Override
public void contextInitialized(ServletContextEvent arg0) {
ServletContext ctx = arg0.getServletContext();
InputStream istream = ctx.getResourceAsStream("version.properties");
// at this point, istream is null
Properties p = new Properties();
p.load(istream);
}
}
I'm not sure if I have the file in the wrong place, if I'm reading it wrong, or both.
update: the following "works":
#Override
public void contextInitialized(ServletContextEvent arg0) {
ResourceBundle bundle = ResourceBundle.getBundle("version");
if (bundle == null) {
logger.info("bundle is null");
} else {
logger.info("bundle is not null");
logger.info("version: " + bundle.getString("myversion"));
}
}
However, I don't think this is the correct solution. Bundles are for locale support, and this does not fall under that category.
Update 2: I corrected the location where the file ends up.
1) Putting the version.properties file in
src/main/resources/version.properties
seems to be correct.
2) In the target war, the file does in fact end up in
WEB-INF/classes/version.properties
3) To read the file: I already had a ServletContextListener defined. If you don't you need to define one and configure it in web.xml. Here is a portion of my ServletContextListener:
package com.mycompany.service;
public class ServletContextClass implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent arg0) {
ServletContext ctx=arg0.getServletContext();
try {
Properties p = new Properties();
InputStream istream = ctx.getResourceAsStream("/WEB-INF/classes/version.properties");
p.load(istream);
Properties sysProps = System.getProperties();
sysProps.putAll(p);
} catch (IOException e) {
logger.error("Error reading " + "version.properties");
}
}
}
It is configured with this piece of the web.xml:
<listener>
<listener-class>com.mycompany.service.ServletContextClass</listener-class>
</listener>

Prevent suffix from being added to resources when page loads

I have a JSF2 application running and working no problem. The issue I am having with JSF is with the resource bundle. All resources have the .xhtml suffix appended to it. So main.css becomes main.css.xhtml when loaded in the browser. I would like to have it so the .xhtml isn't apended to the resources (don't mind about the pages themselves).
Is there a way where we can NOT have .xhtml appended to resources?
I would ideally not have to change the internal workings of the site. I have listed ideas below, but I have to say I don't really like these. Hoping for a solution somewhere?
I am using Majorra v.2.1.17 on Glassfish 3.1.2.2.
Current Faces Servlet loading as in web.xml (updated)
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>
Why this questions is different from others
JSF 2 resources with CDN?. I am not looking to place my resources on a CDN, but to have my resources stay on my server but are pushed towards a CDN.
Change /javax.faces.resource prefix of resource URLs. I don't want to change the prefix. I want only to change the suffix. I would want <link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css.xhtml?ln=styles"> to become : <link type="text/css" rel="stylesheet" href="/javax.faces.resource/main03.css?ln=styles"> WITHOUT the .xhtml extension.
Changing JSF prefix to suffix mapping forces me to reapply the mapping on CSS background images. Since I have no issue with loading the resources. The site works, we are simply having a hard time differrentiating a webpage from a resource (Since we are looking at the extention alone).
Reasoning
Sure you might be asking me why I need this. Well, we are moving our application to be served by the Akamai CDN.
The issue we are having with the integration of the site is that we are trying to cache static content on the edge servers. This is done by matching file extensions (ie: .js, .doc, .png, css, etc). We cannot match xhtml because this would be caching all pages as well as static content. Which by that would cause problems with sessions and such.
Attempted Solution
In line with the answer by BalusC, I have implemented the resource handler as suggested. I will not rewrite code here, since it is in answer below.
However, I am getting an error when loading composite components. I am getting an error as such :
WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
at com.sun.faces.application.ApplicationImpl.createComponent(ApplicationImpl.java:975)
at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.createComponent(CompositeComponentTagHandler.java:162)
at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.createComponent(ComponentTagHandlerDelegateImpl.java:494)
at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:169)
...
Composite component is loaded correctly because if I "unregister" the new ResourceHandler we just created it will load. The stack trace leads me to believe that it is trying to find this component in a java class, instead of finding it in the resources. According to grepcode this would be at this last line (975) where the error happens :
String packageName = componentResource.getLibraryName();
String className = componentResource.getResourceName();
className = packageName + '.' + className.substring(0, className.lastIndexOf('.'));
Meaning that the resourceName, aka className is null since the error I am getting is java.lang.NullPointerException. I can't seem to figure out how/where the ResourceHandler is called vis-a-vis a composite component. Any help figuring out this last issue?
This is doable with a custom ResourceHandler which returns in createResource() a Resource which in turn returns an "unmapped" URL on Resource#getRequestPath(). You only need to add the default JSF resource prefix /javax.faces.resource/* to the <url-pattern> list of the FacesServlet mapping in order to get it to be triggered anyway.
Further, you need to override isResourceRequest() to check if the URL starts with the JSF resource prefix and also the handleResourceRequest() to locate and stream the proper resource.
All with all, this should do:
public class UnmappedResourceHandler extends ResourceHandlerWrapper {
private ResourceHandler wrapped;
public UnmappedResourceHandler(ResourceHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public Resource createResource(final String resourceName, final String libraryName) {
final Resource resource = super.createResource(resourceName, libraryName);
if (resource == null) {
return null;
}
return new ResourceWrapper() {
#Override
public String getRequestPath() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
String mapping = externalContext.getRequestServletPath();
if (externalContext.getRequestPathInfo() == null) {
mapping = mapping.substring(mapping.lastIndexOf('.'));
}
String path = super.getRequestPath();
if (mapping.charAt(0) == '/') {
return path.replaceFirst(mapping, "");
}
else if (path.contains("?")) {
return path.replace(mapping + "?", "?");
}
else {
return path.substring(0, path.length() - mapping.length());
}
}
#Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
public String getResourceName() {
return resource.getResourceName();
}
#Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
public String getLibraryName() {
return resource.getLibraryName();
}
#Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2).
public String getContentType() {
return resource.getContentType();
}
#Override
public Resource getWrapped() {
return resource;
}
};
}
#Override
public boolean isResourceRequest(FacesContext context) {
return ResourceHandler.RESOURCE_IDENTIFIER.equals(context.getExternalContext().getRequestServletPath());
}
#Override
public void handleResourceRequest(FacesContext context) throws IOException {
ExternalContext externalContext = context.getExternalContext();
String resourceName = externalContext.getRequestPathInfo();
String libraryName = externalContext.getRequestParameterMap().get("ln");
Resource resource = context.getApplication().getResourceHandler().createResource(resourceName, libraryName);
if (resource == null) {
super.handleResourceRequest(context);
return;
}
if (!resource.userAgentNeedsUpdate(context)) {
externalContext.setResponseStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
externalContext.setResponseContentType(resource.getContentType());
for (Entry<String, String> header : resource.getResponseHeaders().entrySet()) {
externalContext.setResponseHeader(header.getKey(), header.getValue());
}
ReadableByteChannel input = null;
WritableByteChannel output = null;
try {
input = Channels.newChannel(resource.getInputStream());
output = Channels.newChannel(externalContext.getResponseOutputStream());
for (ByteBuffer buffer = ByteBuffer.allocateDirect(10240); input.read(buffer) != -1; buffer.clear()) {
output.write((ByteBuffer) buffer.flip());
}
}
finally {
if (output != null) try { output.close(); } catch (IOException ignore) {}
if (input != null) try { input.close(); } catch (IOException ignore) {}
}
}
#Override
public ResourceHandler getWrapped() {
return wrapped;
}
}
Register it as follows in faces-config.xml:
<application>
<resource-handler>com.example.UnmappedResourceHandler</resource-handler>
</application>
Extend the FacesServlet URL pattern with ResourceHandler.RESOURCE_IDENTIFIER:
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
<url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>
You could have a look at Rewrite. Rewrite allows to modify URLs that are rendered to the page and modify them in any way you want. You could do something like this to add a CDN To your site:
.addRule(CDN.relocate("{p}foo-{version}.css")
.where("p").matches(".*")
.where("version").matches(".*")
.to("http://mycdn.com/foo-{version}.css"));
I think it should be easy to implement your requirement using Rewrite.
Have a look at the example configurations to learn about the features of rewrite.

Reading .properties file only once while web app deployment

Having a Java web application, how does one read properties file only once when the app is deployed (storing them later in some singleton)? Meaning, configuration changes would require redeployment.
Otherwise, is there an alternative way to prevent an app from constantly reading .properties file? Previously I had settings in my web.xml file, but now .properties is required.
Code used to read app settings from JBoss configuration path:
File f = new File(System.getProperty("jboss.server.config.dir"),
"myappsettings.properties");
Properties p = new Properties();
p.load(new FileInputStream(f));
try {
db_name = p.getProperty("DATABASE_NAME"));
file_path = p.getProperty("FILE_PATH"));
...
} catch (Exception e) {
...
}
Starting with JEE6, another alternative to the ServletContextListener could be using a singleton startup bean:
#Singleton
#Startup
public class PropertyRegistry {
#PostConstruct
private void init(){
//do something
}
}
Implement your own ServletContextListener:
public class PropertiesReadingListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
//read properties here...
event.
getServletContext().
setAttribute("db_name", p.getProperty("DATABASE_NAME"));
}
#Override
public void contextDestroyed(ServletContextEvent event) {
}
}
You must reference this class in web.xml:
<listener>
<listener-class>com.example.PropertiesReadingListener</listener-class>
</listener>

Categories

Resources