I am writing a class in JSP to retrieve a bunch of config values from an XML file. My plan is to have a class "XMLConfig" that loads in the values from the file, and then uses access methods to get at the values in the config object.
My problem is that i cannot seem to call application.getRealPath() from within the class, since eclipse tells me that "application cannot be resolved". I suspect that I must change "application" to something else but I am unsure what.
My code for the class:
<%!
//Config object
public class XMLConfig {
public boolean loadConfigFile(String strName) {
String XMLfileName = application.getRealPath(strName);
try {
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = null;
doc = db.parse(XMLFileName);
}catch(Exception e)
{
System.out.println(e.getMessage());
return false;
}
return true;
}
}
%>
application isn't a global var. If you want to use it in your method then you'll need to pass it as a parameter.
Not sure why you're defining the class within the jsp though instead of just creating a 'normal' java class.
That's a job for a servlet instead of JSP. Create a class which extends HttpServlet and implement the doGet() method as follows:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String strName = getOrDefineItSomehow();
Document doc = loadConfigFile(getServletContext().getRealPath(strName));
// Do whatever you want with it and then display JSP page.
request.getRequestDispatcher("/WEB-INF/config.jsp").forward(request, response);
}
Map this servlet in web.xml on an url-pattern of for example /config and invoke it by for example http://example.com/context/config. It'll run the code in doGet().
See also:
Beginning and intermediate JSP/Servlet tutorials
How to avoid Java code in JSP?
Hidden features of JSP/Servlet
Related
I have pojo classes that handle my backend connections. I want to encapsulate my (backend) error handling in these classes by catching backend exceptions inside.
Is there any way to access the current wicket page (or any component for that matter) to enable me to give feedback to the user from outside the wicket component hierarchy?
class MyService {
...
public void doBackEndThing(){
try {
backEndService.doRemoteCall();
} catch (BackendException e) {
//we're not inside the component hierarchy! so no getPage() available
WebPage page = getCurrentPage();
page.error("Backend is currently not available");
}
}
I've tried the PageManager, but I have no idea how to retrieve the correct version and so I do not know if would work at all:
int version = ?;
WebPage page = (WebPage )Session.get().getPageManager().getPage(version);
There isn't a nice way and it doesn't seem to be a good idea to do this. Your frontend should call your backend not the other way. So the easiest way to do this would be to store the errors inside your service and have your page get these.
class MyService {
private String error;
public void doBackEndThing(){
try {
backEndService.doRemoteCall();
} catch (BackendException e) {
error ="Backend is currently not available";
}
}
}
and
class MyPage extends WebPage {
private MySerivce service;
public void doSomethingFrontendy() {
error = service.getError();
}
}
or you could return an error from your backend method or throw an Exception and handle this in your WebPage or use IRequestCycleListener#onException() like #svenmeier pointed out.
IRequestCycleListener#onException() is a better place for this - you can get access to the current page via RequestCycle#getActiveRequestHandler().
I am using JSF 2.2. I am trying to use JSF as a pure templating language. However, there is one problem. Any user who is creating a JSF page in my environment can do something like this:
#{session.getAttribute('user').getApiKey()}
Here I have a user object that is stored in the session and getApiKey() method is a getter in that class.
Is there 'web.xml' configuration or some other trick that I can use to disable session object completely on a JSF page?
Is there 'web.xml' configuration or some other trick that I can use to disable session object completely on a JSF page?
No.
Parse the template manually against a whitelist of allowed tags, attributes and EL expressions (note: don't use a blacklist, hackers will find ways you wouldn't have imagined). For instance, the following expressions have the same effect as #{session.getAttribute('user').getApiKey()}:
#{request.session.getAttribute('user').apiKey}
#{sessionScope.user.apiKey}
#{user.apiKey}
#{facesContext.externalContext.sessionMap.user.apiKey}
#{facesContext.externalContext.session.getAttribute('user').apiKey}
After all, JSF/Facelets is likely the wrong tool for the job of offering clients some kind of a template which will be executed in the server. Rather look for BB/Wiki/Markdown-like markup or whitelisted HTML which you display via <h:outputText escape="false">.
Maybe. The implicit variables are contributed by a particular ELResolver. Removing that one from the list of ELResolvers, or prepending an own resolver that always returns null for all implicit variables to that list, should do the trick.
Off hand, I don't know whether JSF offers a public API do this, or the spec even permits something like that.
Either way, if you just need a templating engine, there are easier options that customizing a stateful, component-based web application framework ...
Here is what I did to solve this problem. This class essentially revokes access to all the core objects on the page. Additionally, I've added a utility variable to give access to the context path. I have tried this and it seems to WORK!.
package com.example.templates.jsf;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.PropertyNotFoundException;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import com.sun.faces.component.CompositeComponentStackManager;
import com.sun.faces.el.ImplicitObjectELResolver;
import com.sun.faces.util.MessageUtils;
/**
* This class revokes access to server page context objects
*/
public class CustomImplicitObjectELResolver extends ImplicitObjectELResolver {
public static final int CONTEXT_PATH = 19;
public CustomImplicitObjectELResolver(){
super();
// Revoke access to variables that can potentially
// give access to internal class objects.
IMPLICIT_OBJECTS.remove("facesContext");
IMPLICIT_OBJECTS.remove("session");
IMPLICIT_OBJECTS.remove("sessionScope");
IMPLICIT_OBJECTS.remove("application");
IMPLICIT_OBJECTS.remove("applicationScope");
IMPLICIT_OBJECTS.remove("request");
IMPLICIT_OBJECTS.remove("requestScope");
IMPLICIT_OBJECTS.remove("view");
IMPLICIT_OBJECTS.remove("viewScope");
IMPLICIT_OBJECTS.remove("initParam");
IMPLICIT_OBJECTS.remove("component");
IMPLICIT_OBJECTS.remove("cookie");
IMPLICIT_OBJECTS.remove("header");
IMPLICIT_OBJECTS.remove("headerValues");
IMPLICIT_OBJECTS.remove("flowScope");
// My own utility method
IMPLICIT_OBJECTS.put("contextPath", CONTEXT_PATH);
}
#Override
public Object getValue(ELContext context,Object base, Object property)
throws ELException {
// variable resolution is a special case of property resolution
// where the base is null.
if (base != null) {
return null;
}
if (property == null) {
String message = MessageUtils.getExceptionMessageString
(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property");
throw new PropertyNotFoundException(message);
}
Integer index = IMPLICIT_OBJECTS.get(property.toString());
if (index == null) {
return null;
} else {
FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
ExternalContext extCtx = facesContext.getExternalContext();
switch (index) {
case COMPOSITE_COMPONENT:
// The following five lines violate the specification.
// The specification states that the 'cc' implicit object
// always evaluates to the current composite component,
// however, this isn't desirable behavior when passing
// attributes between nested composite components, so we
// need to alter the behavior so that the components behave
// as the user would expect.
/* BEGIN DEVIATION */
CompositeComponentStackManager manager =
CompositeComponentStackManager.getManager(facesContext);
Object o = manager.peek();
/* END DEVIATION */
if (o == null) {
o = UIComponent.getCurrentCompositeComponent(facesContext);
}
context.setPropertyResolved(o != null);
return o;
case PARAM:
context.setPropertyResolved(true);
return extCtx.getRequestParameterMap();
case PARAM_VALUES:
context.setPropertyResolved(true);
return extCtx.getRequestParameterValuesMap();
case CONTEXT_PATH:
context.setPropertyResolved(true);
return extCtx.getRequestContextPath();
case RESOURCE:
context.setPropertyResolved(true);
return facesContext.getApplication().getResourceHandler();
default:
return null;
}
}
}
}
Next, in faces-config.xml, add the following entry:
<application>
<el-resolver>
com.example.templates.jsf.CustomImplicitObjectELResolver
</el-resolver>
</application>
Simply, how do I create a global variable in JSP, such that I can access it across other JSP pages and/or inside frames/iframes? I tried <%!..%> but I got an error that the variable could not be resolved in a separate jsp page. Is it even possible to access JSP variables in more than one page without resorting to query strings, session variables, etcetera?
Thank you.
As I've already commented, you can use ServletContext to maintain the variables for all your application. Do not confuse this with static variables, because the ServletContext will die when your application is undeployed but static variables will be alive until the JVM is turned off.
You can save variables in ServletContext by using setAttribute method. Also, you can get the actual value by using getAttribute. Let's see a sample of ServletContext in a servlet:
public class SomeServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext servletContext = getServletContext();
String someAttribute = servletContext.getAttribute("someAttribute");
System.out.println("someAttribute value: " + someAttribute);
}
}
Also, you can use a Listener to ServletContext, so you can execute some code when the application starts (is deployed correctly) to initialize the attributes on the ServletContext) and when it finish (before its undeployed).
public final class MyAppListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
System.out.println("Application gets started.");
ServletContext servletContext = event..getServletContext();
servletContext.setAttribute("someAttribute", "Hello world!");
}
public void contextDestroyed(ServletContextEvent event) {
System.out.println("Application has finished.");
}
}
If you're using Java EE 5, you should configure the listener in the web.xml
<listener>
<listener-class>mypackage.listener.MyAppListener</listener-class>
</listener>
I want to make a web application by using jsp servlet and bean am using Netbeans IDE.
I want to know where I should place the database connectivity code so that i can use my database code with every servlet, means I do not want to write the connectivity code in everypage where I need to use the database.
Please help me to find and how should I move?
Just put all the JDBC stuff in its own class and import/call/use it in the servlet.
E.g.
public class UserDAO {
public User find(String username, String password) {
User user = new User();
// Put your JDBC code here to fill the user (if found).
return user;
}
}
With
import com.example.dao.UserDAO;
import com.example.model.User;
public class LoginServlet extends HttpServlet {
private UserDAO userDAO;
public void init() throws ServletException {
userDAO = new UserDAO(); // Or obtain by factory.
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userDAO.find(username, password);
if (user != null) {
// Login.
} else {
// Error: unknown user.
}
}
}
Here's one idea how to do it:
Make a class named DBConnection with a static factory method getNewDBConnection
During application startup, verify that your db connection is valid, and using ServletContextListener, set up the DBConnection class so the mentioned method will always return a new connection
Use throughout your code DBConnection.getNewDBConnection().
I'll leave the boilerplate and exception handling up to you. There are more elegant ways to do this, using JPA for example, but this is outside of this answer's scope.
Beware of above idea. I have only written it; but haven't tried it and proven it correct.
Have you tried using the include mechanisms:
<%# include file="filename" %>
Detail here http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPIntro8.html
If you make connection from the servlets, you could create a BaseServlet class that extends HttpServlet, than your actual server have to extends BaseServlet rather then HttpServlet.
Now you can write the connectivity code just in the BaseServlet and just use it in your pseudo-servlets (extending BaseServlet).
I print a list directly in the servlet using the print writer and the list prints.
When I try to put in the jsp however the list doesn't print whether I use JSTL or scriptlets.
I tried to test in JSTL and scriptlet if the object is null and turns out that it is!
Why does this happen and how can I fix this?
Servlet code that works
for (Artist artist:artists){
resp.getWriter().println(artist.getName());
}
Servlet code that puts object in the request
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("com/helloworld/beans/helloworld-context.xml");
ArtistDao artistDao = (ArtistDao) ctx.getBean("artistDao");
List<Artist> artists = null;
try {
artists = artistDao.getAll();
} catch (SQLException e) {
e.printStackTrace();
}
req.setAttribute("artists", artists);
try {
req.getRequestDispatcher("index.jsp").forward(req, resp);
} catch (ServletException e) {
e.printStackTrace();
}
scriptlet code that suddenly finds the object null
<%
List<Artist> artists = (List<Artist>) request.getAttribute("artists");
if (artists == null) {
out.println("artists null");
}
else {
for (Artist artist: artists){
out.println(artist.getName());
}
}
%>
Even the jstl code seems to agree
<c:if test="${artists eq null}">
Artists are null
</c:if>
<c:forEach var="artist" items="${artists}">
${artist.name}
</c:forEach>
For my app I am using weblogic, spring 2.5.6 and ibatis.
I think it depends on the web server. But without changing your previous directory structure,
try putting the list in session like this
req.getSession(false).setAttribute("artists", artists);
and in your jsp,
write
List<Artist> artists = (List<Artist>) request.getSession(false).getAttribute("artists");
I think my approach will work for all web servers.
Maybe the app server is resetting your request object. You can work around this by creating a new request object, that wraps your original request, and pass that to the reqest dispatcher.
e.g.
MyHttpRequest myRequest = new MyHttpRequest(req);
myRequest.setAttribute(...);
req.getRequestDispatcher("index.jsp").forward(myRequest, resp);
And the MyHttpReqest code:
class MyHttpRequest extends HttpServletRequestWrapper
{
Map attributes = new HashMap();
MyHttpRequest(HttpRequest original) {
super(original);
}
#Override
public void setAttribute(Object key, Object value) {
attributes.put(key, value);
}
public Object getAttribute(Object key) {
Object value = attributes.get(key);
if (value==null)
value = super.getAttribute(key);
return value;
}
// similar for removeAttribute
}
I just discovered inadvertently while trying to fix my directory structure in WebContent/
My previous directory structure was
WEB-CONTENT/
- META-INF/
- WEB-INF/
index.jsp
Then I tried to create a folder jsp in WEB-CONTENT and placed index.jsp there. It works!
My current directory structure now is
WEB-CONTENT/
- META-INF/
- WEB-INF/
- jsp/
-index.jsp
I don't know why it works but it did.
Anyone here with any idea why?