how to share a jsf error page between multiple wars - java

I'm trying to share an error page (error.xhtml) between multiple wars. They are all in a big ear application, and all use a common jar library, where I'd like to put this.
The error page should use web.xml, or better web-fragment.xml, and would be declared as a standard java ee error page.
Actual EAR structure:
EAR
EJB1
EJB2
WAR1 (using CommonWeb.jar)
WAR2 (using CommonWeb.jar)
WAR3 (using CommonWeb.jar)
Just putting the error page under META-INF/resources won't work, as it's not a resource.
I'd like to have as little as possible to configure in each war file.
I'm using Glassfish 3.1, but would like to use Java EE 6 standards as much as possible.

You need to create a custom ResourceResolver which resolves resources from classpath, put it in the common JAR file and then declare it in web-fragment.xml of the JAR (or in web.xml of the WARs).
Kickoff example:
package com.example;
import java.net.URL;
import javax.faces.view.facelets.ResourceResolver;
public class FaceletsResourceResolver extends ResourceResolver {
private ResourceResolver parent;
private String basePath;
public FaceletsResourceResolver(ResourceResolver parent) {
this.parent = parent;
this.basePath = "/META-INF/resources"; // TODO: Make configureable?
}
#Override
public URL resolveUrl(String path) {
URL url = parent.resolveUrl(path); // Resolves from WAR.
if (url == null) {
url = getClass().getResource(basePath + path); // Resolves from JAR.
}
return url;
}
}
with in web-fragment.xml or web.xml
<context-param>
<param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
<param-value>com.example.FaceletsResourceResolver</param-value>
</context-param>

Related

Can I set jetty classloading semantics using system properties?

In our project, we start embedded Jetty using only the Java API (no external xml, etc.), and then deploy war bundles to it. Now I have a situation where I'm getting ClassCastExceptions because of differing jars loaded from the .war vs. what is on the actual classpath. Reading the Jetty page on classloading (https://www.eclipse.org/jetty/documentation/current/jetty-classloading.html) I wanted to see if I could configure the WebAppClassLoader to augment the set of classes considered to be 'system' classes. There is a Java API to do this (WebAppContext.setServerClasses()) and a way to do it if you're using an xml config file:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="serverClasses">foo.bar.,com.acme.</Set>
...
But I'd like to know if it is possible to do it using just Java system properties.
Thanks!
There are no system properties to configure server or system classes on a WebAppContext.
This is because that kind of change is considered to belong to a specific WebApp, not all WebApps.
But, you have an alternative, if you are using the DeploymentManager in your embedded-jetty, you are in luck, you have an option in code.
You'll want to create a custom AppLifeCycle.Binding which sets those properties on any deployed WebAppContext (I would recommend binding to deploying).
Here's an example that forces the WebAppContext's to always use the logging libraries from the server/system classloader.
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.AppLifeCycle;
import org.eclipse.jetty.deploy.graph.Node;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.webapp.WebAppContext;
public class CentralizedWebAppLoggingBinding implements AppLifeCycle.Binding
{
public String[] getBindingTargets()
{
return new String[]
{ "deploying" };
}
public void processBinding(Node node, App app) throws Exception
{
ContextHandler handler = app.getContextHandler();
if (handler == null)
{
throw new NullPointerException("No Handler created for App: " + app);
}
if (handler instanceof WebAppContext)
{
WebAppContext webapp = (WebAppContext)handler;
webapp.addSystemClass("org.apache.log4j.");
webapp.addSystemClass("org.slf4j.");
webapp.addSystemClass("org.apache.commons.logging.");
}
}
}
And here's an example of using DeploymentManager from embedded-jetty (with the above CentralizedWebAppLoggingBinding too.
ContextHandlerCollection contexts = new ContextHandlerCollection();
DeploymentManager deployer = new DeploymentManager();
if(debugIsEnabled)
{
DebugListener debug = new DebugListener(System.err, true, true, true);
server.addBean(debug);
deployer.addLifeCycleBinding(new DebugListenerBinding(debug));
}
deployer.setContexts(contexts);
deployer.setContextAttribute(
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$");
WebAppProvider webAppProvider = new WebAppProvider();
webAppProvider.setMonitoredDirName(jettyBase + "/webapps");
webAppProvider.setDefaultsDescriptor(jettyHome + "/etc/webdefault.xml");
webAppProvider.setScanInterval(1);
webAppProvider.setExtractWars(true);
webAppProvider.setConfigurationManager(new PropertiesConfigurationManager());
webAppProvider.addLifeCycleListener(new CentralizedWebAppLoggingBinding());

Spring: How to access contents of webapp/resources in service layer

How do I access the contents of my webapp/resources folder from the service layer? I need to access a JSON file to be used for Elasticsearch mappings...
This is how my project structure looks like:
https://www.dropbox.com/s/crdzae1ko0x9p89/Screenshot%202015-05-25%2010.24.12.png?dl=0
I tried this:
http://www.mkyong.com/java/java-read-a-file-from-resources-folder/
String mapping = String.format("es_mappings/%s.json", type);
ClassLoader classLoader = getClass().getClassLoader();
String result = IOUtils.toString(classLoader.getResourceAsStream(mapping));
But I got a null pointer exception for the third line in the code snippet above.
Also tried this:
File file = ResourceUtils.getFile("classpath:es_mappings/bom_exports.json")
String txt= FileUtils.readFileToString(file);
But I got this error: java.io.FileNotFoundException: class path resource [es_mappings/bom_exports.json] cannot be resolved to absolute file path because it does not reside in the file system.
I have this in my -servlet.xml file:
<mvc:resources location="/resources/" mapping="/resources/**"/>
Thanks.
I using this code. It's simple and works.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
// ...
#Value("/resources/json/your_file.json")
private Resource jsonResource;
// ...
InputStream jsonStream = jsonResource.getInputStream();
Now you can use stream to read json.
Using relative paths depends on the classloader, so you need to either work out where your classloader is looking or else just use an absolute path -
when using getResourceAsStream you need to start with a leading / so try this:
String mapping = String.format("/es_mappings/%s.json", type);
ClassLoader classLoader = getClass().getClassLoader();
String result = IOUtils.toString(classLoader.getResourceAsStream(mapping));
Also I'm not sure the webapp/resources folder will be added to the classpath by default in maven. Usually resources like files you need to access at runtime would be in the src/main/resources directory. (but I could be wrong, the easy way to tell is check the packaged war file, if the files are in /WEB-INF/classes then they are on the classpath)
ResourceUtils.getFile("classpath:es_mappings/bom_exports.json")
This method get resources file from the webapp/WEB-INF/classes when you pass classpath:*.
If you want get the json file from webapp/resources/es_mappings/your_file.json, the service class can implement the interface ServletContextAware and get servletContext. Because the webapp directory is determined by the web container such as tomcat or jetty, it only get the relative path from servletContext.getResource(). That method can get resources under webapp.
Code example maybe like:
class your_service implements ServletContextAware {
private ServletContext servletContext;
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public void getJsonResource() {
...//other code
String josnFilepath = servletContext.getResource(
"/resources/es_mappings/your_file.json");
}
}
Also you can get the webapp directory by finding "WEB-INF/classes" substring in classpath.
String path = this.getClass().getResource("").getPath();
String fullPath = URLDecoder.decode(path, "utf-8");
String pathArr[] = fullPath.split("/WEB-INF/classes/");
if (2 == pathArr.length) { //pathArr[0] is webapp directory path
String jsonFilepath = pathArr[0] + "/resources/es_mappings/your_file.json";
}

Get fully qualified resource name in web application in Java

I would like to get access to files in resources folder my web app (independently from this is exploaded WAR or not). I have already used servletContext via Spring to getResource also FileSystem context.
In the end, I choose Spring ResourceLoader because seems that it's the most suitable approach in my case.
I don't like use #PropertySources annotation and get access to particular properties of *.properties files.
UPDATED
I deployed my app using Webspehere Liberty Profile.
#Component
public class FileCreator {
#Autowired
private ResourceLoader resourceLoader;
public String getRealPath(String location) {
String realPath = null;
try {
Resource resource = resourceLoader.getResource(location);
String resourceDesc = resource.getDescription();
realPath = resource.getURI().getPath();
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
return realPath;
}
}
I have common maven layout for my Gradle app. It means that myApp.properties file located in /WEB-INF/classes folder
String scheduledServicesRealPath1 = fileCreator.getRealPath("classpath:myApp.properties");
I want to get the absolute path for this file but I 'm getting just null.
Does it exist any approach which can access resources independently from Application server, way of presentation of app on server (exploaded or not) and independent from file system?

Configure Jersey MVC to serve Viewable without web.xml

The important part is: without web.xml.
I already have a working JAX-RS app running on Glassfish 3.1.2.2 without a web.xml, configured purely by annotations.
The question is, how can I maintain the web.xml-less nirvana and still use Jersey MVC to serve static resources from the resources or webapp directory of my Maven .war project?
I see in many answers how can I do this with web.xml configuration, but nobody mentions how to map resources without the web.xml file.
Currently I have a ui.html file under the resources directory, a JAX-RS Application subclass and a resource class. No web.xml in the project and the following is working well:
#Path("/ui")
#GET
public Response ui() {
String content = "Hello StackOverflow";
return Response.ok(content).build();
}
While this one is failing with the IOException from the resolver:
#Path("/ui")
#GET
public Response ui() {
Viewable viewable = new Viewable("/ui.html");
return Response.ok(viewable).build();
}
java.io.IOException: The template name, /ui.html, could not be resolved to a fully qualified template name
I also tried to specify it with a relative path, but that didn't work either.
The dependencies I'm using for Jersey are as follows:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.18</version>
</dependency>
I understand that a proper example project would be the best and willing to provide that if people are having a hard time figuring out what I'm talking about, just let me know.
Peter Metz, I believe this is possible by using the #WebFilter annotation on a class that extends org.glassfish.jersey.servlet.ServletContainer (Jersey 2.26):-
package com.myorg.myapp.config;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import org.glassfish.jersey.servlet.ServletContainer;
#WebFilter(value = "/*", initParams = #WebInitParam(name = "javax.ws.rs.Application", value = "com.myorg.myapp.config.JerseyConfig"))
public class JerseyFilter extends ServletContainer {
private static final long serialVersionUID = 1L;
}

Import location in wsit-client.xml to file in another jar, using an URL string to locate a file on the classpath

Normally the wsit-client.xml has import statements like this:
<import location="foo.xml" namespace="http://foo.org/" />
I've found that their can be online one wsit-client.xml on the classpath/META-INF, but can I refer to an xml who's located into another jar in that wsit-client.xml? Something like :
<import location="classPathResource/WEB-INF/foo.xml" namespace="http://foo.org/" />
I would like to create a single wsit-client.xml who contains the imports for all my webservices but I want to separate the configuration for all the different webservices in to different projects.
I've fixed it by creating an URLStreamHandler in the wsit-client.xml I can now define location="myprotocol://foo.xml"
I've used spring's PathMatchingResourcePatternResolver to locate my xml file in another project/jar.
public class Handler extends URLStreamHandler {
#Override
protected URLConnection openConnection(URL u) throws IOException {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
final URL resourceUrl = resolver.getResource(u.getPath()).getURL();
if (resourceUrl == null) {
throw new IOException(String.format("File %s not found on the classpath", u.getFile()));
}
return resourceUrl.openConnection();
}
}
I'm not using the VM arguments to define the handler but I've implemented an URLStreamHandlerFActory like explained over here URL to load resources from the classpath in Java
More info about writing your own protocol handlers can be find on this site: http://java.sun.com/developer/onlineTraining/protocolhandlers/
I've still got 1 project who contains the single wsit-client.xml with references to all my web service configurations, but at least I've managed to separate the configuration for all the different services in different maven projects.

Categories

Resources