I have a pretty standard web app running under Tomcat 7.
What I'm now trying to do is leverage JSP/JSTL as a templating language independent of the HTTP/web serving aspects of Tomcat to produce HTML that can be emailed and converted to PDF.
Has anyone else tried to do this before and could help me with some pointers?
Thanks in advance.
In contrast to what Stephen C said, yes, JSP are Servlets, etc. etc. (And Velocity is quite good and easy to use)
But, what is a Servlet?
It's an interface. An interface with one major method:
service(ServletRequest req, ServletResponse res)
Locate the JSP class, cast it to a Servlet, create implementations of ServletRequest and ServletResponse, and then...
String jspClassName = findJspClassForJSP("your.jsp");
Class jspClass = Class.forName(jspClassName);
Servlet jspServlet = (Servlet)jspClass.newInstance();
MyServletRequest req = new MyServletRequest();
MyServletResponse resp = new MyServletResponse();
jspServlet.init();
jspServlet.service(req, resp);
jspServlet.destroy();
String results = reps.getContent();
Will this work? Well, after some work it will. Obviously you need to implement the minimum facades of the ServletRequest/Response as well as what ever your JSPs will need. But, likely you will probably need little more than the attributes and the streams. If you make your Response return a StringWriter, you're halfway there.
The next part is creating the servlet from the JSP. Handily, the Jasper compiler does that for you -- the game is invoking it. I have never done it directly, but it clearly can be done since both the servlet container does it, as well as the JSPC script/bat file, the ant task, as well as most of the Servlet containers out there use Jasper. So, that can be done. Once you know how to invoke that, you'll know the final generated class name for the JSP. (See the first line of the sample.)
Have I ever done this? No. But I bet within less than a day of messing around you'll know whether this is doable or not. I'm betting it is, especially if you don't run in to any class loader shenanigans. You'll possibly have an issue if you let your users change and regenerate a JSP (so MyEmail.jsp gets compiled in to MyEmail.class, MyEmail_2.class, etc.). But if you invoke Jasper yourself, you'll likely have more control over this.
The other hard part is determining the class name of the JSP. Most of the containers follow a basic pattern here, so if you poke around in the generated code from a WAR you'll likely find it.
Keep the JSPs reasonably simple (and an Email template shouldn't need to super complicated with embedded Java or anything making random calls), and it even more a good chance it will work.
Your solution may not be portable out of the box out of Tomcat, but you likely won't care. The folks that I've talked to that use JSP for templates, simply opened a socket to their own server and made a request. They didn't go this far either.
But on the surface, save some whacky class loader black hole hell, I bet you can get this to work pretty quick. Implement as little of the request and response as you need to, fight a few NPEs as the JSP and JSTL call stuff you weren't planning, and, as Santa says,
Hack away, Hack away, Hack away all!
Addenda:
So, for all the naysayers...
public void runJsp() {
JspC jspc = new JspC();
jspc.setUriroot("/tmp/app");
jspc.setOutputDir("/tmp/dest");
jspc.setJspFiles("newjsp.jsp");
jspc.setCompile(true);
try {
jspc.execute();
Class cls = Class.forName("org.apache.jsp.newjsp_jsp");
Servlet s = (Servlet) cls.newInstance();
MyRequest req = new MyRequest();
MyResponse resp = new MyResponse();
s.init(getServletConfig());
s.service(req, resp);
s.destroy();
System.out.println(resp.getSw().toString());
} catch (JasperException ex) {
throw new RuntimeException(ex);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (ServletException ex) {
throw new RuntimeException(ex);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
Amazing what source code and 1/2 hour in a debugger will do for you.
I created a simple JSP in /tmp/app/newjsp.jsp.
jspc.setUriroot tells the compiler where the base of your "web app" is located. jspc.setOutputDir tells jspc where to put the generated Java and Class files. jspc.setJspFiles tells jspc what files to compile, based off of the URI Root. jspc.setCompile told it to actually compile the code. Finally, jspc.execute() does the deed.
By default Jasper uses the package org.apache.jsp, and creates a new class based on the JSP file name. For my simple experiment, I simply put "/tmp/dest" on to the class path of my Glassfish container, so that the container would find the generated classes.
I load the class, and get an instance.
Finally, I created MyRequest, MyRequest, and, ultimately, MySession. My IDE conveniently created stubs for the respective interfaces. In this case I implemented: MyRequest.getSession(), MyResponse.setContentType(), MyResponse.setBufferSize(), and MyResponse.getWriter().
public PrintWriter getWriter() throws IOException {
if (sw == null) {
sw = new StringWriter();
pw = new PrintWriter(sw);
}
return pw;
}
Obviously sw and pw are instance variables of MyResponse.
MyRequest returned an instance of MySession. My implementation of MySession does -- nothing. But the runtime wanted a Session, it just doesn't use it on its own for my very simple JSP, and I wasn't motivated on stuffing in the the one from the Servlet.
I tested this on Glassfish v2.1. I simply added appserv_rt.jar (from glassfish/lib) to my build class path (so it could find the JspC jars), but I don't bundle it in the WAR (since it's already in the container).
And, shazam, it worked. In "real life", assuming the process that wanted to leverage the JSP was actually sourced from a web request, I would simply create an HttpServletResponseWrapper and override the earlier three methods, the rest would probably Just Work. If a web request isn't in the picture at all, then you'd need to create your own Session implementation (no big deal really, it's just a map).
I'd also use a private URLClassLoader to load the faux JSP classes. If I KNEW I'd never reload a JSP, then would just make the destination my WEB-INF/classes directory and give it it's own package and let the system load them.
But, yup, it worked. No big deal. It's just java.
This doesn't really make sense. A JSP is some nice syntax that results in the generation of a Java EE servlet class. Indeed, the "servlet" / "http" nature of a JSP is thoroughly intertwined through the APIs and the semantic model of JSPs and JSTL.
If you want to generate HTML independently of web requests, you would be better of using a different templating technology; e.g. Velocity or FreeMarker. If you then want the HTML to be delivered as web responses as well, arrange that your servlets call the templating engine to generate responses. (If you are using Spring there is existing infrastructure for this. Other frameworks may have similar support, but if not, it shouldn't be hard to implement some glue code yourself to do this.)
Related
I have a service that saves a tree-like structure to a database. Before persisting the tree, the tree gets validated, and during validation, a number of things can go wrong. The tree can have duplicate nodes, or a node can be missing an important field (such as its abbreviation, full name, or level).
In order to communicate to the service what went wrong, I'm using exceptions. When the validateTree() method encounters a problem, it throws the appropriate exception. The HttpService class then uses this exception to form the appropriate response (e.g. in response to an AJAX call).
public class HttpService {
private Service service;
private Logger logger;
// ...
public HttpServiceResponse saveTree(Node root) {
try {
service.saveTree(root);
} catch (DuplicateNodeException e) {
return HttpServiceResponse.failure(DUPLICATE_NODE);
} catch (MissingAbbreviationException e) {
return HttpServiceResponse.failure(MISSING_ABBREV);
} catch (MissingNameException e) {
return HttpServiceResponse.failure(MISSING_NAME);
} catch (MissingLevelException e) {
return HttpServiceResponse.failure(MISSING_LEVEL);
} catch (Exception e) {
logger.log(e.getMessage(), e. Logger.ERROR);
return HttpServiceResponse.failure(INTERNAL_SERVER_ERROR);
}
}
}
public class Service {
private TreeDao dao;
public void saveTree(Node root)
throws DuplicateNodeException, MissingAbbreviationException, MissingNameException, MissingLevelException {
validateTree(root);
dao.saveTree(root);
}
private void validateTree(Node root)
throws DuplicateNodeException, MissingAbbreviationException, MissingNameException, MissingLevelException {
// validate and throw checked exceptions if needed
}
}
I want to know, is this a good use of exceptions? Essentially, I'm using them to convey error messages. An alternative would be for my saveTree() method to return an integer, and that integer would convey the error. But in order to do this, I would have to document what each return value means. That seems to be more in the style of C/C++ than Java. Is my current use of exceptions a good practice in Java? If not, what's the best alternative?
No, exceptions aren't a good fit for the validation you need to do here. You will likely want to display multiple validation error messages, so that the user can see all the validation errors at once, and throwing a separate exception for each invalid input won't allow that.
Instead create a list and put errors in it. Then you can show the user the list of all the validation errors.
Waiting until your request has gotten all the way to the DAO seems like the wrong time to do this validation. A server-side front controller should be doing validation on these items before they get passed along any farther, as protection against attacks such as injection or cross-site scripting.
TL;DR The Java-side parts you showed us are nearly perfect. But you could add an independent validation check and use that from the client side before trying to save.
There are many software layers involved, so let's have a look at each of them - there's no "one size fits all" answer here.
For the Service object, it's the perfect solution to have it throw exceptions from the saveTree() method if it wasn't able to save the tree (for whatever reason, not limited to validation). That's what exceptions are meant for: to communicate that some method couldn't do its job. And the Service object shouldn't rely on some external validation, but make sure itself that only valid data are saved.
The HttpService.saveTree() should also communicate to its caller if it couldn't save the tree (typically indicated by an exception from the Service). But as it's an HTTP service, it can't throw exceptions, but has to return a result code plus a text message, just the way you do it. This can never contain the full information from the Java exception, so it's a good decision that you log any unclear errors here (but you should make sure that the stack trace gets logged too!), before you pass an error result to the HTTP client.
The web client UI software should of course present detailed error lists to the user and not just a translated single exception. So, I'd create an HttpService.validateTree(...) method that returns a list of validation errors and call that from the client before trying to save. This gives you the additional possibility to check for validity independent of saving.
Why do it this way?
You never have control what happens in the client, inside some browser, you don't even know whether the request is coming from your app or from something like curl. So you can't rely on any validation that your JavaScript (?) application might implement. All of your service methods should reject invalid data, by doing the validation themselves.
Implementing the validation checks in a JavaScript client application still needs the same validation inside the Java service (see above), so you'd have to maintain two pieces of code in different languages doing exactly the same business logic - don't repeat yourself! Only if the additional roundtrip isn't tolerable, then I'd regard this an acceptable solution.
Visible and highly noticeable, both in terms of the message itself and how it indicates which dialogue element users must repair.
From Guru Nielsen,
https://www.nngroup.com/articles/error-message-guidelines/
I have to make a Java webapp that would listen for incoming HTTP POST requests, then retrieve the XML contained in the request body in order to process it.
I am using Maven 4, Hibernate 3 and XML-RPC server. I successfully imported XML-RPC jar files using Maven.
Though everyone seem to say XML-RPC is the simpliest thing on earth, I am having a hard time implementing it. I am quite new to webapps.
Looking at Apache XML-RPC tutorial I understand I need to create a class such as:
public class MyServer extends XmlRpcServlet {
private XmlRpcServer server = new XmlRpcServer();
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
server.addHandler("myProcess", new MyProcessHandler);
byte[] result = server.execute (request.getInputStream());
response.setContentType ("text/xml");
response.setContentLength (result.length());
OutputStream out = response.getOutputStream();
out.write (result);
out.flush ();
}
}
But that won't compile because the "execute" method expects a XmlRpcRequest parameter. Any hint about what I am doing wrong?
Aside from that, I don't understand how I am going to get the request's body from my function myProcess(). I have a MyProcessHandler class (which extends no class) implementing a myProcess() function. Do I need to add a parameter in this function? Is so then which type would it be?
The main problem lies in the XML-RPC version: Apache first made an old version named helma-xmlrpc, then refactored it with deep changes into org.apache.xmlrpc. Though Apache updated some parts of its XML-RPC online documentation, some other parts still reference helma-xmlrpc with no hint, on each page, of the version used.
Moreover, Apache says that projects using helma-xmlrpc only have to update their imports in order to use the new version org.apache.xmlrpc, no impacts on the code - That's totally wrong. Some methods and even some classes disappeared, or the signature changed, and some classes have been put into sub-directories, so the imports don't work anymore.
Okay. So once I figured out that, I also understood that most of the Internet tutorials dealing with Apache XML-RPC use the old helma-xmlrpc version, but show their imports as org.apache.xmlrpc. As a result, the implementations they present won't work if you paste it in your own project which uses org.apache.xmlrpc. It doesn't even compile.
I looked over the Internet for up-to-date org.apache.xmlrpc-implementation-with-servlets tutorials with no result. Hence I decided to use old helma-xmlrpc and all went well. With Helma, the code I posted in my first message now compiles and is right.
As for the link between the listener and MyProcessHandler class, it exists thanks to the addHandler function. Once the handler is declared, all incoming requests with methodName like 'myProcess.myFunction' are automatically redirected toward MyProcessHandler.myFunction() when the instruction server.execute(...) is processed.
For that to work, myFunction() must declare one String input parameter. When myFunction() will be called, this parameter contains the body of the request (extracted by request.getInputStream() in the servlet). myFunction() also has to return something, which will be returned into the byte[] result variable of the servlet.
I made good use of the link below, very complete and treating of helma-xmlrpc only with no pretense of using org.apache.xmlrpc...: http://www.perfectxml.com/oreilly/chapter.asp?row_id=11
I hope this answer is clear enough (my English speaking is not perfect...) and it will help other developers to understand Apache XML-RPC.
You can use XmlRpcServletServer (apache xml-rpc 3.1.3):
public class EmbeddedXmlRpc extends HttpServlet
{
...
protected XmlRpcServletServer server = new XmlRpcServletServer();
...
server.setHandlerMapping(phm);
...
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
server.execute(request, response);
}
}
I'm currently having problems with a little project I'm working on. In this project I'm trying to dynamically create Classes from a configuration String and load it into the JVM.
When I do this in a "normal" environment (Unit Tests) everything works fine. But when I try to create the Classes in an OSGI environment (Apache Karaf) I receive a ClassFormatError with the Message "Illegal class name "Ljava/lang/String;" in class ...".
After a short research I found out that this problem occurs for classes in java/lang when they are not loaded by the system class loader but I'm everything else than an expert when it comes to class loading in java and especially OSGi.
I think the way I'm getting access to the defineClass method could be of interest for this problem so here it is:
PROTECTION_DOMAIN = (ProtectionDomain) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return RestEndpoint.class.getProtectionDomain();
}
});
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
Class loader = Class.forName("java.lang.ClassLoader");
DEFINE_CLASS = loader.getDeclaredMethod("defineClass",
new Class[]{ String.class,
byte[].class,
Integer.TYPE,
Integer.TYPE,
ProtectionDomain.class });
DEFINE_CLASS.setAccessible(true);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
return null;
}
});
The last (hopefully useful) piece of information is the ClassLoader I am invoking the defineClass method on when running my project in an OSGi bundle: It is an instance of org.apache.felix.framework.BundleWiringImpl.
It would be great if someone could help me out here!
Greetings,
Pascal
EDIT:
I need to define classes at runtime because I want to avoid boilerplate code in my project and make the program more consistent.
To be more precise my project will be a RESTful WebService. Since I'm using multiple technologies to store data and snychronize processes (mongoDB, MySQL, activeMQ, ...), I want to use Apache camel to deal with all the different technologies.
The problem is that there is no possibility I know of to nicely integrate Camel with the Java approach on REST (The whole mapping of methods and classes to HTTP requests is done with Annotations).
So the only possibility for me was to write methods which would place parameters of the request in the exchange headers of Camel and fire them to the route.
To avoid this I wanted to automate this process by defining those classes at runtime from the route definitions.
Write your own class loader whose parent is the bundle's class loader instead of trying to hack into the existing class loader.
I'm working on a JSR-303 validation framework for GWT. Some of you may have heard of it even though it is a small project. Here is gwt-validation.
In the old days (v1.0) it used a marker interface for each class and each class had metadata generated separately. This was bad because it was not part of the JSR-303 standard and we moved on to the next idea.
In version 2.0 it scans the classpath at runtime using Reflections. This is great. The downside is that it doesn't seem to be able to work inside of containerized environments or those with special restrictions.
This is probably my fault, look at the following code:
//this little snippet goes through the classpath urls and ommits jars that are on the forbidden list.
//this is intended to remove jars from the classpath that we know are not ones that will contain patterns
Set<URL> classPathUrls = ClasspathHelper.forJavaClassPath();
Set<URL> useableUrls = new HashSet<URL>();
for(URL url : classPathUrls) {
boolean use = true;
for(String jar : this.doNotScanJarsInThisList) {
if(url.toString().contains(jar)) {
use = false;
break;
}
}
if(use) {
useableUrls.add(url);
}
use = false;
}
ConfigurationBuilder builder = new ConfigurationBuilder()
.setUrls(useableUrls)
.setScanners( new TypeAnnotationsScanner(),
new FieldAnnotationsScanner(),
new MethodAnnotationsScanner(),
new SubTypesScanner()
)
.useParallelExecutor()
;
this.reflections = new Reflections(builder);
I'm using the filter to remove jars that I know can't have annotations in them that I'm interested in. As I mention this gives a huge speed boost (especially on large classpaths) but the ClasspathHelper.forJavaClassPath() that I'm basing this on probably isn't the best way to go in container environments. (e.g. Tomcat, JBoss)
Is there a better way or at least a way that will work with a container environment and still let my users filter out classes they don't want?
I've looked, some, into how the Hibernate Validation project (the reference implementation for JSR-303) and they appear to at least be using (at least in part) the Annotations Processing in Java 6. This can't be all of the story because that didn't show up until JDK6 and Hibernate Validator is JDK5 compatible. (See: hibernate documentation)
So, as always, there's more to the story.
I've read these threads, for reference:
About Scannotation which has been pretty much replaced by Reflections.
This one but it uses File and I'm not sure what the implications are of that in things like GAE (Google App Engine) or Tomcat.
Another that goes over a lot of the things I've talked about already.
These threads have only helped so much.
I've also read about the annotation processing framework and I must be missing something. It appears to do what I want but then again it appears to only work at compile time which I know isn't what is done by Hibernate Validator. (Can anyone explain how it does scanning? It works on GAE which means it can't use any of the IO packages.)
Further, would this code work better than what I have above?
Set<URL> classPathUrls = ClasspathHelper.forClassLoader(Thread.currentThread().getContextClassLoader());
Could that correctly get the classloader inside of a Tomcat or JBoss container? It seems scan a smaller set of classes and still finish okay.
So, in any case, can anyone help me get pointed in the right direction? Or am I just stuck with what I've got?
You could take a look at Spring's annotation support.
Spring can scan annotations in files (using asm IIRC), and works in and out of a container.
It may not be easy because it goes through Spring's Resource abstraction, but it should be doable to reuse (or extract) the relevant code.
What is the best way to enable my webapplication to use JSF files stored in the database?
I'd like to be able to dynamically (during runtime) create new JSF pages which will be made available without having to redeploy the application.
So in other words: I would like to store the bigger part of my JSF pages in the database and would like JSF to use the database as a datasource for getting JSF files.
I've thought long about a solution and found some possible ways. However, I haven't been able to implement either of them.
Whenever a new page has to be added/removed: manipulate the files in the classpath (e.g. remove or add a file to the .war file)
Extending the classpath of the webapplication so it will be able to get files from an at runtime defined location (i.e. /tmp or directly using a database connection)
Provide JSF with a way to find resources another way ( this doesn't seem possible? )
My environment:
Java SE 6
Jetty as servlet container
Mojarra as jsf implementation
Now, my question:
Is it possible for someone to let JSF find pages at a location other than the default classpath, preferably the database?
Any response is greatly appreciated!
1: Whenever a new page has to be added/removed: manipulate the files in the classpath (e.g. remove or add a file to the .war file)
This is definitely possible if the WAR is expanded. I am not sure about Jetty, but it works for me with Mojarra 2.x on Tomcat 7 and Glassfish 3. Just writing the file to the expanded WAR folder the usual Java IO way suffices.
File file = new File(servletContext.getRealPath("/foo.xhtml"));
if (!file.exists()) {
OutputStream output = new FileOutputStream(file);
try {
output.write(bytes); // Can be bytes from DB.
} finally {
output.close();
}
}
This needs to be executed before the FacesServlet kicks in. A Filter is a perfect place. See also this related answer:
How to create dynamic JSF form fields
2: Extending the classpath of the webapplication so it will be able to get files from an at runtime defined location (i.e. /tmp or directly using a database connection)
You can package Facelets files in a JAR file and put it in the classpath and provide a Facelets ResourceResolver which serves the files from the JAR on when no match is found in WAR. You can find complete code examples in the following answers:
how to share a jsf error page between multiple wars
How to create a modular JSF 2.0 application?
3: Provide JSF with a way to find resources another way ( this doesn't seem possible? )
You've plenty of play room in the custom ResourceResolver.
Nice question. BalusC's answer is - as always - complete and right.
However, if your point is to create an application where gui is built dynamically, there is a way that might serve you better (depending on what you really want to achieve).
JSF views are similar to Swing forms - they are just a bunch of JavaBeans(tm) glued together. The big difference is that when a field is bound to an EL expression, you do not use standard accessors, but rather a special method (setValueExpression).
This means you can build your GUI from objects (the concrete classes can be found in javax.faces.component.html) in a pure programmatic way and then use binding attribute to show it on page. Something like:
<h:form>
<h:panelGrid binding="#{formBuilder.component}"/>
</h:form>
And then in the managed formBuilder bean:
#PostConstruct
public void init() {
HtmlInputText hit = new HtmlInputText();
// properties are easy:
hol.setStyle("border: 2px solid red");
// binding is a bit harder:
hit.setValueExpression("value", expression("#{test.counter}", String.class));
HtmlOutcomeTargetLink hol = new HtmlOutcomeTargetLink();
hol.setValue("link leading to another view");
hol.setOutcome("whatever");
component = new UIPanel();
component.getChildren().add(hit);
component.getChildren().add(hol);
}
private ValueExpression expression(String s, Class c){
return FacesContext.getCurrentInstance().getApplication().getExpressionFactory().createValueExpression(
FacesContext.getCurrentInstance().getELContext(),
s, c
);
}
The example above builds a static panel, but it would be possible to:
create an object model of your GUI
map the model to database (with hibernate or another orm)
write some kind of adapter or bridge to build JSF objects from your object model
make a managed bean that receives the form id, grabs the relevant form from database, builds a JSF panel out of it and presents it as a property, ready to be bound.
This way you could have just one static xhtml with a single tag and use it to present any number of dynamic forms.
As I said, this method could be better than just storing files, but not necessarily. If you just want to save yourself the hassle of redeployment, this is a huge overkill (then again, you do NOT need to redeploy JSF applications just to change forms). If on the other hand your goal is to have something like user-defined and edited forms, having a good object model and storing it in a proper way could be a good idea.
The bumps ahead would be:
navigation (perhaps a custom navigation handler would suffice?)
problems with generating plain html
possibly some problems with lifecycle of view scoped forms