This post is after a while. So, what have I been up to. Nothing new in Java world, but with my third iPhone / iPad application underway, I think I have made some serious progress in iPhone development.
So, what is today's topic of discussion? Recently I was faced with an option to choose between SQLite or Core Data for data storage on the device. I was all for SQLite until I found out that all the examples provided by Apple using SQLite were gone.. Not really gone, but switched to Core Data. So, that's how quest to choose began.
So, what do you look into making choices. My first reaction was to see what people out there are doing. What are they using and what choices are they making. Of course, not to follow them, but just to gain insight into their thoughts.
And I found arguments going both ways. Instead of pointing them out, as a quick google search will lead you there, I want to mention my decision. Am I glad I went with Core Data. Let me explain.
Before I made the call to use Core Data I decided that I needed to clearly identify my 'need' and find a solution for it, and which-ever solution fit, I'd go for it. I could quantify my 'need' in the following:
1. invoke a web service and get data and store it on device.
2. query device for listing of saved data with basic querying.
3. update of individual records of saved data.
4. access related entities when reading one entity.
Could I do all of above with SQLite? Yes. What about Core Data? Yes. So, still not clear which one to choose. Next I though of what other 'needs' may arise?
1. update multiple records based on criteria
2. generate detailed, grouped reports
These are possible 'needs' an application may have, but did I foresee this in my app? No. Would SQLite be suitable? Yes. What about Core Data? Its do-able, but not elegant. (such as, looping and updating each record instead of issuing 'update xyz where abc')
This settled one question. If I had these needs, then I would have used SQLite, for performance, ease of use. But, since I do not have this need, which one should I go with? That question still was not answered. Next thought: What does Core Data give me that SQLite does not?
1. ORM 'style' working. (Note: Core Data is not ORM. It does not map a Database Schema, actually it is DB agnostic in a way.. But it works just like ORM models, such as Hibernate models, in many respects).
2. Lazy loading of related entities, reverse relations
3. API for querying, ordering & filtering
4. Session based updates.
Basically, all the goodies that I know and love about Hibernate. (not really all, such as, I cannot bypass the Core Data request and query objects by SQL as in Hibernate). What else would Core Data provide?
1. A new skill.
2. A better understanding of Core Data, so that if and when I have to decide again, I would make a more informed decision.
So, you can see.. I am leaning towards Core Data. So, what is there to convince me? Apple. There is a reason (with Apple knows better) why they switched their examples from SQLite to Core Data. Though it is unlikely that they will drop support for SQLite (Core data itself uses SQLite as one of data store options), but there is going to be lesser and lesser support in Apple documentation for SQLite.
So, there you have it. My reasoning to switch to Core Data. Having said that, Am I glad that I chose it. (Did I already say that?). Accessing and writing data is a breeze. In summary, I would say that if you do not have a 'need' that overwhelmingly 'requires' a SQLite solution, go for Core Data.
Tuesday, July 20, 2010
Wednesday, February 17, 2010
Extending UsernamePasswordAuthenticationFilter in Spring Security
So, you are using Spring security, and you want to process some information after a user has logged in (say, load something in session) or after failed login attempts (such as lock an account after a set number of failed logins.. ), here's how it can be done.. Hope this helps.
Before I go on to describe what goes into it, thanks to the following. These links are a bit dated, but they did help me along.
Custom AuthenticationProcessingFilter for spring security to perform actions on login
An example of the security config for a custom auth filter (see last post)
Spring's documentation on adding own filters
Now, here we go. What is described below works for Spring Security 3.0.0.RELEASE.
1. We need to extend UsernamePasswordAuthenticationFilter
It used to be AuthenticationProcessingFilter, which is depricated.
In this example, we just write to the console. You would do something more important.
2. In spring security context, we will be overriding the form login filter FORM_LOGIN_FILTER.
This used to be AUTHENTICATION_PROCESSING_FILTER, which is not used now.
Note: Since we are replacing the default FORM_LOGIN_FILTER, we should not use <form-login login-page... , as that will try to create the default filter and you would get an exception (that there are two filters defined at the same position).
3. Since we are using the custom FORM_LOGIN_FILTER, we need to set the following property on <http ..
4. Another thing to set at <http is entry-point-ref
Again, since we are altering the default behavior, we need to tell what is the entry point for the form login.
And, correspondingly, define the loginUrlAuthenticationEntryPoint bean. Note that LoginUrlAuthenticationEntryPoint used to be AuthenticationProcessingFilterEntry which is depricated.
5. Remember the filter 'customUsernamePasswordAuthenticationFilter ' we used in in step 2 and extended in step 1, we have to define it.
6. In the definition of 'customUsernamePasswordAuthenticationFilter' we are identifying the 'authenticationManager', so when you define your authentication manager provide an 'alias' for it:
There you have it. Share and enjoy.
Before I go on to describe what goes into it, thanks to the following. These links are a bit dated, but they did help me along.
Custom AuthenticationProcessingFilter for spring security to perform actions on login
An example of the security config for a custom auth filter (see last post)
Spring's documentation on adding own filters
Now, here we go. What is described below works for Spring Security 3.0.0.RELEASE.
1. We need to extend UsernamePasswordAuthenticationFilter
It used to be AuthenticationProcessingFilter, which is depricated.
In this example, we just write to the console. You would do something more important.
public class CustomUsernamePasswordAuthenticationFilter extends
UsernamePasswordAuthenticationFilter {
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, Authentication authResult)
throws IOException, ServletException {
super.successfulAuthentication(request, response, authResult);
System.out.println("==successful login==");
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response, AuthenticationException failed)
throws IOException, ServletException {
super.unsuccessfulAuthentication(request, response, failed);
System.out.println("==failed login==");
}
}
2. In spring security context, we will be overriding the form login filter FORM_LOGIN_FILTER.
This used to be AUTHENTICATION_PROCESSING_FILTER, which is not used now.
<http ...
<custom-filter position="FORM_LOGIN_FILTER" ref="customUsernamePasswordAuthenticationFilter">
Note: Since we are replacing the default FORM_LOGIN_FILTER, we should not use <form-login login-page... , as that will try to create the default filter and you would get an exception (that there are two filters defined at the same position).
3. Since we are using the custom FORM_LOGIN_FILTER, we need to set the following property on <http ..
<http auto-config="false"
4. Another thing to set at <http is entry-point-ref
Again, since we are altering the default behavior, we need to tell what is the entry point for the form login.
<http entry-point-ref="loginUrlAuthenticationEntryPoint"
And, correspondingly, define the loginUrlAuthenticationEntryPoint bean. Note that LoginUrlAuthenticationEntryPoint used to be AuthenticationProcessingFilterEntry which is depricated.
<beans:bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/login.html">
</beans:bean>
5. Remember the filter 'customUsernamePasswordAuthenticationFilter ' we used in in step 2 and extended in step 1, we have to define it.
<beans:bean id="customUsernamePasswordAuthenticationFilter"
class="com.yourapp.web.security.CustomUsernamePasswordAuthenticationFilter" >
<beans:property name="authenticationManager" ref="authenticationManager">
<beans:property name="authenticationFailureHandler" ref="failureHandler">
<beans:property name="authenticationSuccessHandler" ref="successHandler">
</beans:bean>
<beans:bean id="successHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/login.html">
</beans:bean>
<beans:bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login.html?login_error=true">
</beans:bean>
6. In the definition of 'customUsernamePasswordAuthenticationFilter' we are identifying the 'authenticationManager', so when you define your authentication manager provide an 'alias' for it:
<authentication-manager alias="authenticationManager">
...
</authentication-manager>
There you have it. Share and enjoy.
Labels:
aceigi,
authentication,
filters,
Spring,
spring security,
springMVC
Saturday, February 13, 2010
Flash Scope alternative in Spring MVC
Flash scope in Spring MVC has been a topic of discussion, and even though Spring provides infrastructure to create custom scopes, I went with another solution. Hey.. as long as it works.. (for your requirements and within your constraints)...
The goal:
Set a flash error or flash message before redirecting to another view. The next view consumes the flash, displays it and clears it (so that on further redirects or refreshes the message does not appear).
Here we go:
1. Create a SessionHandler (or any other dependency you can inject into your Controller).
2. Use it in your controller.
3. Create FlashController (which is ResourceLoaderAware) and map it to a url (say /flash.html)
Now the question is, we have a way and place to set the flash error/message and now a way to retrieve the message. How do we show it on a view. That comes next.
4. Invoke FlashController from your view using ajax call.
That's it. using jQuery getJSON method, we get the messages, and if received show them.
I'm sure there are limitations and constraints in this method, such as using javascript, ajax may be a constraint. I'm sure workarounds can be found. And if not, then using Spring's custom flash scope is always an option. I would like to hear from you if you find any security issue in this solution. n'joy.
Additional reading:
Custom Scope for Flash Scope discussion
Spring by example Custom ThreadScope
The goal:
Set a flash error or flash message before redirecting to another view. The next view consumes the flash, displays it and clears it (so that on further redirects or refreshes the message does not appear).
Here we go:
1. Create a SessionHandler (or any other dependency you can inject into your Controller).
This handler accepts the flash error/message and sets in session. When requested for it (using consumeFlash), it gets it from the session and clears it. It returns null if it does not find it in session.Next,
public class SessionHandler {
private transient final Log log = LogFactory.getLog(SessionHandler.class);
public static final String FLASH_MESSAGE = "FLASH_MESSAGE";
public static final String FLASH_ERROR = "FLASH_ERROR";
public static final String FLASH_TYPE = "flashType";
public void flashError(HttpServletRequest request, String message){
flash(request, FLASH_ERROR, message);
}
public void flashMessage(HttpServletRequest request, String message){
flash(request, FLASH_MESSAGE, message);
}
public String consumeFlash(HttpServletRequest request, String flashType){
String flash = null;
try {
flash = (String) request.getSession().getAttribute(flashType);
request.getSession().removeAttribute(flashType);
} catch (Exception e){
log.warn("Error retrieving flash value of type:" + flashType);
log.error(e.getMessage());
}
return flash;
}
/**
* helper method that sets the flash message of the type provided in session scope
*/
private void flash(HttpServletRequest request, String flashType, String message){
request.getSession().setAttribute(flashType, message);
}
2. Use it in your controller.
or on a successful operation,
if(<error condition>){
sessionHandler.flashError(request, "user.error.user.id.invalid");
return new ModelAndView(cancelView);
}
userManager.save(user);As of this point we can flash an error or a message. Next step is to show it. Here is where my solution gets a bit different. I created another controller (FlashController) that creates a view of type MappingJacksonJsonView and returns that along with flash messages as redereredAttributes.
sessionHandler.flashMessage(request, "user.message.saved.successfully");
return new ModelAndView(getSuccessView());
3. Create FlashController (which is ResourceLoaderAware) and map it to a url (say /flash.html)
Couple of things to note here. Since I've added support for key-value from a resource properties file, if the flash message sent is found in the resource file (classpath:ApplicationResources.properties by default), it uses that, or else it just sends the message sent.
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
MappingJacksonJsonView view = new MappingJacksonJsonView();
Mapmodel = new HashMap ();
Resource resource = null;
PropertyResourceBundle propertyResourceBundle = null;
try{
resource = resourceLoader.getResource(resourceLocation);
propertyResourceBundle = new PropertyResourceBundle(resource.getInputStream());
}catch (Exception e){
log.warn("Error loading resource bundle");
log.error(e.getMessage());
}
String flashError = sessionHandler.consumeFlash(request, SessionHandler.FLASH_ERROR);
if(!(flashError==null)){
String resolvedFlashError = flashError;
if (!(propertyResourceBundle==null)){
try{
resolvedFlashError = propertyResourceBundle.getString(flashError);
}catch(Exception e){}
}
model.put(SessionHandler.FLASH_ERROR, resolvedFlashError);
}
String flashMessage = sessionHandler.consumeFlash(request, SessionHandler.FLASH_MESSAGE);
if(!(flashMessage==null)){
String resolvedFlashMessage = flashMessage;
if (!(propertyResourceBundle==null)){
try{
resolvedFlashMessage = propertyResourceBundle.getString(flashMessage);
}catch(Exception e){}
}
model.put(SessionHandler.FLASH_MESSAGE, resolvedFlashMessage);
}
SetrenderedAttributes = new HashSet ();
renderedAttributes.add(SessionHandler.FLASH_ERROR);
renderedAttributes.add(SessionHandler.FLASH_MESSAGE);
return(new ModelAndView(view, model));
}
Now the question is, we have a way and place to set the flash error/message and now a way to retrieve the message. How do we show it on a view. That comes next.
4. Invoke FlashController from your view using ajax call.
<script>
$.getJSON("${ctx}/flash.html",
function(data){
$.each(data, function(i,item){
var curDiv = (i=='FLASH_ERROR')?"#flashError":"#flashMessage";
$(curDiv).html(item).fadeIn('slow');
});
});
</script>
<div id="flashError" style="display:none;"></div>
<div id="flashMessage" style="display:none;"></div>
That's it. using jQuery getJSON method, we get the messages, and if received show them.
I'm sure there are limitations and constraints in this method, such as using javascript, ajax may be a constraint. I'm sure workarounds can be found. And if not, then using Spring's custom flash scope is always an option. I would like to hear from you if you find any security issue in this solution. n'joy.
Additional reading:
Custom Scope for Flash Scope discussion
Spring by example Custom ThreadScope
Friday, February 5, 2010
JasperReports in Spring with runtime report and format
This post is after a while. I recently finished a phpCake project, which I want to write about a bit, but in an another post. This post is about something I recently was challenged with and came up with a pretty decent solution. (I think..) hope it helps.
My current project is a Spring based solution, built on Spring MVC, spring Security, Sitemesh, JPA with Hibernate and all other bells and whistles. It also integrates JasperReports. Spring has built in support for JasperReports. You can see it documented (that can be debated) here. It has built in View implementations for different renderings of the JasperReports. (csv, html, pdf, xls).
It works, with a little bit of digging.
But it was not sufficient for my requirement, which was:
Allow for rendering of a jasper report picked at runtime in a format chosen at runtime.
The View resolvers pretty much expect that the report url be defined at configuration time. Spring has another View implementation (JasperReportsMultiFormatView) that allows run time format choice, but the JasperReport url still needs to be defined at configuration time.
I understand where this behavior comes from, as majority of the time the reports are built and packaged with source code and the rendering is wired. But it fell short of allowing picking JasperReport at runtime. So, determined to get it to work within the framework of Spring Jasper View implementations (with its nifty support for both .jrxml and compiled .jasper) , I came up with this solution. Of course, this is one implementation, and can be optimized.. If you do, please drop in a note in comments.
1. Create a JasperReportsViewFactory
As you can see, the return type is a super class of all the Spring's Jasper View implementations. Another feature in this method is to set content disposition and supply an alternate file name for the downloaded file.
2. Use It
Once you have this , make it a dependency in your controller responsible for launching the report, and provide the url, format and other required elements for the view resolver, and execute your report.
Limitations:
I'm sure there are some.. One that I know of is Jasper's sub-reports. For me it is not an issue right now as we are not supporting Jasper sub-Reports in our application.
There you have it.. short and sweet. Here are some other links if this is not what you're looking for.
Matt Raible's blog on JasperReports with Appfuse and Spring (dated)
AppFuseJasperReports
A springOne presentation of Spring and JasperReports
Filename discussion using JasperReportsMultiFormatView using configuration
My current project is a Spring based solution, built on Spring MVC, spring Security, Sitemesh, JPA with Hibernate and all other bells and whistles. It also integrates JasperReports. Spring has built in support for JasperReports. You can see it documented (that can be debated) here. It has built in View implementations for different renderings of the JasperReports. (csv, html, pdf, xls).
It works, with a little bit of digging.
But it was not sufficient for my requirement, which was:
Allow for rendering of a jasper report picked at runtime in a format chosen at runtime.
The View resolvers pretty much expect that the report url be defined at configuration time. Spring has another View implementation (JasperReportsMultiFormatView) that allows run time format choice, but the JasperReport url still needs to be defined at configuration time.
I understand where this behavior comes from, as majority of the time the reports are built and packaged with source code and the rendering is wired. But it fell short of allowing picking JasperReport at runtime. So, determined to get it to work within the framework of Spring Jasper View implementations (with its nifty support for both .jrxml and compiled .jasper) , I came up with this solution. Of course, this is one implementation, and can be optimized.. If you do, please drop in a note in comments.
1. Create a JasperReportsViewFactory
protected static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
public AbstractJasperReportsSingleFormatView getJasperReportsView(HttpServletRequest httpServletRequest,
DataSource dataSource, String url, String format, String fileName){
String viewFormat = format==null?"pdf":format;
// set possible content headers
Properties availableHeaders = new Properties();
availableHeaders.put("html", "inline; filename="+fileName+".html");
availableHeaders.put("csv", "inline; filename="+fileName+".csv");
availableHeaders.put("pdf", "inline; filename="+fileName+".pdf");
availableHeaders.put("xls", "inline; filename="+fileName+".xls");
// get jasperView class based on the format supplied
// defaults to pdf
AbstractJasperReportsSingleFormatView jasperView = null;
if(viewFormat.equals("csv")) {
jasperView = new JasperReportsCsvView();
}else if(viewFormat.equals("html")){
jasperView = new JasperReportsHtmlView();
}else if(viewFormat.equals("xls")){
jasperView = new JasperReportsXlsView();
}else{
jasperView = new JasperReportsPdfView();
}
// get appContext. required by the view
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(
httpServletRequest.getSession().getServletContext());
// set the appropriate content disposition header.
Properties headers = new Properties();
headers.put(HEADER_CONTENT_DISPOSITION, availableHeaders.get(viewFormat));
// set the relevant jasperView properties
jasperView.setJdbcDataSource(dataSource);
jasperView.setUrl(url);
jasperView.setApplicationContext(ctx);
jasperView.setHeaders(headers);
// return view
return jasperView;
}
As you can see, the return type is a super class of all the Spring's Jasper View implementations. Another feature in this method is to set content disposition and supply an alternate file name for the downloaded file.
2. Use It
Once you have this , make it a dependency in your controller responsible for launching the report, and provide the url, format and other required elements for the view resolver, and execute your report.
public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws Exception {
Mapmodel = new HashMap ();
String format = httpServletRequest.getParameter("format");
//Default format to pdf
if (StringUtils.hasText(format)){
if (!(format.equalsIgnoreCase("pdf") || format.equalsIgnoreCase("html")
|| format.equalsIgnoreCase("csv") || format.equalsIgnoreCase("xls"))){
format = "pdf";
}
}else{
format = "pdf";
}
// get the View that will render the report.
// in actual controller, based on report id rquestd, get the report name and build URL and use
AbstractJasperReportsSingleFormatView jasperView = jasperReportsViewFactory.getJasperReportsView(
httpServletRequest, dataSource, "/WEB-INF/jasper/sample.jrxml",format,"DownloadFileName");
// add parameters used by the report
model.put("Company","Sample Company");
// more here...
return new ModelAndView(jasperView, model);
}
Limitations:
I'm sure there are some.. One that I know of is Jasper's sub-reports. For me it is not an issue right now as we are not supporting Jasper sub-Reports in our application.
There you have it.. short and sweet. Here are some other links if this is not what you're looking for.
Matt Raible's blog on JasperReports with Appfuse and Spring (dated)
AppFuseJasperReports
A springOne presentation of Spring and JasperReports
Filename discussion using JasperReportsMultiFormatView using configuration
Subscribe to:
Posts (Atom)