Validating JSF view parameter and error message - jsf-2

I have a JSF2 page with a view parameter that must be looked up in a database.
On the page the properties of that entity are then displayed.
Now I would like to handle the case where the view parameter is missing/invalid
<f:metadata>
<f:viewParam name="id" value="#{fooBean.id}" />
<f:event type="preRenderView" listener="#{fooBean.init()}" />
</f:metadata>
And the init() code is as follows:
String msg = "";
if (id == null) {
msg = "Missing ID!";
}
else {
try {
entity = manager.find(id);
} catch (Exception e) {
msg = "No entity with id=" + id;
}
}
if (version == null) {
FacesUtils.addGlobalMessage(FacesMessage.SEVERITY_FATAL, msg);
FacesContext.getCurrentInstance().renderResponse();
}
Now my problem is that the remaing page is still rendered and I get errors in the application server log saying that entity is null (and therefore some elements are not rendered properly).
I would like only the error message to be displayed.
Should I be returning a String so that a POST to an error page is issued?
However if I choose that way, how do I add a custom error message? Passing Strings as view
parameters does not seem like a good idea at all.

In my opinion, the best thing to do in these cases, is to send an HTTP response with the appropriate error code (404 for not found/invalid, 403 for forbidden, etc):
Add to your FacesUtils this utility method:
public static void responseSendError(int status, String message)
throws IOException {
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.getExternalContext().responseSendError(status, message);
facesContext.responseComplete();
}
and then, change in your preRenderView listener to:
public void init() throws IOException {
if (id == null || id.isEmpty()) {
FacesUtils.responseSendError(404, "URL incomplete or invalid!");
}
else {
try {
entity = manager.find(id);
} catch (Exception e) { // <- are you sure you want to do that? ;)
FacesUtils.responseSendError(404, "No entity found!");
}
}
}

Related

Showing error message after checking the back-end

My controller is something like this:
[HttpPost]
[Route("Somewhere")]
public JsonResult SetSomething(string propertyName, string propertyValue)
{
var successSave = this.SaveIt(propertyName,propertyValue);
if(successSave)
return Json(propertyValue);
else
// Show a message in front end that there was problem in saving
}
And then my view is currently something like:
#Model.SomethingFeild
That just loads the value and shows it in a textbox field in there .
So how can I change this to be able to handle the psedo-code scenario I wrote in the controller, so that if something is wrong in DB ( not front-end vlaidation) such as duplicate entry, then it comes back and tells the UI that so UI shows a hard coded message?
Wrap it in try catch block and add an extension method for reading exception (or your exception type that is thrown) like so:
[HttpPost]
[Route("Somewhere")]
public JsonResult SetSomething(string propertyName, string propertyValue)
{
try
{
var successSave = this.SaveIt(propertyName, propertyValue);
if (successSave)
return Json(new { success = true, value = propertyValue });
}
catch (Exception ex)
{
return Extensions.ReturnExceptionToView(ex);
}
}
Example extension method (static method):
internal static JsonResult ReturnExceptionToView(Exception ex)
{
List<object> viewErrors = new List<object>();
viewErrors.Add(new { ErrorMessage = ex.ToString() });
return new JsonResult() { Data = (new { success = false, errors = viewErrors }) };
}
Then check for success property in the response in JS. Example below is using response of ajax call and pushing to Knockout observable array.
if (response.success) {
// do something with successful response
} else {
// we have an error in the response.errors collection
$.each(response.errors, function () {
vm.saveErrors.push(new ErrorMsg(this.ErrorMessage));
});

JSF View- returning null on actions do not update the view

i have read the post that have same problem as mine
JSF ViewScope - returning null on actions do not update the view
but it haven't worked for me cause i already use the h:commandLink in another page and its works perfectly but in this page it doesn't .
this is the request Bean
public class AddSectionBean {
public String delete(String id) {
try {
HttpSession session = SessionUtil.getSession();
UserVO userVOCreater = (UserVO) session.getAttribute("userVO");
SectionsDao.getInstance().deleteSectionById(
Integer.parseInt(id));
LoggerVO loggerVO =new LoggerVO();
loggerVO.setUserid(userVOCreater.getId());
loggerVO.setLog("deleted Section Id:"+id);
LoggerDao.getInstance().insertLogger(loggerVO);
} catch (Exception e) {
e.printStackTrace();
BundleMessages.getInstance().setMessage("error",
FacesMessage.SEVERITY_ERROR);
logger.error(e.getMessage(), e);
}
return null;
}
}
and the link is inside a richtable for every column
<rich:column>
<h:commandLink id="actualDelete" styleClass="delete_#{sectionsBean.datatableSections.rowIndex}" action ="#{addSectionBean.delete(s.id)}" />
</rich:column>
Note That: i tried to return the outcome instead of null but when i do that i lose the style and scripts in page
, note that the scripts have no effect cause i have tested it with them and had the same result
the problem solved by moving the delete method to the bean that view the table and calling the database method again inside the delete function to reload the table even its reloads in the postConstruct function
public class SectionsBean{
List<SectionVO> sectionsList = new ArrayList<SectionVO>();
#PostConstruct
public void postConstruct() {
try {
this.sectionsList = SectionsDao.getInstance().getSections();
} catch (Exception e) {
e.printStackTrace();
logger.error(e.getMessage(), e);
}
}
public String delete(String id) {
try {
HttpSession session = SessionUtil.getSession();
UserVO userVOCreater = (UserVO) session.getAttribute("userVO");
SectionsDao.getInstance().deleteSectionById(
Integer.parseInt(id));
LoggerVO loggerVO =new LoggerVO();
loggerVO.setUserid(userVOCreater.getId());
loggerVO.setLog("deleted Section Id:"+id);
LoggerDao.getInstance().insertLogger(loggerVO);
//reload the database table
this.sectionsList = SectionsDao.getInstance().getSections();
} catch (Exception e) {
e.printStackTrace();
BundleMessages.getInstance().setMessage("error",
FacesMessage.SEVERITY_ERROR);
logger.error(e.getMessage(), e);
}
BundleMessages.getInstance().setMessage("success",
FacesMessage.SEVERITY_INFO);
System.out.println("calling delete id="+id);
return null;
}
}

Error in redirecting my spring application to different domain on mobile

I am working on a Spring application which runs on mobile and web. On web everything runs fine but on mobile when the form is posted, its hits the controller and the controller is redirecting to other application.
#RequestMapping(value = "/common", method = RequestMethod.GET)
public String showLandingPage(HttpServletRequest req, HttpServletResponse response, Model model) {
logger.debug("Received request to set partner info");
Device currentDevice = DeviceUtils.getCurrentDevice(req);
setCookies(response);
Properties props = new Properties();
try {
props.load(getClass().getClassLoader().getResourceAsStream( "sampleApp.properties"));
} catch (IOException e) {
logger.fatal(new StringBuilder("MainController : setCookies() : Error while reading sampleApp.properties "+e));
}catch (Exception e) {
logger.fatal(new StringBuilder("MainController : setCookies() : Error while reading sampleApp.properties "+e));
}
if(currentDevice.isMobile() || currentDevice.isTablet()){
return "redirect:"+props.getProperty("popcorn-mobile-url");
} else {
return "redirect:"+props.getProperty("popcorn-web-url");
}
}
When the control goes to the redirect location I get "error loading page" on the screen.
In JSP I am using following jQuery libraries.
<script src="${pageContext.request.contextPath}/js/mobile/mobile-config.js"></script>
<script src="${pageContext.request.contextPath}/js/mobile/jquery.mobile-1.2.0.min.js"></script>
<script src="${pageContext.request.contextPath}/js/mobile/plugins.js"></script>
I woul duse a deviceinterceptor, somethign like below :
public class DeviceInterceptor extends HandlerInterceptorAdapter {
private final DeviceResolver deviceResolver;
private Device device;
/**
* Create a device resolving {#link HandlerInterceptor} that defaults to a
* {#link LiteDeviceResolver} implementation.
*/
public DeviceInterceptor() {
this(new LiteDeviceResolver());
}
public DeviceInterceptor(DeviceResolver deviceResolver) {
this.deviceResolver = deviceResolver;
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
device = deviceResolver.resolveDevice(request);
request.setAttribute(DeviceUtils.CURRENT_DEVICE_ATTRIBUTE, device);
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
if (device.isMobile()) {
modelAndView.setViewName("/mobile/" + modelAndView.getViewName());
}else {
modelAndView.setViewName("/jsp/" + modelAndView.getViewName());
}
}

JSF h:commandLink not work with filter

I create simple login system for my jsf project.
In project I create filter to check user login status.
If login, continue to requested page.
If not login or session is destroy, redirect to login page
My problem is, if I apply filter then all of h:commandLink not process anything after clicked. But when I remove filter, everything work well.
I try to use h:commandButton with fileter, then everthing work correctly.
How can I fixed this problem?
I research for a long time, but not found any solution.
Please help me!
Filter code:
#WebFilter(filterName = "AuthenticationFilter", urlPatterns = {"*.htm"}, dispatcherTypes = {DispatcherType.FORWARD, DispatcherType.REQUEST})
public class AuthenticationFilter implements Filter {
// The filter configuration object we are associated with. If
// this value is null, this filter instance is not currently
// configured.
private FilterConfig filterConfig = null;
#Inject
private AuthenticationManager authenticationManager;
public AuthenticationFilter() {
}
/**
* #param request The servlet request we are processing
* #param response The servlet response we are creating
* #param chain The filter chain we are processing
*
* #exception IOException if an input/output error occurs
* #exception ServletException if a servlet error occurs
*/
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
Throwable problem = null;
try {
HttpServletRequest req = (HttpServletRequest) request;
String requestUrl = req.getRequestURI();
String contextPath = req.getContextPath();
if(contextPath.equals("/")){
contextPath = "";
}
String jsfUrl = requestUrl.replaceFirst(contextPath, "");
if (authenticationManager.allowedAccess(jsfUrl) || requestUrl.equalsIgnoreCase(contextPath+"/login.htm")) {
chain.doFilter(request, response);
}
else {
String redirectPath = contextPath+"/login.htm";
((HttpServletResponse) response).sendRedirect(redirectPath); // Not logged in, so redirect to error page.
}
}
catch (Throwable t) {
// If an exception is thrown somewhere down the filter chain,
// we still want to execute our after processing, and then
// rethrow the problem after that.
problem = t;
}
// If there was a problem, we want to rethrow it if it is
// a known type, otherwise log it.
if (problem != null) {
if (problem instanceof ServletException) {
throw (ServletException) problem;
}
if (problem instanceof IOException) {
throw (IOException) problem;
}
sendProcessingError(problem, response);
}
}
/**
* Return the filter configuration object for this filter.
*/
public FilterConfig getFilterConfig() {
return (this.filterConfig);
}
/**
* Set the filter configuration object for this filter.
*
* #param filterConfig The filter configuration object
*/
public void setFilterConfig(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
if (filterConfig != null) {
}
}
}
Jsf code:
<h:body>
<f:view contentType="text/html" locale="#{authenticationManager.languageCode}">
<div class="header">
<h:form id="topForm" prependId="false">
<div class="logo">
<h1><img src="#{facesContext.externalContext.requestContextPath}/resources/images/login-logo2.png" width="220" height="64"/></h1>
</div>
<ul class="navTop">
<li>
<span class="pictograms">f</span>#{authenticationManager.currentUser.firstName} #{authenticationManager.currentUser.lastName}
</li>
<li>
<span class="pictograms">m</span>Messages
</li>
<li class="logout">
<h:commandButton action="#{authenticationManager.logout()}" value="aaaaaaa" style="color:#fff;" />
<h:commandLink action="#{authenticationManager.logout()}" value="#{label.Logout}"/>
<h:commandLink immediate="true" action="#{authenticationManager.logout}" id="logoutLink">
<span class="pictograms">E</span>***This link is not work correctly***
</h:commandLink>
</li>
</ul>
<ui:insert name="mainmenu"/>
</h:form>
</div>
Your concrete problem is caused because the serving of the JSF default resource jsf.js has been blocked by the filter. This resource is mandatory for functioning of JSF command links and JSF ajax requests (plain command buttons without ajax will just work).
You need to exclude JSF resources from the authentication check. You can do that by just checking if the request URI starts after the webapp context path with ResourceHandler.RESOURCE_IDENTIFIER (which has a value of /javax.faces.resource).
So, basically:
HttpServletRequest req = (HttpServletRequest) request;
if (req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) {
chain.doFilter(request, response); // Let it continue.
return;
}
Checking the file extensions is clumsy and does not sufficiently cover all possible resource requests.
After research, I didn't found any solution.
So I guest to many possible ways, and found the explanation about this.
I filter everything with filter pattern "*.htm", then every request like .js.htm, .css.htm, .gif.htm, .jpg.htm will redirected to login.htm page.
The point is redirect .js.htm to login page instead of right file.
So the important library like jsf.js.htm was redirect to login.htm, this is the main cause to make h:commandLink work not correctly.
Hop this will help someone, like me.
try {
HttpServletRequest req = (HttpServletRequest) request;
String requestUrl = req.getRequestURI();
if(requestUrl.endsWith(".js.htm")
|| requestUrl.endsWith(".css.htm")
|| requestUrl.endsWith(".gif.htm")
|| requestUrl.endsWith(".png.htm")
|| requestUrl.endsWith(".jpg.htm")
|| requestUrl.endsWith(".jpeg.htm")){
chain.doFilter(request, response);
}
else{
String contextPath = req.getContextPath();
if(contextPath.equals("/")){
contextPath = "";
}
String jsfUrl = requestUrl.replaceFirst(contextPath, "");
if (authenticationManager.allowedAccess(jsfUrl) || requestUrl.equalsIgnoreCase(contextPath+"/login.htm")) {
chain.doFilter(request, response);
}
else {
String redirectPath = contextPath+"/login.htm";
((HttpServletResponse) response).sendRedirect(redirectPath); // Not logged in, so redirect to error page.
}
}
}

Multiple Image upload in primefaces

I am using PrimeFaces fileUpload with multiple upload options. In my project i want to send email notification during image upload. My problem is when i upload 10 images means simultaneously 10 email notifications are send. I want to send only one email notification during uploading 10 images. I am using primefaces 3.0 and jsf 2.0. How can I solve it?
My jsf pages:
<p:fileUpload id="imaload" fileUploadListener="#{photoUploadAction.handleImage}"
mode="advanced" multiple="true" process="#form"
update="messages,#form"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>
Backing Bean:
public void handleImage(FileUploadEvent event) throws IOException, EmailException {
try {
photoUploadVO.setDisabled("false");
//BufferedImage image = ImageIO.read(in);
ImageIO.write(resize(bufferedImage, 400, bufferedImage.getHeight()), "jpg", new File(tmpFile));
flag = photoUploadDaoService.uploadPhotos(photoUploadVO);
// profileImageService.uploadPhotos(profileImageBean);
if (flag == true) {
if(!loginBean.getType().equals("ngo") && !loginBean.getType().equals("admin") &&
!loginBean.getType().equals("ngo_coordinator") ){
volName = getVolunteerName(photoUploadVO.getUsrId(),photoUploadVO.getUser_type());
lst = apDao.retreiveSetup();
notification = lst.get(0).activity_email.toString();
email = lst.get(0).approval_toEmail.toString();
if(notification.equalsIgnoreCase(tmp)){
ecs.sendPhotoNotiFication(email,photoUploadVO,volName);
}
}
FacesMessage msg = new FacesMessage("Successfully Uploaded");
FacesContext.getCurrentInstance().addMessage(null, msg);
} else {
FacesMessage msg = new FacesMessage("Failure", event
.getFile().getFileName() + " to uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
} catch (IOException e) {
e.printStackTrace();
FacesMessage error = new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"The files were not uploaded!", "");
FacesContext.getCurrentInstance().addMessage(null, error);
}
}
This is my email notification method inside handle upload methos:
ecs.sendPhotoNotiFication(email,photoUploadVO,volName);
Redesign your bean as such that the file upload handler method merely captures and remembers all uploaded files in some collection. Then add a "Save" button below the form which is bound to an action method which will actually process and save all those uploaded files and finally send the mail. If you put the bean in the view scope, then one and same bean instance will just be reused as long as the enduser interacts with the same view. You could then just collect the uploaded files in a collection property.
Something like this:
#ManagedBean
#ViewScoped
public class Bean implements Serializable {
private List<UploadedFile> uploadedFiles;
#PostConstruct
public void init() {
uploadedFiles = new ArrayList<UploadedFile>();
}
public void upload(FileUploadEvent event) {
uploadedFiles.add(event.getFile());
}
public void save() {
for (UploadedFile uploadedFile : uploadedFiles) {
// Process them all here.
}
// Send only one email.
}
}
with
<p:fileUpload ... fileUploadListener="#{bean.upload}" />
<p:commandButton value="Save" action="#{bean.save}" />

Resources