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
Thursday, September 17, 2009
Baking with cakePHP
Its been a while..
So lately I've been baking with cakePHP. Since I'm new to php and new to this framework, my thoughts might overlap between the two. A comment for the cake might be due to php and vice-versa. Anyway, here it goes. Instead of pro's and con's, I'll write as likes and don't-likes.. in no particular order. As I don't think I can judge php and related technology being a newbie..
Like:
First thoughts of using phpcake reminded me of Grails. very simple, less code and code generator tools.
Don't Like:
Too much reliance on convention over configuration. I'm still a bit 'old-school' if you will on this. My gripe with this is that if you live a framework (meaning that is all that you do), then convention is all ok. But if you switch between projects using different frameworks, configuration is a lifesaver. You know exactly what goes where and why. Personally I fall in the second camp and don't like to rely on too many 'automagic' methods.
Like:
convention overrides. It gives ways to override conventions. Such as /controllers/opportunities_controller.php expects and uses /models/opportunity.php model and will error out if model not present. But if you want to use /models/client.php model in /controllers/opportunities_controller.php, just declare a member:
or if you want to use other models, declare:
Like:
bake tool. It generates the models, views, controllers with staple code. The generated code is very workable to customize.
Don't Like:
ACL. Nothing wrong with ACL, but the heavy reliance on ACL for Authorization. I wish they support url pattern for authorization as an alternative. (maybe they do.. but I didn't find a good example). As a comparison see aceigi ( http://www.acegisecurity.org/petclinic-tutorial.html and scroll to block of code just before section 'Start petclinic's database)
Also, there is not much support for 'rapid development' with authorization using ACL. Everyone seems to create a different way to implement the actual authorization permission checking, especially from the views. So, I did the same. I even had to create my own session managed permission map, so that the system does not make tons of db queries on each page request.
And if you need to see at a later date which resource is authorized to whom, you need to be a SQL guru to run Tree/Hierarchical queries to find that out.
Like:
debugging. It helps a lot, and shows what framework is doing internally to get stuff done.
Don't Like:
Lack to true OO. a quick example. It allows you to create a Model class. When you invoke for a model from the Model's find() method, you don't get an instance of the model. You get an array with data?!
Lets say controllerA is using ModelB, you can say:
Like:
components for controllers and helpers for views concept. This helps create reusable functionality and integration into controllers and views is seamless.
Don't Like:
models with data access methods. I had this gripe with Grails as well. There is a big debate on this issue about should models be aware of loading and fetching themselves or should that functionality be separated in DAO's. I don't want to judge which is better, but I like DAO's.. This helps models to behave as command or transport objects.
Like:
dynamic methods: findBy... and findAllBy.. on models.. that's a life saver.
Like:
$conditions for making complex queries. Build your complex query in an array, and supply it to the find method. This addresses one issue I had talked about earlier. See ORM and search/filtering In effect it uses the method I had talked about called 'search...(criteria)', where a criteria object is built and sent to the search method.
Don't Like:
->, => .. fingers hurt typing. This is php issue though..
So finally, would I use php cake in future? Yes, for a quick prototype or where php is required in a project. But for more enterprise solutions I'd fall back on a java solution.
So lately I've been baking with cakePHP. Since I'm new to php and new to this framework, my thoughts might overlap between the two. A comment for the cake might be due to php and vice-versa. Anyway, here it goes. Instead of pro's and con's, I'll write as likes and don't-likes.. in no particular order. As I don't think I can judge php and related technology being a newbie..
Like:
First thoughts of using phpcake reminded me of Grails. very simple, less code and code generator tools.
Don't Like:
Too much reliance on convention over configuration. I'm still a bit 'old-school' if you will on this. My gripe with this is that if you live a framework (meaning that is all that you do), then convention is all ok. But if you switch between projects using different frameworks, configuration is a lifesaver. You know exactly what goes where and why. Personally I fall in the second camp and don't like to rely on too many 'automagic' methods.
Like:
convention overrides. It gives ways to override conventions. Such as /controllers/opportunities_controller.php expects and uses /models/opportunity.php model and will error out if model not present. But if you want to use /models/client.php model in /controllers/opportunities_controller.php, just declare a member:
$uses = array('Client');
or if you want to use other models, declare:
$uses = array('Opportunity','Client');
Like:
bake tool. It generates the models, views, controllers with staple code. The generated code is very workable to customize.
Don't Like:
ACL. Nothing wrong with ACL, but the heavy reliance on ACL for Authorization. I wish they support url pattern for authorization as an alternative. (maybe they do.. but I didn't find a good example). As a comparison see aceigi ( http://www.acegisecurity.org/petclinic-tutorial.html and scroll to block of code just before section 'Start petclinic's database)
Also, there is not much support for 'rapid development' with authorization using ACL. Everyone seems to create a different way to implement the actual authorization permission checking, especially from the views. So, I did the same. I even had to create my own session managed permission map, so that the system does not make tons of db queries on each page request.
And if you need to see at a later date which resource is authorized to whom, you need to be a SQL guru to run Tree/Hierarchical queries to find that out.
Like:
debugging. It helps a lot, and shows what framework is doing internally to get stuff done.
Don't Like:
Lack to true OO. a quick example. It allows you to create a Model class. When you invoke for a model from the Model's find() method, you don't get an instance of the model. You get an array with data?!
Lets say controllerA is using ModelB, you can say:
$model = $this->ModelB->find(...)This is OO. But any call on
$model->..fails, as $model is not an instance of a class. It is an array.
Like:
components for controllers and helpers for views concept. This helps create reusable functionality and integration into controllers and views is seamless.
Don't Like:
models with data access methods. I had this gripe with Grails as well. There is a big debate on this issue about should models be aware of loading and fetching themselves or should that functionality be separated in DAO's. I don't want to judge which is better, but I like DAO's.. This helps models to behave as command or transport objects.
Like:
dynamic methods: findBy... and findAllBy.. on models.. that's a life saver.
Like:
$conditions for making complex queries. Build your complex query in an array, and supply it to the find method. This addresses one issue I had talked about earlier. See ORM and search/filtering In effect it uses the method I had talked about called 'search...(criteria)', where a criteria object is built and sent to the search method.
Don't Like:
->, => .. fingers hurt typing. This is php issue though..
There are features that I've not tried yet. Such as behaviors, elements etc. I may write again when I have a fuller grasp of the framework.
So finally, would I use php cake in future? Yes, for a quick prototype or where php is required in a project. But for more enterprise solutions I'd fall back on a java solution.
Friday, May 29, 2009
Designing Correct Solutions
Recently I was asked to describe my experience with solutioning. Fristly, I'm not sure if solutioning is a word, but, assuming that it means 'my experience with creating solutions', I said:
"Each opportunity presents a unique set of challenges and requires a unique approach for arriving at a solution.
I have come to realize that the best solution comes by consulting the team, explaining the solution to stakeholders, prototyping and building on the results, learning from past experiences and never shunning an advice.
Technology plays a role in making a right solution, but is not the driver for a solution. A customer's need should drive a solution.
A good solution is a correct solution. A solution can be enhanced by making it efficient, robust, cost effective and scalable. "
Well, I wrote this, that is why I have the original quote. And I thought, elaborate it in my post. So, instead of repeating what I said, I'll just highlight a thought and expound on it.
Each unique opportunity requires a unique approach
Meaning, one cannot take a cookie cutter approach to any challenge presented, how so much ever it is similar to what he/she has done before. Of course, one can take from one's experience, but each new task should be taken on its own merits, analysed, designed, solved and tested. Identify the challenges, find parallels in your experience and extract what is new and what can be reused, solve the problem as a whole independent problem with a whole independent solution.
Consult with the team
Ever so often, in this every changing and tele-commuting world, with vertical job descriptions, we forget that we are a part of a team. It is a job of a team to provide a solution. An architect, an analyst, a tech lead, a developer, a tester, a project manager, a designer, an information architect etc. etc. comprises a team. These people cannot, should not work in a vacuum. If an architect comes with a design, consult with your tech lead, your PM, your stakeholder before you set it in stone. If a developer comes up with re-usable components, consult with team lead, testers, folks who will maintain the codebase before you refactor. If an IA comes up with a new work flow, consult with who-so-ever it will affect before you put it in your wireframes. Increased communication brings increased clarity, increased productivity, decreases re-works and every team member appreciates the other.
Explain your solution to stakeholders
One of the reasons so many solutions fail to live up to their promise is that the end result is not what you were hired to build. There exists a flurry of agile methodologies that address this problem, be it SCRUM, XP, RUP or their variations. Among many things these methodologies try to solve is to make sure the solution is presented to stakeholders so that they can see the results sooner, and they can control the direction. Which is good. For me, it is as simple as honoring a contract. If you were contracted to build a wall, you build a wall. You do not build a picket fence and deliver at the end with no budget to correct it.
Prototype and build on results
As mentioned earlier, every problem presents a unique set of challenges and require a unique set of solutions. From them are those solutions that one has no experience with, or just a better way of achieving the results. I say, go for it. But prototype first, on a small scale. If it works, then refactor and build. If not, you haven't lost much, rather learned which path not to take in future.
Learning from past experiences
Experience is a valuable asset and one's seniority is defined by his/her experience. In my humble opinion, a lot of repetition does not qualify for equivalent time of experience, rather the exposure to different tasks or variations of a task amount to experience. For example, there is difference in the quality of experience of a person who has installed 100 bath tubs in peoples homes versus a person who has installed 10 bath tubs, but each in a different setting, such as a residential complex, a business, a public facility, a government institution etc. etc.
Having said that, experience is a valuable asset and lessons should be extracted from it, and applied in your work. If you find an urge to try someting fanciful and it cannot be justified within the context of a project, try it on a personal pet project. (of course, I would not say do not try it.. just don't try it on a project at the expense of your business sponsor)
Never shun an advice
Even if it is from a person not in your descipline. Be grateful that someone cares about you and wants to help you achieve your goals. If you disagree, disagree on its merits or demerits, not because 'who is he/she to say this.' All members of a team come from varied backgrounds and have had unique experiences in their past work or jobs, and if someone offers an advice, hear it. This does not mean, you do not excercise your judgment. No. Rather, what I am saying is, use that judgment to analyze the advice. If there is something valueable in it, acknowledge it and use it. If not, then you have heard.
Technology is not a driver of a solution
Rather, the business owner, stakeholders are the driver. One should not forget that someone owns the project and has funded it. They need something out of it which brings some business value to them. That should be the goal in designing a solution. Then, use the technology to achieve it. Technology is a means to the solution, not the goal.
Yes, sometimes you may be bound by technology choices, which are made by someone sitting in a board room somewhere and has paid enormous license fees. And sometimes, you are the boss, you can choose your latest and greatest tool available out there. So, in the first case, make the best of what is available to you. If you want change, get every concerned party on board before changing. Be prepared to explain that the technology change is supprotable, maintainable, affordable and necessary.In the second case, do not get carried away. Use the technology that is just right, affordable and maintainable for your client, even if it means not using your favorite tool that was beta-released a day before.
A good solution is a correct solution
How often do we see emphasis put on the scalablity of the solution, or configurability or how cost efficient the solution is. But we loose sight of the bigger picture, is the solution put in place the 'correct' solution? Yes we can build a scissor that can cut thru 100 pages in 2 seconds and build it very cheap, but can a surgeon finely cut muscle tissue with it in an operation, the reason for builing this scissor?
So, the first thing one should focus on is that the solution is the correct solution for the problem. Once you have a correct solution, you can work day and night to make it most efficient, cost effective, robust, scalable or any other enhancement if you like.
Finally,
Of course much more could be said, and I'm sure has been said. I welcome critique, corrections or additions.
"Each opportunity presents a unique set of challenges and requires a unique approach for arriving at a solution.
I have come to realize that the best solution comes by consulting the team, explaining the solution to stakeholders, prototyping and building on the results, learning from past experiences and never shunning an advice.
Technology plays a role in making a right solution, but is not the driver for a solution. A customer's need should drive a solution.
A good solution is a correct solution. A solution can be enhanced by making it efficient, robust, cost effective and scalable. "
Well, I wrote this, that is why I have the original quote. And I thought, elaborate it in my post. So, instead of repeating what I said, I'll just highlight a thought and expound on it.
Each unique opportunity requires a unique approach
Meaning, one cannot take a cookie cutter approach to any challenge presented, how so much ever it is similar to what he/she has done before. Of course, one can take from one's experience, but each new task should be taken on its own merits, analysed, designed, solved and tested. Identify the challenges, find parallels in your experience and extract what is new and what can be reused, solve the problem as a whole independent problem with a whole independent solution.
Consult with the team
Ever so often, in this every changing and tele-commuting world, with vertical job descriptions, we forget that we are a part of a team. It is a job of a team to provide a solution. An architect, an analyst, a tech lead, a developer, a tester, a project manager, a designer, an information architect etc. etc. comprises a team. These people cannot, should not work in a vacuum. If an architect comes with a design, consult with your tech lead, your PM, your stakeholder before you set it in stone. If a developer comes up with re-usable components, consult with team lead, testers, folks who will maintain the codebase before you refactor. If an IA comes up with a new work flow, consult with who-so-ever it will affect before you put it in your wireframes. Increased communication brings increased clarity, increased productivity, decreases re-works and every team member appreciates the other.
Explain your solution to stakeholders
One of the reasons so many solutions fail to live up to their promise is that the end result is not what you were hired to build. There exists a flurry of agile methodologies that address this problem, be it SCRUM, XP, RUP or their variations. Among many things these methodologies try to solve is to make sure the solution is presented to stakeholders so that they can see the results sooner, and they can control the direction. Which is good. For me, it is as simple as honoring a contract. If you were contracted to build a wall, you build a wall. You do not build a picket fence and deliver at the end with no budget to correct it.
Prototype and build on results
As mentioned earlier, every problem presents a unique set of challenges and require a unique set of solutions. From them are those solutions that one has no experience with, or just a better way of achieving the results. I say, go for it. But prototype first, on a small scale. If it works, then refactor and build. If not, you haven't lost much, rather learned which path not to take in future.
Learning from past experiences
Experience is a valuable asset and one's seniority is defined by his/her experience. In my humble opinion, a lot of repetition does not qualify for equivalent time of experience, rather the exposure to different tasks or variations of a task amount to experience. For example, there is difference in the quality of experience of a person who has installed 100 bath tubs in peoples homes versus a person who has installed 10 bath tubs, but each in a different setting, such as a residential complex, a business, a public facility, a government institution etc. etc.
Having said that, experience is a valuable asset and lessons should be extracted from it, and applied in your work. If you find an urge to try someting fanciful and it cannot be justified within the context of a project, try it on a personal pet project. (of course, I would not say do not try it.. just don't try it on a project at the expense of your business sponsor)
Never shun an advice
Even if it is from a person not in your descipline. Be grateful that someone cares about you and wants to help you achieve your goals. If you disagree, disagree on its merits or demerits, not because 'who is he/she to say this.' All members of a team come from varied backgrounds and have had unique experiences in their past work or jobs, and if someone offers an advice, hear it. This does not mean, you do not excercise your judgment. No. Rather, what I am saying is, use that judgment to analyze the advice. If there is something valueable in it, acknowledge it and use it. If not, then you have heard.
Technology is not a driver of a solution
Rather, the business owner, stakeholders are the driver. One should not forget that someone owns the project and has funded it. They need something out of it which brings some business value to them. That should be the goal in designing a solution. Then, use the technology to achieve it. Technology is a means to the solution, not the goal.
Yes, sometimes you may be bound by technology choices, which are made by someone sitting in a board room somewhere and has paid enormous license fees. And sometimes, you are the boss, you can choose your latest and greatest tool available out there. So, in the first case, make the best of what is available to you. If you want change, get every concerned party on board before changing. Be prepared to explain that the technology change is supprotable, maintainable, affordable and necessary.In the second case, do not get carried away. Use the technology that is just right, affordable and maintainable for your client, even if it means not using your favorite tool that was beta-released a day before.
A good solution is a correct solution
How often do we see emphasis put on the scalablity of the solution, or configurability or how cost efficient the solution is. But we loose sight of the bigger picture, is the solution put in place the 'correct' solution? Yes we can build a scissor that can cut thru 100 pages in 2 seconds and build it very cheap, but can a surgeon finely cut muscle tissue with it in an operation, the reason for builing this scissor?
So, the first thing one should focus on is that the solution is the correct solution for the problem. Once you have a correct solution, you can work day and night to make it most efficient, cost effective, robust, scalable or any other enhancement if you like.
Finally,
Of course much more could be said, and I'm sure has been said. I welcome critique, corrections or additions.
Monday, April 27, 2009
Why Nassi-Schniederman a flowchart?
If you can use a flowchart synonymously with a Nassi Schniederman diagram (NSD), why would you want to use it? Flow-charts are widely supported in many tools and any algorithm can be possibly drawn with it, why would you need a NSD? I felt the need for it. Here is why.
While working on an SMS solution where the system responds to individual SMS text messages, each controlled by a single keyword. Each SMS has a response based on conditions such as, which phone was used to text, if the keyword was sent before from that phone, if a user had access to request a resource, etc. etc. I had to make sure that each and every possible scenario is handled by the system resulting in a successful or an error response. A logical approach would be to draw a flowchart outlining each possible path that ends in a response. While technically correct, I felt it did not deliver what I was looking for, which is a complete snapshot of all possible scenarios laid out, guaranteeing that no scenario was missing.
I recalled a good example in the book 'Groovy in Action', they used a NSD to identify how a method is invoked in a Groovy Class, depending on if the class instance is a Groovy Object, a Closure or an instance of Groovy interceptable. It identifies at the bottom of the chart which method gets invoked based on the path taken from top to bottom. I felt, if I laid out all possible scenarios in a diagram like this, it would 'shout' at me if I was missing a scenario/path a SMS message could take.
Next step was to draw one. Of course I could draw by hand, but I needed to document it as well. That resulted in a google search, and I did find couple of commercial products, and with little further search I found Structorizer (GPL), an open source product. Though rough on edges, it does the job. Very satisfied with the tool, outputs the diagram in a range of formats, including .png and .pdf.
As an comparison, I thought post an example NSD. Below you will find a NSD equivalent of a flowchart example found on wikipedia's flowchart page.
Flow Chart example (from wikipedia)

Equivalent NSD drawn using Structorizer.

So, experiment with NSD in addition to a flowchart. You never know why one diagram may add value over the other, even if technically they have the same information.
While working on an SMS solution where the system responds to individual SMS text messages, each controlled by a single keyword. Each SMS has a response based on conditions such as, which phone was used to text, if the keyword was sent before from that phone, if a user had access to request a resource, etc. etc. I had to make sure that each and every possible scenario is handled by the system resulting in a successful or an error response. A logical approach would be to draw a flowchart outlining each possible path that ends in a response. While technically correct, I felt it did not deliver what I was looking for, which is a complete snapshot of all possible scenarios laid out, guaranteeing that no scenario was missing.
I recalled a good example in the book 'Groovy in Action', they used a NSD to identify how a method is invoked in a Groovy Class, depending on if the class instance is a Groovy Object, a Closure or an instance of Groovy interceptable. It identifies at the bottom of the chart which method gets invoked based on the path taken from top to bottom. I felt, if I laid out all possible scenarios in a diagram like this, it would 'shout' at me if I was missing a scenario/path a SMS message could take.
Next step was to draw one. Of course I could draw by hand, but I needed to document it as well. That resulted in a google search, and I did find couple of commercial products, and with little further search I found Structorizer (GPL), an open source product. Though rough on edges, it does the job. Very satisfied with the tool, outputs the diagram in a range of formats, including .png and .pdf.
As an comparison, I thought post an example NSD. Below you will find a NSD equivalent of a flowchart example found on wikipedia's flowchart page.
Flow Chart example (from wikipedia)
Equivalent NSD drawn using Structorizer.

So, experiment with NSD in addition to a flowchart. You never know why one diagram may add value over the other, even if technically they have the same information.
Labels:
flowchart,
Groovy,
Nassi Schniederman,
requirements,
SMS
Tuesday, March 3, 2009
jfcTags is out
jfcTags 0.4 is released (alpha release) under LGPL license and you can download it here .
So what is jfcTags?
It is an easy way to build charts in web applications by defining the charts using jfcTags tag library. The goal was to make it easy for web developers to use jfreeChart charting library. Using it the traditional way was, lets say, a decent amount of work per chart, and if you are making an application with many charts, writing that many servlets can be daunting, not to mention all the chart display properties would be compiled in. So I decided to make it easy on myself and wrote this library and I thought to share with others in the open source community. So, how do you build charts?
Lets say, you have a JFreeChart PieDataset 'chartData' in request scope, and you want to build a pie chart. Here is how you would do it.
1. set it up
a. Include jfcTags and JFreeChart jar files and all the JFreeChart dependencies.
b. define jfcTags chart servlet in web.xml
a. Include jfcTags taglib declaration
To make this post short, I'll just mention some other features:
So what is jfcTags?
It is an easy way to build charts in web applications by defining the charts using jfcTags tag library. The goal was to make it easy for web developers to use jfreeChart charting library. Using it the traditional way was, lets say, a decent amount of work per chart, and if you are making an application with many charts, writing that many servlets can be daunting, not to mention all the chart display properties would be compiled in. So I decided to make it easy on myself and wrote this library and I thought to share with others in the open source community. So, how do you build charts?
Lets say, you have a JFreeChart PieDataset 'chartData' in request scope, and you want to build a pie chart. Here is how you would do it.
1. set it up
a. Include jfcTags and JFreeChart jar files and all the JFreeChart dependencies.
b. define jfcTags chart servlet in web.xml
<servlet>2. use it
<servlet-name>chart</servlet-name>
<servlet-class>
com.logific.jfctags.servlet.ChartServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>chart</servlet-name>
<url-pattern>
/chart/*
</url-pattern>
</servlet-mapping>
a. Include jfcTags taglib declaration
<%@ taglib prefix="jfct" uri="http://www.logific.com/jfctags" %>b. Define chart
<jfct:chart chartservletmapping="/chart"This generates the following chart.
id="pieChartStrData"
charttype="p"
dataset="${chartData}"
width="360"
height="300"
title="Coffee Pie Chart"
sectionpaintlist="#FFB728|#FF5432|#2889FF"
plotbackgroundpaint="#fdfdfd"
backgroundpaint="#ffffff"
generateurls="true"
imagecssclass="noborder"
urlprefix="/pieDetail.jsp"
urlcategoryparamname="beverageName"
urlindexparamname="pieIndex"
maximumlabelwidth="20"
valueformat="percent"
valueformatstring="#0.00%"
labelfont="helvetica"
labelpaint="#679ed2"
labelbackgroundpaint="#feeffe">
</jfct:chart>
To make this post short, I'll just mention some other features:
- Supply data to chart using JFreeChart Datasets or String based formatted data
- URL support with Drill down capabilities
- ToolTips support
- Currently supports Pie, 3D Pie, Line, Bar and Stacked Bar charts
- jfcTags tag library jar file
- jfcTags-sample-webapp war file
- jfcTags user guide and tag library reference pdf.
Labels:
charting,
Java,
jfcTags,
jFreeChart,
open source,
servlet,
taglib
Saturday, January 10, 2009
ORM and searching / filtering
OK, so you have decided to use an ORM. And there is a need to get all users or a user from database.
This is not a discussion about how to implement the DAO method. Is it by a query, calling a stored procedure or using the ORM's object based querying.
Having said that, to get users from database, you go ahead and write your DAO class with methods: getAll() and get(id)
How about, get all users who belong to a specific company. Easy. You go and write :getUsersByCompany(Company company).
So far so good. There is a new use case that requires all users who belong to a specific company and are employed full time and were hired in last 4 months and speak English.
Is the method: getUsersByComapnyAndByHireTypeAndByDateOfHireAndBy.... in works for your DAO class?
Or you just use the DAO method : getUsersByCompany(..)and then further filter in a service method by parsing and inspecting user attributes and excluding the ones that do not match the criteria?
This makes me think, what is a criteria for a method to qualify for a home in a DAO class? get(), getAll(), delete(id), update(object), getByThis(..), getByThisAndThat(..)These methods seem logical and most of them are necessary. But why would the above mentioned method not qualify? (or should it?)
There exists a solution in a more dynamic language based framework, like Grails based on Groovy, which kind of does away with the DAO objects and the domain class itself is responsible for its data access and storage. An example is : customer = Customer.findByName("... This is achieved by dynamic methods. But we're talking about java, which is not dynamic.
Having raised the question,I have couple of methods that I follow, but I'm not sure if they are most optimal.
I use a mix of DAO methods and additional service methods to apply further filtering. Lets take the example above: find users "who belong to a specific company and are employed full time and were hired in last 4 months and speak English".
Based on the overall scope of the project, I would decide to what detail I should create a DAO method. Accordingly I'll create:
getUsersByCompanyAndEmploymentType(company, employmentType) Among the criteria to create this method, is, Is the resultant list of users manageable for any further processing without putting undue stress on the server? Is this method useful to fulfill some other use cases?
This gets the users for the specific company and who work full time, then I pass this to a service method that parses the users and filters users who were hired within last 4 months and who speak English.
Another alternative for such cases could be a single catch-all method called: searchUsers(criteria)where criteria could be sent either as a Hashmap, or a class with specific fields that the users can be search by. The service method fills in the criteria based on a use case and pass it on to DAO.
These may not be the most optimal solutions, but I would like to hear of alternatives.
On a side note, there exists a mini-framework that helps with Hibernate and this 'search' issue, which formalizes the Search method. Its called 'hibernate-generic-dao'. I have not used it, but concept looks nice, but again, its tied to Hibernate only.
This is not a discussion about how to implement the DAO method. Is it by a query, calling a stored procedure or using the ORM's object based querying.
Having said that, to get users from database, you go ahead and write your DAO class with methods: getAll() and get(id)
How about, get all users who belong to a specific company. Easy. You go and write :getUsersByCompany(Company company).
So far so good. There is a new use case that requires all users who belong to a specific company and are employed full time and were hired in last 4 months and speak English.
Is the method: getUsersByComapnyAndByHireTypeAndByDateOfHireAndBy.... in works for your DAO class?
Or you just use the DAO method : getUsersByCompany(..)and then further filter in a service method by parsing and inspecting user attributes and excluding the ones that do not match the criteria?
This makes me think, what is a criteria for a method to qualify for a home in a DAO class? get(), getAll(), delete(id), update(object), getByThis(..), getByThisAndThat(..)These methods seem logical and most of them are necessary. But why would the above mentioned method not qualify? (or should it?)
There exists a solution in a more dynamic language based framework, like Grails based on Groovy, which kind of does away with the DAO objects and the domain class itself is responsible for its data access and storage. An example is : customer = Customer.findByName("... This is achieved by dynamic methods. But we're talking about java, which is not dynamic.
Having raised the question,I have couple of methods that I follow, but I'm not sure if they are most optimal.
I use a mix of DAO methods and additional service methods to apply further filtering. Lets take the example above: find users "who belong to a specific company and are employed full time and were hired in last 4 months and speak English".
Based on the overall scope of the project, I would decide to what detail I should create a DAO method. Accordingly I'll create:
getUsersByCompanyAndEmploymentType(company, employmentType) Among the criteria to create this method, is, Is the resultant list of users manageable for any further processing without putting undue stress on the server? Is this method useful to fulfill some other use cases?
This gets the users for the specific company and who work full time, then I pass this to a service method that parses the users and filters users who were hired within last 4 months and who speak English.
Another alternative for such cases could be a single catch-all method called: searchUsers(criteria)where criteria could be sent either as a Hashmap, or a class with specific fields that the users can be search by. The service method fills in the criteria based on a use case and pass it on to DAO.
These may not be the most optimal solutions, but I would like to hear of alternatives.
On a side note, there exists a mini-framework that helps with Hibernate and this 'search' issue, which formalizes the Search method. Its called 'hibernate-generic-dao'. I have not used it, but concept looks nice, but again, its tied to Hibernate only.
Tuesday, December 30, 2008
stuff change on you...
I am sure at some point in time we all make a judgment call to go with a piece of software based on its merits. The criteria for what constitutes a merit differs from one individual to another. We come up with a set of criteria and a set of softwares to choose from. We subject the software to the criteria and make a call. All well and good.
If for some reason the software we choose is the choice of many others in our 'sphere of interest' we have a hit. And if we are an outlier, we end up in one of two scenarios.
1. Either we really have made a good choice and the market around has to 'see' the light and catch on, or
2. We really missed the mark and we have to re-analyze our choice and 'catch-up' with the rest.
Of course, the realization of 'hitting the mark' itself is relative. I'm sure there are some die hard fans of EJB2 who will still say that Hibernate and other ORM's have not got it.
So, what would you say, a person trying to make a call between EJB2 and Hibernate?
One can't say for sure. Hear this argument.
Joe: It does not matter what features EJB2 and Hibernate have, our company policy is not to use open source products. All products have to comply with industry standards.
Mark: But what is 'industry standard'. Isn't it what the 'industry' accepts as a standard.. meaning us, developers/architects. If we say Hibernate is a better choice, so it is a standard.
Joe: Possibly, but our policy writers do not see it like that. If it does not come from the Suns, IBMs, Xs or Ys, its not a standard.
Mark: but..
So, you see, Joe and Mark agree. But still have to disagree due to the criteria used for making a choice.
Then there are re-incarnations.
Remember when you looked at JSF when the world was going with Struts and its sisters. Its too dotnet. Its too component oriented. Its not MVC enough. Its this and its not that. The 'sphere of interest' goes with Struts, Webworks, SpringMVC etc. etc. And then JSF comes with a re-incarnation. It has the blessing of the big names Joe was looking for. It has the blessing of 'us, developers/architects' in open source implementations of JSF that Mark was looking for.
So, what would you say, a person who made the choice of JSF at a time when it did not make the cut.. and stuck with it. Is it because that person 'saw' the promise and potential and had the foresight of its success? Or is it just that the person gambled with it and it paid out?
Its the similar story with EJB in its new EJB3 re-incarnation.
Then there is stuff that changes on you.
How often do you make a choice of software with due diligence. Even the 'sphere of interest' is with you. Things are going fine.. You bet your projects and your raise on it. And then it hits you. The people responsible for your choice software bail out on you. The product is no longer supported.
Recently I was looking for a tag library to use jfreecharts.. Cewolf was the number one choice. Even documented and recommended by jfreechart folks.. But its not supported anymore.
Would you use it in your project? (on a side note, I'm writing my own now.)
Another case in point is Appfuse. I have used it multiple times.. with JSF and SpringMVC. Every time I have to use Appfuse, I've to make a call, which MVC framework to use. And to be frank, I had gotten to like SpringMVC. But it seems appfuse may drop support for springMVC. (http://raibledesigns.com/rd/entry/appfuse_light_converted_to_maven). I hope I read it wrong.
So, what would you say, a person who made a choice of SpringMVC with Appfuse, and then the folks at Appfuse possibly dropping SpringMVC support?
One could say, 'Its a price for getting stuff free.'.
Or one could say, 'Get a life.. what else do you expect. It is the hazard of the landscape.'
Or as Arnold would say, 'Stop whining.'
I say, Is it even something one should feel averse to? Is it something that is not good for you? Isn't change supposed to be good?
Yes, sometimes you change your choice, sometimes the 'sphere of interest' changes its choices and sometimes someone else changes your choice. Its an opportunity.
Its an opportunity to learn something new. Its an opportunity to make yourself adapt.. and be agile.
Yes, a root canal at a dentist's office hurts.. but its good for you.
If for some reason the software we choose is the choice of many others in our 'sphere of interest' we have a hit. And if we are an outlier, we end up in one of two scenarios.
1. Either we really have made a good choice and the market around has to 'see' the light and catch on, or
2. We really missed the mark and we have to re-analyze our choice and 'catch-up' with the rest.
Of course, the realization of 'hitting the mark' itself is relative. I'm sure there are some die hard fans of EJB2 who will still say that Hibernate and other ORM's have not got it.
So, what would you say, a person trying to make a call between EJB2 and Hibernate?
One can't say for sure. Hear this argument.
Joe: It does not matter what features EJB2 and Hibernate have, our company policy is not to use open source products. All products have to comply with industry standards.
Mark: But what is 'industry standard'. Isn't it what the 'industry' accepts as a standard.. meaning us, developers/architects. If we say Hibernate is a better choice, so it is a standard.
Joe: Possibly, but our policy writers do not see it like that. If it does not come from the Suns, IBMs, Xs or Ys, its not a standard.
Mark: but..
So, you see, Joe and Mark agree. But still have to disagree due to the criteria used for making a choice.
Then there are re-incarnations.
Remember when you looked at JSF when the world was going with Struts and its sisters. Its too dotnet. Its too component oriented. Its not MVC enough. Its this and its not that. The 'sphere of interest' goes with Struts, Webworks, SpringMVC etc. etc. And then JSF comes with a re-incarnation. It has the blessing of the big names Joe was looking for. It has the blessing of 'us, developers/architects' in open source implementations of JSF that Mark was looking for.
So, what would you say, a person who made the choice of JSF at a time when it did not make the cut.. and stuck with it. Is it because that person 'saw' the promise and potential and had the foresight of its success? Or is it just that the person gambled with it and it paid out?
Its the similar story with EJB in its new EJB3 re-incarnation.
Then there is stuff that changes on you.
How often do you make a choice of software with due diligence. Even the 'sphere of interest' is with you. Things are going fine.. You bet your projects and your raise on it. And then it hits you. The people responsible for your choice software bail out on you. The product is no longer supported.
Recently I was looking for a tag library to use jfreecharts.. Cewolf was the number one choice. Even documented and recommended by jfreechart folks.. But its not supported anymore.
Would you use it in your project? (on a side note, I'm writing my own now.)
Another case in point is Appfuse. I have used it multiple times.. with JSF and SpringMVC. Every time I have to use Appfuse, I've to make a call, which MVC framework to use. And to be frank, I had gotten to like SpringMVC. But it seems appfuse may drop support for springMVC. (http://raibledesigns.com/rd/entry/appfuse_light_converted_to_maven). I hope I read it wrong.
So, what would you say, a person who made a choice of SpringMVC with Appfuse, and then the folks at Appfuse possibly dropping SpringMVC support?
One could say, 'Its a price for getting stuff free.'.
Or one could say, 'Get a life.. what else do you expect. It is the hazard of the landscape.'
Or as Arnold would say, 'Stop whining.'
I say, Is it even something one should feel averse to? Is it something that is not good for you? Isn't change supposed to be good?
Yes, sometimes you change your choice, sometimes the 'sphere of interest' changes its choices and sometimes someone else changes your choice. Its an opportunity.
Its an opportunity to learn something new. Its an opportunity to make yourself adapt.. and be agile.
Yes, a root canal at a dentist's office hurts.. but its good for you.
Tuesday, September 16, 2008
Hibernate and connection pools
I recently spent some time researching and fixing a bug in one of my applications. This is just a summary of its solution, for all those it may help.
Problem:
Mysql has a default time-out on idle connections. The default is 8 hours. If an application uses a connection that has been sitting idle in a connection pool beyond the database time-out period, the application throws an exception.
Solution:
Well, firstly, I thank all those who wrote on blogs/mailing-lists that I had to read to come to the solution, some of which I will quote from here.
To reporduce the problem, I first had to re-create it for testing. I updated mysql's my.ini (windows file, use the corresponding file in Unix/Linux environments) file. I added a wait_timeout value of 120 seconds.
This immediately produced the error after 2 minutes of reusing an idle connection.
I was using commons-dbcp connection pool as a spring managed bean. Since I used appfuse's spring mvc archtype as a quickstart, it came configured with the commons-dbcp. (http://appfuse.org/display/APF/AppFuse+QuickStart).
Gavin King from Hibernate suggests not to use the commons-dbcp as it is faulty. (http://opensource.atlassian.com/projects/hibernate/browse/HB-959) So, taking his advice, my first take was to change the datasource to use a different one.
So, the next question was, if not dbcp, then which one? After a while I stumbled across this connection pool that hibernate supports. I must say, I had not heard of it before, and with an acronym (c3p0) it is not forgetteable. (http://www.hibernate.org/214.html)
Accordingly, I first changed the bean definition from
to the bean definition that uses c3p0:
Note the difference in some of the property names between them. driverClassName/driverClass, url/jdbcUrl, username/user etc. Since these are bean properties, and not resource definition (such as for a web container), the names can be whatever the bean-writers choose them to be.
Refer to this link for more discussion about setting up c3p0 as a bean.
http://forum.springframework.org/showthread.php?t=16309
As you can see, I did not set any other property in the bean definition. The reason requires a little bit of explanation.
In another link (http://forum.springframework.org/showthread.php?t=13078), you can see how the properties can be set.
But, if you set the properties in this manner, c3p0 does not pickup the user and password as a regular 'property', you have to specify them as prop's in the properties 'property'. So, I yanked all from here, but kept the user and password. I moved all other properties to a c3p0.properties file.
One thing that is easily 'missable' is the names of properties. They are named differently in hibernate for the corresponding properties in c3p0. For example, the property of most interest c3p0.idleConnectionTestPeriod is named in hibernate as c3p0.idle_test_period. That makes me wonder, if the property was correctly set in the second springforum link I quoted. (http://forum.springframework.org/showthread.php?t=13078)
So, if you set your c3p0 properties in a c3p0.properties files, you should use c3p0 property names, and in hibernate config files, you should use hibernate co-equivalents.
Another note of caution, even though it is mentioned in passing in the hibernate document (http://www.hibernate.org/214.html), is when you set any of the hibernate cp30 properties, there are 7 properties that hibernate overrides. So you should set all those properties in hibernate, if you do not want hibernate defaults to override cp30 settings or defaults. You will find a reminder in cp30 documentation as well. (http://www.mchange.com/projects/c3p0/index.html#hibernate-specific)
Here is my hibernate.cfg.xml snippet.
As you can see they are same as that in c3p0.properties file. In any case it does not matter, hibernate values will supercede any corresponding value set in c3p0.properties file.
So, what do we have here. We have idle_test_period as 100 seconds, and we had kept mySql's wait-timeout as 120 seconds. This means that the connection pool will discard any connection that has been idle for 100 seconds, and thus will not get used.
The logs show evidence.
So, a long story in short.
Use c3p0 as your connection pool if you are using hibernate. c3p0 can be configured as a resource bean in Spring. Set hibernate properties for c3p0 to override the c3p0 defaults and hibernate's own c3p0 defaults.
Happy programming.
By the way, I like this convention over configuration thing, but care is needed. I may write about it in another post.
Problem:
Mysql has a default time-out on idle connections. The default is 8 hours. If an application uses a connection that has been sitting idle in a connection pool beyond the database time-out period, the application throws an exception.
Solution:
Well, firstly, I thank all those who wrote on blogs/mailing-lists that I had to read to come to the solution, some of which I will quote from here.
To reporduce the problem, I first had to re-create it for testing. I updated mysql's my.ini (windows file, use the corresponding file in Unix/Linux environments) file. I added a wait_timeout value of 120 seconds.
[mysqld]
wait_timeout=120
This immediately produced the error after 2 minutes of reusing an idle connection.
org.hibernate.exception.GenericJDBCException: Cannot release connection
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:29)
..
..
Caused by: java.sql.SQLException: Already closed.
at org.apache.commons.dbcp.PoolableConnection.close(PoolableConnection.java:84)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.close(PoolingDataSource.java:181)
at org.hibernate.connection.DatasourceConnectionProvider.closeConnection(DatasourceConnectionProvider.java:74)
at org.hibernate.jdbc.ConnectionManager.closeConnection(ConnectionManager.java:451)
... 44 more
I was using commons-dbcp connection pool as a spring managed bean. Since I used appfuse's spring mvc archtype as a quickstart, it came configured with the commons-dbcp. (http://appfuse.org/display/APF/AppFuse+QuickStart).
Gavin King from Hibernate suggests not to use the commons-dbcp as it is faulty. (http://opensource.atlassian.com/projects/hibernate/browse/HB-959) So, taking his advice, my first take was to change the datasource to use a different one.
So, the next question was, if not dbcp, then which one? After a while I stumbled across this connection pool that hibernate supports. I must say, I had not heard of it before, and with an acronym (c3p0) it is not forgetteable. (http://www.hibernate.org/214.html)
Accordingly, I first changed the bean definition from
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="100"/>
<property name="maxWait" value="1000"/>
<property name="poolPreparedStatements" value="true"/>
<property name="defaultAutoCommit" value="true"/>
</bean>
to the bean definition that uses c3p0:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
Note the difference in some of the property names between them. driverClassName/driverClass, url/jdbcUrl, username/user etc. Since these are bean properties, and not resource definition (such as for a web container), the names can be whatever the bean-writers choose them to be.
Refer to this link for more discussion about setting up c3p0 as a bean.
http://forum.springframework.org/showthread.php?t=16309
As you can see, I did not set any other property in the bean definition. The reason requires a little bit of explanation.
In another link (http://forum.springframework.org/showthread.php?t=13078), you can see how the properties can be set.
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<!--<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>-->
<property name="properties">
<props>
<prop key="c3p0.acquire_increment">5</prop>
<prop key="c3p0.idle_test_period">100</prop>
<prop key="c3p0.max_size">100</prop>
<prop key="c3p0.max_statements">0</prop>
<prop key="c3p0.min_size">10</prop>
<prop key="user">${db.user}</prop>
<prop key="password">${db.pass}</prop>
</props>
</property>
</bean>
But, if you set the properties in this manner, c3p0 does not pickup the user and password as a regular 'property', you have to specify them as prop's in the properties 'property'. So, I yanked all from here, but kept the user and password. I moved all other properties to a c3p0.properties file.
c3p0.acquireIncrement=1
c3p0.idleConnectionTestPeriod=100
c3p0.initialPoolSize=5
c3p0.maxIdleTime=80
c3p0.maxPoolSize=10
c3p0.maxStatements=0
c3p0.minPoolSize=5
One thing that is easily 'missable' is the names of properties. They are named differently in hibernate for the corresponding properties in c3p0. For example, the property of most interest c3p0.idleConnectionTestPeriod is named in hibernate as c3p0.idle_test_period. That makes me wonder, if the property was correctly set in the second springforum link I quoted. (http://forum.springframework.org/showthread.php?t=13078)
So, if you set your c3p0 properties in a c3p0.properties files, you should use c3p0 property names, and in hibernate config files, you should use hibernate co-equivalents.
Another note of caution, even though it is mentioned in passing in the hibernate document (http://www.hibernate.org/214.html), is when you set any of the hibernate cp30 properties, there are 7 properties that hibernate overrides. So you should set all those properties in hibernate, if you do not want hibernate defaults to override cp30 settings or defaults. You will find a reminder in cp30 documentation as well. (http://www.mchange.com/projects/c3p0/index.html#hibernate-specific)
Here is my hibernate.cfg.xml snippet.
<session-factory>
<property name="connection.pool_size">10</property>
<property name="c3p0.acquire_increment">1</property>
<property name="c3p0.idle_test_period">100</property> <!-- seconds -->
<property name="c3p0.max_size">10</property>
<property name="c3p0.max_statements">0</property>
<property name="c3p0.min_size">5</property>
<property name="c3p0.timeout">80</property> <!-- seconds -->
..
..
As you can see they are same as that in c3p0.properties file. In any case it does not matter, hibernate values will supercede any corresponding value set in c3p0.properties file.
So, what do we have here. We have idle_test_period as 100 seconds, and we had kept mySql's wait-timeout as 120 seconds. This means that the connection pool will discard any connection that has been idle for 100 seconds, and thus will not get used.
The logs show evidence.
DEBUG [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0] C3P0PooledConnectionPool.finerLoggingTestPooledConnection(315) | Testing PooledConnection [com.mchange.v2.c3p0.impl.NewPooledConnection@17fd168] on IDLE CHECK.
DEBUG [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2] C3P0PooledConnectionPool.finerLoggingTestPooledConnection(319) | Test of PooledConnection [com.mchange.v2.c3p0.impl.NewPooledConnection@f5b2da] on IDLE CHECK has
SUCCEEDED.
DEBUG [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1] C3P0PooledConnectionPool.destroyResource(468) | Preparing to destroy PooledConnection: com.mchange.v2.c3p0.impl.NewPooledConnection@70ccb
DEBUG [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1] NewPooledConnection.close(566) | com.mchange.v2.c3p0.impl.NewPooledConnection@70ccb closed by a client.
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:566)
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:234)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:470)
at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:964)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
So, a long story in short.
Use c3p0 as your connection pool if you are using hibernate. c3p0 can be configured as a resource bean in Spring. Set hibernate properties for c3p0 to override the c3p0 defaults and hibernate's own c3p0 defaults.
Happy programming.
By the way, I like this convention over configuration thing, but care is needed. I may write about it in another post.
Sunday, August 10, 2008
Unit Testing in Software Development and Junit
Late adoption of certain practices mean that you talk about a technology or a process as something that deserves a second look, whereas, the industry around you considers it a 'norm'. In my case such is the case with incorporating unit testing into development process.
Sometimes one gets too cosy with their SystemOutPrints or ResponeWrites for testing software, or use log4j (well, i've another story for log4j's late adoption) for verifying tests, that one wonders, dosent't 'log' in log4j stand for some kind of logging, and not testing.
Lets see, when we talk about testing, we talk about a piece of functionality, encapsulated in a single method, or a sequence of method calls behaving as desired. So, when we test, we know the outcome, and we want to verify that the outcome of an actual run is as it is expected. A SystemOutPrint or a log command, may serve this purpose but there has to be a 'human' sitting on a terminal reading the output to verify that. Lets say in a system with 10 classes with 10 methods each, there are 100 calls to verify. How can that be automated?
Before going into unit testing with junit, let me quantify what's wrong with using SystemOutPrint (SOP going forward) or log4j for testing. With objections out of the way, we can discuss how junit addresses such instances.
1. clutter
Putting SOP's clutter your code with statements one has to remove after the code is 'tested'. In many instances, a developer either does not remove them or keeps them commented, for 'just in case I need to test it again'. So, your console output from application is cluttered with unwanted output and your code is cluttered with unwanted lines of code. Not to mention, when a developer wants to test again, he/she has to either type in SOP's again or uncomment the existing SOP's..
2. misuse
We all agree that log4j is for logging purposes. And SOP is more generic in use, and cannot be just tied to logging. SOP's have a place and logging has a place. But their place is not for testing. They can be utilized alongside testing, for logging and printing test results to console, but they are not test tools. Testing should be executed and the system should tell you if all the tests succeeded, irrespective of a person parsing 3000 lines in a log file trying to figure out the test results.
3. non-repeatability
When a developer tests using log statements, it is tested when it is coded. Seems like a redundant statement. But read on with me. Lets say a piece of functionality is tested and deployed using log statements. Another developer comes along and modifies your code to add more functionality. He/She tests his/her work using logs and is satisfied with his/her results.. You can't disagree with me for the possibility of a bug being introduced in your original piece of work. If such a bug gets introduced, who tests for that? and when? So, tests should be repeatable, so if any change occurs in your code or else where, it does not affect your original coded behaviour.
4. undocumented
Since using SOP's and logs are left at the needs/desires of an individual developer, there is no need or lack thereof to use or not use them. Accordingly, a developer new to the team or team that inherits an application has no clue what is tested and what is not. Also, all the SOP's that made sense to one developer or a team is 'noise' to another developer or team.
5. non-intutive
If a system is tested using SOP's and logs how can one answer this simple question : How do I test this thing? You can't.. A person doing the testing has to have intimate knowledge of the code and has to know what to look for in the logs to test such systems. Completely impractical. Wouldn't it be easy to just answer 'hey run the 'test' target in ant' or 'run maven and don't skip the test' or something like that.. And your build tool runs all the tests and gives you the results..
I think these 5 points convey my point. So, how can these issues be addressed. Let me explain using a junit example.
Lets begin with a class that we want to test. Please keep in mind, that the example will be really simple, so as to convey the point. You can read more documentation at junits website.(*1)
The Class Doodle has a method add which adds two numbers. We need to make sure it adds correctly. (One might say, a+b should add.. what's there to test? yes, I know.. this is just an example.. pretend for a moment that the implementation is pretty complex and needs testing..)
How do we go about testing this without using the dreaded SOP's and log statements.
We write a test class. Here is how it looks.
We have a TestDoodle class, with three methods.
setUp() - Its annotated with @Before, which tells junit to run this method before every test method
testDoodleAdd() - Its annotated with @Test, which tells junit to run this method when this class is invoked for testing
cleanUp() - Its annotated with @After, which tells junit to run this method after each test method.
In testDoodleAdd(), we invoke our add method by sending, 2 and 2 for test values, and we get the results back in result variable, which should be 4.
As mentioned earlier, I need to know what the result is before running the test, to make sure that the test is successful. That is happening in the junit method assertEquals(expectedValue, actualValue). If this method returns 'true' then the test is successful, and if not the test is a failure.
How do we run it. It can run on a command line, but I'll give an 'ant' snippet.
So, the test can be run by running 'ant test' on command line. (note, this snippet depends on 'compile' task, and 'tests.path' value, which are not included. but I think the intent is clear)
Now, let us see how it stands for the above-mentioned objections to using SOP's and logs.
1. no clutter
As it is evident, Doodle.java is clutter free.
2. no misuse
There is no unnecessary use of SOP's and log statements for other than their intended purposes. (I know, there are none in the example, but I could log the add operation for logging purposes.. not for testing..)
3. repeatable
This test can be run any number of times, without any side-effect. Each time the class is modified, this test, in addition to any new test can be run. If any of the results change due to code changes, it will manifest itself next time the test runs.
4. documented
There is a TestDoodle class, and its purpose is to test the Doolde class. And, this class along with its annotations, and comments (if any) is clearly a clean way of understanding which tests are being performed and what the expected results are.
5. intutive
Ok, I know a person has to know junit is being used, and in my case 'ant' is used to run tests.. But most of that is 'staple' for java development nowadays. It is very unlikely any experienced java developer will not know what is going on after looking at the ant's build.xml file and corresponding test classes. So, it is very intutive by convention.
In summary, incorporating unit tests in a development process is necessary for many other reasons other than the general concept of testing. And if junit makes it easy, why not use it.
(*1) http://www.junit.org/
Sometimes one gets too cosy with their SystemOutPrints or ResponeWrites for testing software, or use log4j (well, i've another story for log4j's late adoption) for verifying tests, that one wonders, dosent't 'log' in log4j stand for some kind of logging, and not testing.
Lets see, when we talk about testing, we talk about a piece of functionality, encapsulated in a single method, or a sequence of method calls behaving as desired. So, when we test, we know the outcome, and we want to verify that the outcome of an actual run is as it is expected. A SystemOutPrint or a log command, may serve this purpose but there has to be a 'human' sitting on a terminal reading the output to verify that. Lets say in a system with 10 classes with 10 methods each, there are 100 calls to verify. How can that be automated?
Before going into unit testing with junit, let me quantify what's wrong with using SystemOutPrint (SOP going forward) or log4j for testing. With objections out of the way, we can discuss how junit addresses such instances.
1. clutter
Putting SOP's clutter your code with statements one has to remove after the code is 'tested'. In many instances, a developer either does not remove them or keeps them commented, for 'just in case I need to test it again'. So, your console output from application is cluttered with unwanted output and your code is cluttered with unwanted lines of code. Not to mention, when a developer wants to test again, he/she has to either type in SOP's again or uncomment the existing SOP's..
2. misuse
We all agree that log4j is for logging purposes. And SOP is more generic in use, and cannot be just tied to logging. SOP's have a place and logging has a place. But their place is not for testing. They can be utilized alongside testing, for logging and printing test results to console, but they are not test tools. Testing should be executed and the system should tell you if all the tests succeeded, irrespective of a person parsing 3000 lines in a log file trying to figure out the test results.
3. non-repeatability
When a developer tests using log statements, it is tested when it is coded. Seems like a redundant statement. But read on with me. Lets say a piece of functionality is tested and deployed using log statements. Another developer comes along and modifies your code to add more functionality. He/She tests his/her work using logs and is satisfied with his/her results.. You can't disagree with me for the possibility of a bug being introduced in your original piece of work. If such a bug gets introduced, who tests for that? and when? So, tests should be repeatable, so if any change occurs in your code or else where, it does not affect your original coded behaviour.
4. undocumented
Since using SOP's and logs are left at the needs/desires of an individual developer, there is no need or lack thereof to use or not use them. Accordingly, a developer new to the team or team that inherits an application has no clue what is tested and what is not. Also, all the SOP's that made sense to one developer or a team is 'noise' to another developer or team.
5. non-intutive
If a system is tested using SOP's and logs how can one answer this simple question : How do I test this thing? You can't.. A person doing the testing has to have intimate knowledge of the code and has to know what to look for in the logs to test such systems. Completely impractical. Wouldn't it be easy to just answer 'hey run the 'test' target in ant' or 'run maven and don't skip the test' or something like that.. And your build tool runs all the tests and gives you the results..
I think these 5 points convey my point. So, how can these issues be addressed. Let me explain using a junit example.
Lets begin with a class that we want to test. Please keep in mind, that the example will be really simple, so as to convey the point. You can read more documentation at junits website.(*1)
public class Doodle {
public int add(int a, int b) {
return a+b;
}
}
The Class Doodle has a method add which adds two numbers. We need to make sure it adds correctly. (One might say, a+b should add.. what's there to test? yes, I know.. this is just an example.. pretend for a moment that the implementation is pretty complex and needs testing..)
How do we go about testing this without using the dreaded SOP's and log statements.
We write a test class. Here is how it looks.
import org.junit.Test;
import static org.junit.Assert.*;
public class TestDoodle {
private Doodle doodle;
@Before
public void setUp() {
doodle = new Doodle();
}
@Test
public void testDoodleAdd() throws Exception {
int result = d.add(2, 2);
assertEquals(4, result);
}
@After
public void cleanUp() {
doodle = null;
}
}
We have a TestDoodle class, with three methods.
setUp() - Its annotated with @Before, which tells junit to run this method before every test method
testDoodleAdd() - Its annotated with @Test, which tells junit to run this method when this class is invoked for testing
cleanUp() - Its annotated with @After, which tells junit to run this method after each test method.
In testDoodleAdd(), we invoke our add method by sending, 2 and 2 for test values, and we get the results back in result variable, which should be 4.
As mentioned earlier, I need to know what the result is before running the test, to make sure that the test is successful. That is happening in the junit method assertEquals(expectedValue, actualValue). If this method returns 'true' then the test is successful, and if not the test is a failure.
How do we run it. It can run on a command line, but I'll give an 'ant' snippet.
<target name="test" depends="compile">
<junit fork="yes" haltonfailure="yes">
<test name="TestDoodle" />
<formatter type="plain" usefile="false" />
<classpath refid="tests.path" />
</junit>
</target>
So, the test can be run by running 'ant test' on command line. (note, this snippet depends on 'compile' task, and 'tests.path' value, which are not included. but I think the intent is clear)
Now, let us see how it stands for the above-mentioned objections to using SOP's and logs.
1. no clutter
As it is evident, Doodle.java is clutter free.
2. no misuse
There is no unnecessary use of SOP's and log statements for other than their intended purposes. (I know, there are none in the example, but I could log the add operation for logging purposes.. not for testing..)
3. repeatable
This test can be run any number of times, without any side-effect. Each time the class is modified, this test, in addition to any new test can be run. If any of the results change due to code changes, it will manifest itself next time the test runs.
4. documented
There is a TestDoodle class, and its purpose is to test the Doolde class. And, this class along with its annotations, and comments (if any) is clearly a clean way of understanding which tests are being performed and what the expected results are.
5. intutive
Ok, I know a person has to know junit is being used, and in my case 'ant' is used to run tests.. But most of that is 'staple' for java development nowadays. It is very unlikely any experienced java developer will not know what is going on after looking at the ant's build.xml file and corresponding test classes. So, it is very intutive by convention.
In summary, incorporating unit tests in a development process is necessary for many other reasons other than the general concept of testing. And if junit makes it easy, why not use it.
(*1) http://www.junit.org/
Monday, July 28, 2008
Why Magnolia
I chose Magnolia (www.magnolia.info) again for my third Content Management Solution. And, I still like it. Though Magnolia is capable of much more, following are the reasons I prefer it.
1. administrator managed public viewing site
Magnolia comes with role based security. It is extendable as its security is based on JAAS (Java Authentication and Authorization Service). Branches of the site can be secured based on role and roles can be configured with read/write access rightes. Roles and permissions can easily be managed and modified.
2. wsywyg editing
Magnolia adds its own javascript based controls for editing the pages. The controls apprear in edit mode and are hidden in preview mode. They do not exist in published pages. I would not call it 100% wsywyg editing, as Magnolia does not allow you 'inline' editing of the pages, but it allows you form based editing in popup forms. It still qualifies for wyswyg as the preview mode of the page is exactly how a published page would look like.
3. complete control over look & feel of the site
Since you as a developer create templates for the page layouts, and templates for the paragraphs, you have 100% control over how the site looks and behaves. I think this is the 'most' important asset of Magnolia. I've seen many other CMS solutions that allow you to create a page and paragraph layout with web based tools, but with any web based tool, there come certain limitations. With Magnolia, since a developer codes the templates, there is no such limitation. (Yes, the newer versions of Magnolia have some online template builder tool (Sitedesigner), but I have not used it, so I cannot comment on it. Also, it is part of 'enterprise' build)
4. database independent implementation
Magnolia stores its data using jackrabbit Content Repository. And, since you as a developer create dialogs (to capture data) and paragraphs (to display data) and you use magnolia's tag libraries to access data for publishing, there is not much jackrabbit know-how necessary to create a magnolia solution. But the fact that you do not have to configure a database as part of implementation is a plus. One less thing to worry about while deploying your magnolia solution.
5. a simple workflow, create - preview - publish
The workflow is simple. A content manager creates a page, previews it and if satisfied publishes the page. I think, for a vast majority of CMS solutions this simple workflow works and suffices. As a developer you can stack multiple installations of magnolia to create more elaborate workflows, like create - preview - review - confirm - publish, but I have not implemented such a system. I have read it is possible, but I'm not sure what baggage it comes with. I would still recommened a good understanding of Magnolia and its capabilities in expanding the workflow before you 'reject' it for any other tool, if a more complex workflow is required.
What else?
Now, is there something that I would like to see in Magnolia that it does not provide? Of course yes. No tool is perfect and no tool gives you 100% of what you want. The reason a tool is a 'good' tool depends on how easily it 'allows' you to reach your 100% beyond the 'X'% it gives you.
So, I would like that Magnolia provide a good 'eclipse' project, so that developing templates is much easier. (No, I'm not saying an 'eclipse' project to work on magnolia code itself.. I'm talking about an 'eclipse' project for creating and managing templates and other code artifacts (such as docroot artifacts))
I would also like that it is more seamless to adding custom code, like servlets and jsp's. Yes, it does allow, but it should be more seamless. And good integration of jsp's that read managed header/footer from magnolia templates.
I would also like more pre-built modules, like a blog or a message board. Though I'm not sure if that really adds value to Magnolia. But it sure will make it more competitive, as its competitors 'boast' of such 'out of box' features.
So, in short, Magnolia is a good tool to create highly customized and managed public domain websites.
1. administrator managed public viewing site
Magnolia comes with role based security. It is extendable as its security is based on JAAS (Java Authentication and Authorization Service). Branches of the site can be secured based on role and roles can be configured with read/write access rightes. Roles and permissions can easily be managed and modified.
2. wsywyg editing
Magnolia adds its own javascript based controls for editing the pages. The controls apprear in edit mode and are hidden in preview mode. They do not exist in published pages. I would not call it 100% wsywyg editing, as Magnolia does not allow you 'inline' editing of the pages, but it allows you form based editing in popup forms. It still qualifies for wyswyg as the preview mode of the page is exactly how a published page would look like.
3. complete control over look & feel of the site
Since you as a developer create templates for the page layouts, and templates for the paragraphs, you have 100% control over how the site looks and behaves. I think this is the 'most' important asset of Magnolia. I've seen many other CMS solutions that allow you to create a page and paragraph layout with web based tools, but with any web based tool, there come certain limitations. With Magnolia, since a developer codes the templates, there is no such limitation. (Yes, the newer versions of Magnolia have some online template builder tool (Sitedesigner), but I have not used it, so I cannot comment on it. Also, it is part of 'enterprise' build)
4. database independent implementation
Magnolia stores its data using jackrabbit Content Repository. And, since you as a developer create dialogs (to capture data) and paragraphs (to display data) and you use magnolia's tag libraries to access data for publishing, there is not much jackrabbit know-how necessary to create a magnolia solution. But the fact that you do not have to configure a database as part of implementation is a plus. One less thing to worry about while deploying your magnolia solution.
5. a simple workflow, create - preview - publish
The workflow is simple. A content manager creates a page, previews it and if satisfied publishes the page. I think, for a vast majority of CMS solutions this simple workflow works and suffices. As a developer you can stack multiple installations of magnolia to create more elaborate workflows, like create - preview - review - confirm - publish, but I have not implemented such a system. I have read it is possible, but I'm not sure what baggage it comes with. I would still recommened a good understanding of Magnolia and its capabilities in expanding the workflow before you 'reject' it for any other tool, if a more complex workflow is required.
What else?
Now, is there something that I would like to see in Magnolia that it does not provide? Of course yes. No tool is perfect and no tool gives you 100% of what you want. The reason a tool is a 'good' tool depends on how easily it 'allows' you to reach your 100% beyond the 'X'% it gives you.
So, I would like that Magnolia provide a good 'eclipse' project, so that developing templates is much easier. (No, I'm not saying an 'eclipse' project to work on magnolia code itself.. I'm talking about an 'eclipse' project for creating and managing templates and other code artifacts (such as docroot artifacts))
I would also like that it is more seamless to adding custom code, like servlets and jsp's. Yes, it does allow, but it should be more seamless. And good integration of jsp's that read managed header/footer from magnolia templates.
I would also like more pre-built modules, like a blog or a message board. Though I'm not sure if that really adds value to Magnolia. But it sure will make it more competitive, as its competitors 'boast' of such 'out of box' features.
So, in short, Magnolia is a good tool to create highly customized and managed public domain websites.
Labels:
CMS,
Content Repository,
JackRabbit,
Magnolia,
Templating,
Workflow
Monday, June 9, 2008
ORM Models : Hibernate with Annotations and Cayenne
Before I used Hibernate (*1), I played around with Cayenne (*2). I liked its Visual Modeler. It allows you to create models, and map them to database fields. It also generates Java Code and sql scripts. All packaged up. I liked it. Untill I worked with Hibernate.
I must admit, I tend to not like things that get too much hype, and sometimes the hype is much deserved. So, in such cases I kind of 'miss the boat'. Hibernate falls in that category.. But, in the end, having a better grasp at competing technologies never hurts.. Let me explain, and I will limit the discussion to few items, which I feel are a 'make or break', at least for me, and please take it for what its worth.
Lets take Cayenne first. Lets take a look at its generated model. Or should I say 'models', as it creates two files.
public class Blog extends _Blog {
...
}
pretty small.. Wait till you see the _Blog
public class _Blog extends org.apache.cayenne.CayenneDataObject {
public static final String BLOG_DESCRIPTION_PROPERTY = "blogDescription";
public static final String BLOG_TITLE_PROPERTY = "blogTitle";
public static final String DATE_CREATED_PROPERTY = "dateCreated";
public static final String DATE_MODIFIED_PROPERTY = "dateModified";
public static final String BLOG_ID_PK_COLUMN = "BLOG_ID";
public void setBlogDescription(String blogDescription) {
writeProperty("blogDescription", blogDescription);
}
public String getBlogDescription() {
return (String)readProperty("blogDescription");
}
public void setBlogTitle(String blogTitle) {
writeProperty("blogTitle", blogTitle);
}
public String getBlogTitle() {
return (String)readProperty("blogTitle");
}
public void setDateCreated(java.util.Date dateCreated) {
writeProperty("dateCreated", dateCreated);
}
public java.util.Date getDateCreated() {
return (java.util.Date)readProperty("dateCreated");
}
public void setDateModified(java.util.Date dateModified) {
writeProperty("dateModified", dateModified);
}
public java.util.Date getDateModified() {
return (java.util.Date)readProperty("dateModified");
}
}
So, what is the issue..
Firstly, Cayenne creates a model, which is for you to extend and customize, which extends another class (_Blog.java).
The _ in _Blog.java means, 'do not touch'. Cayenne reserves the full right to over-write it. This is a problem, in at least one of these ways:
Thirdly, Can you find getBlogId() or setBlogId(...) in the _Blog.java ? Neither do I. Cayenne documentation says, "Normally it is not advisable to map primary and foreign key columns (PK and FK) as Java class properties (ObjAttributes)." (*3) But they do not explain the wisdom in it. So, you have to write an elaborate custom method to get the id from the model itself (see the referenced link). But to set an id, that is still a no-no. Of course, you may agree with the methodology of not allowing access to Id from model, but I tend to like ot have it.
So, to keep it short, I'll just limit my discussion to these three points. And no, I'm not skipping Hibernate. Here I'll just relate Hibernate with these three points.
Lets see a Hibernate Model class.
@Entity
@Table(name="CLIENT")
public class Client implements Serializable {
@Id
@Column(name="id", nullable=false)
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(name="name", nullable=false, length=255, unique=true)
private String name;
@Column(name="account_manager",nullable=true, length=255)
private String accountManager;
@Column(name="account_owner",nullable=true, length=255)
private String accountOwner;
public Client() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAccountManager() {
return accountManager;
}
public void setAccountManager(String accountManager) {
this.accountManager = accountManager;
}
public String getAccountOwner() {
return accountOwner;
}
public void setAccountOwner(String accountOwner) {
this.accountOwner = accountOwner;
}
}
This example of the Model class uses Annotations, though all of this can be accomplished using an XML file. But I prefer Annotations, and using Annotations has its benefits, which I won't mention here, as I'm discussing Model classes.
So, First issue : I generate the Class. Even if there exists tools that generate the Model classes, there is nothing stopping me from writing or modifying it.
Secondly, the Client.java extends Serializable, which qualifies it for a POJO. I know, I know, this class has javax.persistence.Entity, javax.persistence.Id and similar annotations, but, there is nothing that prevents me from instantiating a Client Class, and setting all the properties and have it then persist..
Thirdly, getId() and setId(...). Ahh. Dosen't that make you breathe easier.
In any case, I would use Hibernate just for these reasons, even though there are other equally compelling reasons to use it. Like, javax.persistence/EJB3 supported annnotations, the Hibernate model above could be used with JPA without changing a single line of code. (Of course, a Hibernate DAO will differ from JPA DAO), extensive Maven support for Hibernate and other 'nice to haves'.
(*1) http://www.hibernate.org/
(*2) http://cayenne.apache.org/
(*3) http://cayenne.apache.org/doc20/accessing-pk-and-fk-values.html
I must admit, I tend to not like things that get too much hype, and sometimes the hype is much deserved. So, in such cases I kind of 'miss the boat'. Hibernate falls in that category.. But, in the end, having a better grasp at competing technologies never hurts.. Let me explain, and I will limit the discussion to few items, which I feel are a 'make or break', at least for me, and please take it for what its worth.
Lets take Cayenne first. Lets take a look at its generated model. Or should I say 'models', as it creates two files.
public class Blog extends _Blog {
...
}
pretty small.. Wait till you see the _Blog
public class _Blog extends org.apache.cayenne.CayenneDataObject {
public static final String BLOG_DESCRIPTION_PROPERTY = "blogDescription";
public static final String BLOG_TITLE_PROPERTY = "blogTitle";
public static final String DATE_CREATED_PROPERTY = "dateCreated";
public static final String DATE_MODIFIED_PROPERTY = "dateModified";
public static final String BLOG_ID_PK_COLUMN = "BLOG_ID";
public void setBlogDescription(String blogDescription) {
writeProperty("blogDescription", blogDescription);
}
public String getBlogDescription() {
return (String)readProperty("blogDescription");
}
public void setBlogTitle(String blogTitle) {
writeProperty("blogTitle", blogTitle);
}
public String getBlogTitle() {
return (String)readProperty("blogTitle");
}
public void setDateCreated(java.util.Date dateCreated) {
writeProperty("dateCreated", dateCreated);
}
public java.util.Date getDateCreated() {
return (java.util.Date)readProperty("dateCreated");
}
public void setDateModified(java.util.Date dateModified) {
writeProperty("dateModified", dateModified);
}
public java.util.Date getDateModified() {
return (java.util.Date)readProperty("dateModified");
}
}
So, what is the issue..
Firstly, Cayenne creates a model, which is for you to extend and customize, which extends another class (_Blog.java).
The _ in _Blog.java means, 'do not touch'. Cayenne reserves the full right to over-write it. This is a problem, in at least one of these ways:
- If I have to modify the model, I have to use the 'Modeler' and then 're-generate' the code.
- I am tied to Cayenne for the model class, and the proof? _Blog.java itself extends org.apache.cayenne.CayenneDataObject
Thirdly, Can you find getBlogId() or setBlogId(...) in the _Blog.java ? Neither do I. Cayenne documentation says, "Normally it is not advisable to map primary and foreign key columns (PK and FK) as Java class properties (ObjAttributes)." (*3) But they do not explain the wisdom in it. So, you have to write an elaborate custom method to get the id from the model itself (see the referenced link). But to set an id, that is still a no-no. Of course, you may agree with the methodology of not allowing access to Id from model, but I tend to like ot have it.
So, to keep it short, I'll just limit my discussion to these three points. And no, I'm not skipping Hibernate. Here I'll just relate Hibernate with these three points.
Lets see a Hibernate Model class.
@Entity
@Table(name="CLIENT")
public class Client implements Serializable {
@Id
@Column(name="id", nullable=false)
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(name="name", nullable=false, length=255, unique=true)
private String name;
@Column(name="account_manager",nullable=true, length=255)
private String accountManager;
@Column(name="account_owner",nullable=true, length=255)
private String accountOwner;
public Client() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAccountManager() {
return accountManager;
}
public void setAccountManager(String accountManager) {
this.accountManager = accountManager;
}
public String getAccountOwner() {
return accountOwner;
}
public void setAccountOwner(String accountOwner) {
this.accountOwner = accountOwner;
}
}
This example of the Model class uses Annotations, though all of this can be accomplished using an XML file. But I prefer Annotations, and using Annotations has its benefits, which I won't mention here, as I'm discussing Model classes.
So, First issue : I generate the Class. Even if there exists tools that generate the Model classes, there is nothing stopping me from writing or modifying it.
Secondly, the Client.java extends Serializable, which qualifies it for a POJO. I know, I know, this class has javax.persistence.Entity, javax.persistence.Id and similar annotations, but, there is nothing that prevents me from instantiating a Client Class, and setting all the properties and have it then persist..
Thirdly, getId() and setId(...). Ahh. Dosen't that make you breathe easier.
In any case, I would use Hibernate just for these reasons, even though there are other equally compelling reasons to use it. Like, javax.persistence/EJB3 supported annnotations, the Hibernate model above could be used with JPA without changing a single line of code. (Of course, a Hibernate DAO will differ from JPA DAO), extensive Maven support for Hibernate and other 'nice to haves'.
(*1) http://www.hibernate.org/
(*2) http://cayenne.apache.org/
(*3) http://cayenne.apache.org/doc20/accessing-pk-and-fk-values.html
Subscribe to:
Posts (Atom)
