Cyndi Vasquez sent me this title a while back. I have been so bogged down that I finally got a chance to look at it. Thanks Murach... this is a good book.
The book is written in a style that many will either love, or hate. I personally am on the former. The pages on the left side are an explanation of the technical matter, and the right side are examples. The book is designed to guide you from front to back on an adventure into programming. Along the safari, I assure you will be pleased. The quarry is knowledge and this book is the tool to capture it.
The books is divided into five sections which will take you from absolute beginner to accomplished Servlet and JSP aficionado. It will even teach you a little about databases, and JSF along the way. There are two appendices that will show you how to set up your computer either Mac, or PC before you get started on your journey.
One of the thrills about this book is the use of NetBeans. I believe that NetBeans is the easiest tool for developing web based applications using Servlets and JSP. It also is my preferred tool for Java development in general. The book not only teaches you about the essentials of the title technologies, but helps you gain an in-depth knowledge of a valuable IDE that you can bank your career on.
Section one covers the basics of the technology and the MVC pattern. This is followed by a crash course on HTML, CSS, and web technologies based on Java. The 8th chapter on EL is a great reference for how to use this important technology in your web applications.
Section three covers essential database skills to get you started with web development. These skills are the bare minimum to get started, but are complete for the purpose of this book. Keep in mind, these are the basics.
Section four is the meat of the book. This covers the advanced Servlet and JSP skills. It also covers some additional technologies like JSF. My favorite parts of this section are chapters 18, 19, and 20. The HTTP Request and Response skills are something every developer should strive to make sure they understand. Chapter 19 covers listeners which are truly your friends. Chapter 20 covers another often misused, abused, and otherwise fantastic technology. The filter can make your life as a web developer a great pleasure, or a rabbit hole in which you feel like Alice in Wonderland.
The final concluding section five puts all of the pieces together in a Music Store website. The Music Store website uses most of the technologies covered, and takes the learner to the next level with clear and concise directions.
Overall this is a great book for anyone interested in learning about Servlet and JSP technology. Please keep in mind that all Java web technologies are based on the Servlet foundation. JSF is nothing more than a veneer on top of this technology as an example.
Sunday, September 06, 2015
Wednesday, April 01, 2015
JSF 2.2 Tip of the Day: p:passthrough and How to use it
I was asking my team to go through their JSF pages, and to update the XML namespaces to use the latest namespace from the JSF 2.2 specification. While I was looking at the code, I found a number of instances where developers were adding attributes like
Fortunately, some of these attributes were passing through to the underlying page without needing
Alright, so how do we do it correctly?
There is no magic here. It is simply a matter of adding the attribute with a prefix of
So I have an example, and the resulting output.
The resulting output will run the JavaScript associated with the passed through attributes, or set the CSS styling. Very simple and easy to implement.
name
to <h:commandButton />
and NetBeans correctly was identifying that there is an issue with that.Fortunately, some of these attributes were passing through to the underlying page without needing
p:passthrough
. However, you should not rely on such functionality to work. If the VDL Document does not show it as an attribute, you shouldn't expect it to work.
Alright, so how do we do it correctly?
There is no magic here. It is simply a matter of adding the attribute with a prefix of
p:
, for example p:name="someName"
for the name
attribute. This will result in the attribute being passed through the rendered and added to the resulting output.So I have an example, and the resulting output.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version='1.0' encoding='UTF-8' ?> | |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | |
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml" | |
xmlns:h="http://xmlns.jcp.org/jsf/html" | |
xmlns:p="http://xmlns.jcp.org/jsf/passthrough"> | |
<h:head> | |
<title><p:passthrough/> example</title> | |
</h:head> | |
<h:body> | |
<h:panelGroup id="panelGroup1" layout="block" | |
p:onmouseover="this.setAttribute('style', 'color: blue; font-size:32px; font-weight:bolder;');" | |
p:onmouseout="this.setAttribute('style', 'color: black; font-size:inherit; font-weight:normal;');"> | |
<h:outputText id="outputText1" value="Click me!" | |
p:data-experimental-type="Hello World!" | |
p:style="font-variant:small-caps;" | |
p:onclick="alert(this.getAttribute('data-experimental-type'));"/> | |
</h:panelGroup> | |
</h:body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version='1.0' encoding='UTF-8' ?> | |
<!DOCTYPE html> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head id="j_idt2"> | |
<title><p:passthrough/> example</title> | |
</head> | |
<body> | |
<h1><p:passthrough/> example</h1> | |
<div id="panelGroup1" | |
onmouseout="this.setAttribute('style', 'color: black; font-size:inherit; font-weight:normal;');" | |
onmouseover="this.setAttribute('style', 'color: blue; font-size:32px; font-weight:bolder;');"> | |
<span id="outputText1" onclick="alert(this.getAttribute('data-experimental-type'));" | |
data-experimental-type="Hello World!" | |
style="font-variant:small-caps;">Click me!</span> | |
</div> | |
</body> | |
</html> |
Monday, March 30, 2015
Customizing Blogger
Introduction
I want to start by blaming Markus Eisele for my misadventures. I was looking at his blog and liked the makeover he gave it. I did find the template he was using, but decided that I would write my own. Well I thought this should be an easy thing to do. I severely underestimated the challenge of making a custom template for myself. It turns out that one of the easiest things turns out to be the hardest. Alright Markus you are off the hook... it may just be my bravado, and belief I can build a better mousetrap that led me down the long lonesome road.Google is well known for having good and sometimes great APIs for their technology. Blogger is an exception to that rule. There is not one clear cut schema for their layout that I can find ironically using Google itself. You figure with all of the templates and bloggers that this would be covered ad nauseum. It is not though.
Technologies
I was looking for a simple and elegant framework to make my blog sites look professional, and also make them portable. I had the following requirements:- Mature framework
- Can be found on a CDN
- Easy to use
- Simple to implement
- Well Documented
- Lots of examples
- Flexible
- Customizable
- Response UI
- HTML5
- Portable
- JSF Compatible
- Works with NetBeans IDE for Tooling
The first thing I wanted to know was what was the minimum required for a template on Blogger. I discovered that are a couple of versions of the template: an HTML 4.01 version (v.1) and an HTML 5 version (v.2) which are somewhat a hybrid mix of XML, and (X)HTML. I published the basic templates on Gist as shown below.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8" ?> | |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
<html xmlns='http://www.w3.org/1999/xhtml' | |
xmlns:b='http://www.google.com/2005/gml/b' | |
xmlns:data='http://www.google.com/2005/gml/data' | |
xmlns:expr='http://www.google.com/2005/gml/expr'> | |
<head> | |
<title><data:blog.pageTitle/></title> | |
<b:skin> | |
<![CDATA[ | |
<!-- SKIN CONTENTS --> | |
]]> | |
</b:skin> | |
</head> | |
<body> | |
<!-- BODY CONTENTS --> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8" ?> | |
<!DOCTYPE html> | |
<html b:version='2' class='v2' expr:dir='data:blog.languageDirection' | |
xmlns='http://www.w3.org/1999/xhtml' | |
xmlns:b='http://www.google.com/2005/gml/b' | |
xmlns:data='http://www.google.com/2005/gml/data' | |
xmlns:expr='http://www.google.com/2005/gml/expr'> | |
<head> | |
<title><data:blog.pageTitle/></title> | |
<b:skin> | |
<![CDATA[ | |
<!-- SKIN CONTENTS --> | |
]]> | |
</b:skin> | |
</head> | |
<body> | |
<!-- BODY CONTENTS --> | |
</body> | |
</html> |
The next thing I needed to find out was what was the minimal template I would need for using with Foundation. The template below uses a CDN to deliver the required JS/CSS. The template below is the culmination of a lot of work to make it work with the visual tools on Blogger. Remember to backup your existing template before installing mine.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8" ?> | |
<!DOCTYPE html> | |
<html xmlns='http://www.w3.org/1999/xhtml' | |
xmlns:b='http://www.google.com/2005/gml/b' | |
xmlns:data='http://www.google.com/2005/gml/data' | |
xmlns:expr='http://www.google.com/2005/gml/expr' | |
b:version='2' class='v2 no-js' expr:dir='data:blog.languageDirection'> | |
<head> | |
<meta content='width=device-width, initial-scale=1.0' name='viewport'/> | |
<b:include data='blog' name='all-head-content'/> | |
<title> | |
<data:blog.pageTitle/> | |
</title> | |
<link href='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/css/foundation.min.css' rel='stylesheet'/> | |
<link href='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/css/normalize.min.css' rel='stylesheet'/> | |
<link href='https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/foundation-icons.min.css' rel='stylesheet'/> | |
<b:skin> | |
<![CDATA[ | |
<!-- Add Custom CSS Here --> | |
]]> | |
</b:skin> | |
<b:include data='blog' name='google-analytics'/> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/vendor/modernizr.js' type='text/javascript'> | |
</script> | |
</head> | |
<body> | |
<!-- NAVBAR --> | |
<b:section class='navbar' id='navbar' maxwidgets='1' showaddelement='no'> | |
<b:widget id='Navbar1' locked='true' title='Navbar' type='Navbar'></b:widget> | |
</b:section> | |
<!-- META DATA --> | |
<b:if cond='data:blog.pageType == "index"'> | |
<div itemscope='itemscope' itemtype='http://schema.org/Blog' style='display: none;'> | |
<meta expr:content='data:blog.title' itemprop='name'/> | |
<b:if cond='data:blog.metaDescription'> | |
<meta expr:content='data:blog.metaDescription' itemprop='description'/> | |
</b:if> | |
</div> | |
</b:if> | |
<!-- HEADER --> | |
<div class='row'> | |
<div class='large-12 medium-12 small-12 columns'> | |
<b:section class='header' id='header' maxwidgets='1' showaddelement='no'> | |
<b:widget id='Header1' locked='true' title='Test Blog (Header)' type='Header'></b:widget> | |
</b:section> | |
</div> | |
</div> | |
<!-- MAIN --> | |
<div class='row'> | |
<!-- COLUMN 1 - MAIN --> | |
<div class='large-9 medium-9 small-9 columns'> | |
<b:section class='main' id='main' showaddelement='yes'> | |
<b:widget id='Blog1' locked='true' title='Blog Posts' type='Blog'></b:widget> | |
<b:widget id='PopularPosts1' locked='false' title='Popular Posts' type='PopularPosts'></b:widget> | |
</b:section> | |
</div> | |
<!-- COLUMN 2 - SIDEBAR --> | |
<div class='large-3 medium-3 small-3 columns'> | |
<b:section class='sidebar' id='sidebar' showaddelement='yes'> | |
<b:widget id='BlogArchive1' locked='false' title='Archive' type='BlogArchive'></b:widget> | |
<b:widget id='CustomSearch1' locked='false' title='Search' type='CustomSearch'></b:widget> | |
<b:widget id='Label1' locked='false' title='Labels' type='Label'></b:widget> | |
</b:section> | |
</div> | |
</div> | |
<!-- FOOTER --> | |
<div class='row'> | |
<div class='large-12 medium-12 small-12 columns'> | |
<b:section class='foot' id='footer-3' showaddelement='yes'> | |
<b:widget id='Attribution1' locked='true' title='' type='Attribution'></b:widget> | |
</b:section> | |
</div> | |
</div> | |
<!-- CDN JS Required for Foundation --> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/vendor/jquery.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/vendor/jquery.cookie.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/vendor/placeholder.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/vendor/fastclick.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.abide.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.accordion.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.alert.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.clearing.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.dropdown.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.equalizer.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.interchange.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.joyride.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.magellan.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.offcanvas.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.orbit.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.reveal.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.slider.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.tab.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.tooltip.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.topbar.min.js' type='text/javascript'> | |
</script> | |
<script src='https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.1/js/foundation/foundation.topbar.min.js' type='text/javascript'> | |
</script> | |
<script> | |
$(document).foundation(); | |
</script> | |
</body> | |
</html> |
Conclusion
I finally have a working blog site using the new template, and will update all of my sites to use it. My personal non-technical blog site was the first to use the new template. It is still a work in progress, but it looks very nice. Take a peek for yourself at John Yeary Blogger site.I have compiled a list of links that I found helpful in trying to figure out their layouts and tags in the references below.
References
Tags
Template References
- How to Make a Blogger Template : The Body and APIs - This was a comprehensive blog with lots of great explanations.
- How To Create Blogger Template From Scratch
- Blogger Template Design
- Understanding the Blogger Template - 2 - This is an older article, but useful.
- Template of Doom - Another older useful article.
Additional References
Labels:
blogging
,
example
,
Foundation
,
frameworks
,
HTML5
,
Javascript
,
tutorial
Friday, March 27, 2015
A Simple Method to invoke @PreDestroy on a Class
I was experimenting with how to invoke a
@PreDestroy
annotated method in a class. This will approach will work with other annotations as well.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2016 Blue Lotus Software, LLC. | |
* Copyright 2015 John Yeary <jyeary@bluelotussoftware.com>. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package com.bluelotussoftware.annotation; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.text.MessageFormat; | |
import java.util.Collections; | |
import java.util.Map; | |
import javax.annotation.PreDestroy; | |
/** | |
* | |
* @author John Yeary <jyeary@bluelotussoftware.com> | |
* @version 2.0 | |
*/ | |
public class Utils { | |
/** | |
* This method reflectively examines the provided object looking for | |
* {@link PreDestroy} annotations, invokes the first method with the | |
* annotation found, and returns. | |
* | |
* @param object The object to examine. | |
* @return {@code true} if successful, and {@code false} otherwise. | |
* @throws SecurityException If a security manager, <i>s</i>, is present and | |
* any of the following conditions is met: | |
* <ul> | |
* <li> the caller's class loader is not the same as the class loader of | |
* this class and invocation of | |
* {@link SecurityManager#checkPermissions#checkPermission(java.security.Permission)} | |
* method with {@code RuntimePermission("accessDeclaredMembers")} denies | |
* access to the declared methods within this class.</li> | |
* | |
* <li> the caller's class loader is not the same as or an ancestor of the | |
* class loader for the current class and invocation of | |
* {@link SecurityManager#checkPackageAccess#checkPackageAccess(java.lang.String)} | |
* denies access to the package of this class.</li> | |
* </ul> | |
* @throws IllegalArgumentException if the method is an instance method and | |
* the specified object argument is not an instance of the class or | |
* interface declaring the underlying method (or of a subclass or | |
* implementor thereof); if the number of actual and formal parameters | |
* differ; if an unwrapping conversion for primitive arguments fails; or if, | |
* after possible unwrapping, a parameter value cannot be converted to the | |
* corresponding formal parameter type by a method invocation conversion. | |
* @throws IllegalAccessException if this {@code Method} object is enforcing | |
* Java language access control and the underlying method is inaccessible. | |
* @throws InvocationTargetException if the underlying method throws an | |
* exception. | |
*/ | |
public static boolean destroy(final Object object) throws SecurityException, | |
IllegalArgumentException, IllegalAccessException, InvocationTargetException { | |
Class clazz = object.getClass(); | |
String methodName = null; | |
synchronized (object) { | |
boolean success = false; | |
try { | |
Method[] methods = clazz.getDeclaredMethods(); | |
done:// Break for multiple for loops. | |
for (Method method : methods) { | |
Annotation[] annotations = method.getDeclaredAnnotations(); | |
for (Annotation annotation : annotations) { | |
if (annotation instanceof PreDestroy) { | |
methodName = method.getName(); | |
if (!method.isAccessible()) { | |
method.setAccessible(true); | |
} | |
method.invoke(object, (Object[]) null); | |
success = true; | |
break done; | |
} | |
} | |
} | |
} catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { | |
System.err.println(MessageFormat.format("An exception occurred while trying to process @PreDestroy on : {0}.{1}(). The message follows: {2}", clazz.getName(), methodName, ex.getMessage())); | |
throw ex; | |
} | |
return success; | |
} | |
} | |
/** | |
* | |
* This method reflectively examines the provided map looking for objects | |
* with {@link PreDestroy} annotations, invokes the first method with the | |
* annotation found, and returns. | |
* | |
* @param map A map of objects to examine for {@link PreDestroy} | |
* annotations. | |
* @throws SecurityException If a security manager, <i>s</i>, is present and | |
* any of the following conditions is met: | |
* <ul> | |
* <li> the caller's class loader is not the same as the class loader of | |
* this class and invocation of | |
* {@link SecurityManager#checkPermissions#checkPermission(java.security.Permission)} | |
* method with {@code RuntimePermission("accessDeclaredMembers")} denies | |
* access to the declared methods within this class.</li> | |
* | |
* <li> the caller's class loader is not the same as or an ancestor of the | |
* class loader for the current class and invocation of | |
* {@link SecurityManager#checkPackageAccess#checkPackageAccess(java.lang.String)} | |
* denies access to the package of this class.</li> | |
* </ul> | |
* @throws IllegalArgumentException if the method is an instance method and | |
* the specified object argument is not an instance of the class or | |
* interface declaring the underlying method (or of a subclass or | |
* implementor thereof); if the number of actual and formal parameters | |
* differ; if an unwrapping conversion for primitive arguments fails; or if, | |
* after possible unwrapping, a parameter value cannot be converted to the | |
* corresponding formal parameter type by a method invocation conversion. | |
* @throws IllegalAccessException if this {@code Method} object is enforcing | |
* Java language access control and the underlying method is inaccessible. | |
* @throws InvocationTargetException if the underlying method throws an | |
* exception. | |
* @see Utils#destroy(java.lang.Object) | |
* @since 2.0 | |
*/ | |
public static void destroy(final Map<String, Object> map) throws SecurityException, | |
IllegalAccessException, IllegalArgumentException, InvocationTargetException { | |
if (map != null) { | |
Map<String, Object> synchronizedMap = Collections.synchronizedMap(map); | |
if (!synchronizedMap.isEmpty()) { | |
for (Object o : synchronizedMap.values()) { | |
destroy(o); | |
} | |
} | |
} | |
} | |
} |
Tuesday, February 17, 2015
JSF 2.x Tip of the Day: Implementing a ViewMapListener
A map of the lands where the Trobadors flourished.
"France 1154-en" by Reigen - Own work.
Licensed under CC BY-SA 4.0 via Wikimedia Commons.
|
Introduction
There are a number ofSystemEvent
s supported by JSF 2.x. A question that comes up frequently is how to implement them. In a number of cases on stackoverflow, it is implemented using a PhaseListener
. I was looking for a way to cleanup the view map, or just get values from it before it was destroyed. I decided that the simplest way to do so was to implement a ViewMapListener
. I also noticed that there were very few posts on how to implement it using the faces-config.xml
so I decided to use that approach since it was instructive and more clear to me.Implementation
The basic implementation requires that you add our listener implementation to thefaces-config.xml
. The example I have here is designed to get called on a PreDestroyViewMapEvent
which is called on a normal navigation. We can force it though by adding a @PreDestroy
annotation to a method to invoke before being destroyed. Inside the method we would need to get the UIViewroot
view map, and call clear()
. This would cause our listener to be invoked too. It would be a good cleanup mechanism for cleaning up resources on session expiration too, but at the moment this does not work on JSF 2.1. The @PreDestroy
is not called on session timeout on JSF 2.1. This is expected to be an enhancement in JSF 2.2+.The code for the project can be downloaded from Bitbuket here: viewmaplistener-example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.bluelotussoftware; | |
import com.sun.faces.application.view.ViewScopeManager; | |
import java.util.Collections; | |
import java.util.Map; | |
import javax.faces.component.TransientStateHelper; | |
import javax.faces.component.UIViewRoot; | |
import javax.faces.context.ExternalContext; | |
import javax.faces.context.FacesContext; | |
import javax.faces.event.AbortProcessingException; | |
import javax.faces.event.PreDestroyViewMapEvent; | |
import javax.faces.event.SystemEvent; | |
import javax.faces.event.ViewMapListener; | |
/** | |
* This class is an implementation of {@link ViewMapListener} which listens for | |
* {@link SystemEvent} on the {@link UIViewRoot}. If the event is a | |
* {@link PreDestroyViewMapEvent}, the listener will clear the session map of | |
* the {@link ViewScopeManager#VIEW_MAP_ID} associated with the current view. | |
* | |
* @author John Yeary <jyeary@bluelotussoftware.com> | |
* @version 1.0 | |
* @see ExternalContext#getSessionMap() | |
* @see ViewScopeManager#ACTIVE_VIEW_MAPS | |
* @see ViewScopeManager#VIEW_MAP_ID | |
* @see TransientStateHelper#getTransient(java.lang.Object) | |
*/ | |
public class ViewMapListenerImpl implements ViewMapListener { | |
/** | |
* {@inheritDoc} | |
*/ | |
@Override | |
public void processEvent(SystemEvent event) throws AbortProcessingException { | |
if (event instanceof PreDestroyViewMapEvent) { | |
PreDestroyViewMapEvent pdvme = (PreDestroyViewMapEvent) event; | |
UIViewRoot root = (UIViewRoot) pdvme.getComponent(); | |
FacesContext fctx = FacesContext.getCurrentInstance(); | |
String key = (String) root.getTransientStateHelper().getTransient(ViewScopeManager.VIEW_MAP_ID); | |
System.out.println("Found " + ViewScopeManager.VIEW_MAP_ID + ": " + key); | |
Map<String, Object> viewMaps = (Map<String, Object>) fctx.getExternalContext().getSessionMap().get(ViewScopeManager.ACTIVE_VIEW_MAPS); | |
Map<String, Object> map = Collections.synchronizedMap(viewMaps); | |
synchronized (map) { | |
System.out.println("Views in session map: " + map.keySet().toString()); | |
map.remove(key); | |
System.out.println("View removed from " + ViewScopeManager.ACTIVE_VIEW_MAPS); | |
System.out.println("The remaining views are: " + map.keySet().toString()); | |
} | |
} | |
} | |
/** | |
* {@inheritDoc} | |
* | |
*/ | |
@Override | |
public boolean isListenerForSource(Object source) { | |
return source instanceof UIViewRoot; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version='1.0' encoding='UTF-8'?> | |
<faces-config version="2.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-facesconfig_2_0.xsd"> | |
<application> | |
<system-event-listener> | |
<system-event-listener-class>com.bluelotussoftware.ViewMapListenerImpl</system-event-listener-class> | |
<system-event-class>javax.faces.event.PreDestroyViewMapEvent</system-event-class> | |
<source-class>javax.faces.component.UIViewRoot</source-class> | |
</system-event-listener> | |
</application> | |
</faces-config> |
Conclusion
The example above is just one mechanism of using a
Subscribe to:
Posts
(
Atom
)
Popular Posts
-
Introduction This article is not another diatribe to tell you the importance of unit testing. I think we can all agree that it is important...
-
A friend of mine asked me if there was a list of reserved words in EL and JSF. He had previously looked for it, and after some Google search...
-
I saw a question posed on stackoverflow called Trouble with Primefaces 3.0.M2 SelectOneMenu Ajax behavior and I had just done an example a...
-
I was working on a couple of SSL based issues when I made a couple of observations. The default self-signed key generation in Java does not ...
-
This is an example on how to make a system call to the local operating system to execute external programs. This example was written to work...
-
We have been doing a lot of work lately with PrimeFaces. A common set of questions comes up about displaying <p:dialog/> boxes on a pa...
-
I was asked earlier today how to reset fields in a JSF application, if the validation fails. In his case, he had a Richfaces table which had...
-
Image by quasarkitten via Flickr The basics for creating a Maven archetype can be found in the Maven - Guide to Creating Archetypes . The ...
-
Previously, I posted an example of how to use JSF 1.2 with form based authentication (j_security_check). In this example, I use JSF 2.x to...
-
Abstract A common use case is to iterate over a collection of elements, and display them on a page. In the world of JSP, we would use a Ja...