Mutant Mumblings
IBM DeveloperWorks Article
It has taken almost six months, but the article Jim, Ryan and myself wrote for IBM DeveloperWorks has just been published!
Go check it out!
Patterns of persistence, Part 1: Strategies and best practices for modern ORM toolsPatterns of persistence, Part 2: Increase code reuse and enhance performance
Posted at 09:18AM Apr 22, 2008 by Travis Klotz in Hibernate | Comments[0]
How not to delete
I was talking to my buddy Eric the other day and he told me about a business logic problem he had been having and the very elegant solution he came up with using Hibernate. The problem was so common and the solution so simple (and now that I know it, so obvious) that I just had to write it up.
The problem:
Often times in business software, the Delete feature for many record types shouldn't actually delete the record from the database. Instead you really just want to deactivate the record so it doesn't show up on anybody's screen. This is usually implemented by adding an active column to the records table and then all queries against the table will have a predicate stating that only records with "active=1" should be retrieved. When the application needs to "delete" a record, it will simply set the active flag to 0.
My typical solution:
Typically this delete logic would be implemented by either overriding the standard DAO's delete method, or as an entirely different set of operations at the service level. Either way the application will hold off on calling Hibernates delete function and instead just update the "active" flag on the object. The problem with this is that you immediately lose all the great features that hibernate auto-magically provides when deleting objects. Things like cascading deletes now all need to be managed by hand. And you don't lose these features on just the few objects that require this kind of record keeping. What if your "active" record is the child of another object? In that case we can no longer cascades from the parent objects because we don't want Hibernate to accidentally delete any of our records.
The better solution:
The major problem with the above solution is that hibernate doesn't know what we are trying to do, so it either does something unwanted, or it is configured to do nothing at all. So how do we let Hibernate know what we really want? Well it turns out that all we really need Hibernate to do is exactly what it does by default, EXCEPT in place of executing a delete statement for each record, we want it to issue an update statement.
DELETE FROM employee WHERE employee_id = ?
Becomes
UPDATE employee SET active=0 WHERE employee_id = ?
Thankfully, Hibernate provides the capability to do exactly this. In fact Hibernate will allow us to rewrite any query associated with the basic CRUD operations of an entity. The best part is that its absolutely trivial to implement.
@Entity @SQLDelete(sql="UPDATE employee SET active=0 WHERE employee_id = ?") public class Employee
That's all there is to it. Now any time Hibernate tries to delete an Employee, it will mark it as inactive instead. It doesn't matter if the delete is explicit or from a cascade, and any child objects of Employee with delete cascading enabled will auto-magically be processed and either deleted, or if they have similar @SQLDelete annotations, deactivated as well. This allows us to use all of our standard DAO classes and configuration and treat these objects just like any others.
Thanks Eric!
Posted at 01:01PM Apr 10, 2008 by Travis Klotz in Hibernate | Comments[2]
Integrating Acegi with a Windows 2003 Small Business Server Active Directory Using LDAP
After using Acegi for the last year or so, i have needed to integrate a half dozen applications with Microsoft Active Directory. Doing this the first time was fairly painful because I couldn't find any good examples of what the configuration should really look like, just lots of small pieces. In hopes of saving a few people the many hours I spent working out the details, here is a solution
Assumptions:
- This example is going to work with Win2K3 Small Business Server, the built in wizards actually put the users in a strange place that took a while to figure out, and I never found any good documentations for it.
- My ADS domain is going to be called "SourceAllies.local"
- I'm not going to use TLS for communications between the app server and ADS. In the real world you should always use TLS to protect your credentials, but it adds a whole set of configuration steps that I'm going to call outside the scope of this entry.
Step 1: Define the Initial Directory Context Factory
We need to create a context factory that will provide Acegi with the location of our AD server, the username and password for the account we will use for connecting to the server and any extra information acegi might need to traverse the directory tree.
<bean id="initialDirContextFactory"
class="org.acegisecurity.ldap.DefaultInitialDirContextFactory">
<constructor-arg value="ldap://SourceAllies.local:389/DC=SourceAllies,DC=local" /> (1)
<property name="managerDn" value="CN=acegi,CN=Users,DC=SourceAllies,DC=local" /> (2)
<property name="managerPassword" value="12345" /> (3)
<property name="extraEnvVars"> (4)
<map>
<entry key="java.naming.referral" value="follow" />
</map>
</property>
</bean>
- The constructor-arg tells the context factory what the url to our ADS is including the base DN we want to use. One of the nice things with ADS is that if everything in windows is set up correctly, the name of our ADS domain will also be the name of the ADS server and base DN we want to seach inside the LDAP tree. So in the case "SourceAllies.local" is the server name, and our base DN is "DC=SourceAllies,DC=local". Everything in the domain is stored under that DN.
- By default, ADS does not allow anonymous searches so we must provide a set of credentials. Note that this user was NOT created using the small business server tools so it resides in the normal "CN=Users" section of the LDAP tree.
- This is the password for the "acegi" user in ADS
- ADS requires referrals be set to "follow" in order for queries to work properly.
Step 2: Define the User Search
Now we need to tell Acegi how it should search the LDAP tree to find our users. We do this by creating a search filter that will tell Acegi which directory context to look in, how to make the provided username to the LDAP tree and where in the context to start our search.
<bean id="userSearch"
class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value="" /> (1)
<constructor-arg index="1" value="(sAMAccountName={0})" /> (2)
<constructor-arg index="2" ref="initialDirContextFactory" /> (3)
<property name="searchSubtree" value="true" /> (4)
</bean>
- We can provide a "serachBase" or offset from the initial directory context that we want to search, but in this case I want to look in the entire tree.
- This is the filter itself. This will tell Acegi to find any entry with an sAMAccountName that equal our provided username. sAMAccountName is the name of the LDAP attribute that ADS uses to store the windows account name.
- We provide the search filter with our directory context factory that we configured in a previous step.
- We want to search the entire tree, not just the top level, so we want the query to search the subtrees as well.
Step 3: Define the Authorities Populator
Once the user is authenticated, we need to find out what roles it has. Acegi provides an authorites populator interface with an implementation that will let you query groups from the LDAP server. You could also make your own impl that would look for roles in a database table or any other datastore. But in this case we want to grab all their windows groups.
<bean id="authoritiesPopulator"
class="org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="initialDirContextFactory" /> (1)
<constructor-arg value="OU=Security Groups,OU=MyBusiness" /> (2)
<property name="groupRoleAttribute" value="CN" /> (3)
<property name="rolePrefix" value="ROLE_" /> (4)
<property name="searchSubtree" value="true" />
</bean>
- Provide our context factory defined in a previous Step
- We are going to search for groups in this part of the directory. This is where Small Business Server's wizards will define groups.
- We are going to use the "CN" attribute of the group to define the roles name.
- To make this query match the defaults on the RoleVoter in our standard Acegi configuration, we will prefix the name of all roles with "ROLE_"
Step 4: Define the LDAP Authenticator
We need to tell Acegi how it should go about verifying the credentials our users provide. Acegi provides several different implementations that can compare hashed values of passwords or compare other values, but the option we are forced to choose is the BindAuthenticator. This authenticator will try to attach to the ADS using the credentials provided, we have to use this method because ADS will not let external programs view even the hashed or encrypted values in the password fields. However the bind authenticator is very easy to set up, it just needs to know how to find out directory context, and be able to find the correct user entry in the tree.
<bean id="ldapAuthenticator"
class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
<constructor-arg ref="initialDirContextFactory" />
<property name="userSearch" ref="userSearch" />
</bean>
Step 5: Tie it all together and define the LDAP Provider
This is our primary LDAP authentication provider that will be integrated into the rest of the acegi setup. This piece just needs to know how to authenticate a user and how to retrieve the roles for that user.
<bean id="ldapAuthProvider"
class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider">
<constructor-arg ref="ldapAuthenticator" />
<constructor-arg ref="authoritiesPopulator" />
</bean>
Final Step: Add the LDAP Provider to the Provider Manager
Most of the Acegi configuration doesn't care about where or how credentials are verified, it really only matters from the ProviderManager on down.
<bean id="providerManager"
class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="ldapAuthProvider" />
</list>
</property>
</bean>
Posted at 01:11PM Oct 09, 2007 by Travis Klotz in Acegi | Comments[4]
Using Acegi with JSF and Facelets
A few months ago I was having a hard time getting Facelets and Acegi working properly together. In the past I had gotten JSF+JSP to work with acegi following a great article over at the MyFaces Wiki, but replacing JSP with Facelets causes a few new issues that must be resolved.
All the screen setup should be exactly the same as the MyFaces wiki suggests, but the navigation rules is going to need a little work:
In faces-config.xml
<navigation-rule>
<from-view-id>/login.xhtml</from-view-id>
<navigation-case>
<from-outcome>login</from-outcome>
<to-view-id>/j_acegi_security_check.jsp</to-view-id>
</navigation-case>
</navigation-rule>
Notice that the from-view-id has been changed to a xhtml extension, but the to-view-id remains jsp. At first I was trying to get the rule to work with the to-view-id set with a .xhtml extension, but this has one major issue:
- When processing navigation rules to a new facelet, there is no servlet forward like there would be with JSPs(facelets are not servlets). So there is no chance for the Acegi filter chain to fire.
However, just switching to the .jsp extension is not enough, by default faclets wants to believe that all navigation rules will only refer to facelets. So by default, even with the above rule, facelets tries to parse a file called "j_acegi_security_check.xhtml". But this is easy to solve once your know the problem.
In web.xml: <context-param> <param-name>facelets.VIEW_MAPPINGS</param-name> <param-value>*.xhtml</param-value> </context-param>
This tells facelets that only navigation rules with to-view-ids that end in ".xhtml" should be treated as facelets and everything else should be deferred back to the default view handler. This allows "/j_acegi_security_check.jsp" to be seen as something outside of facelets and causes a servlet forward to occur.
But there is still one catch. Even though your navigation rule tells JSF to forward onto "/j_acegi_security_check.jsp", the forward request actually says "/j_acegi_security_check.xhtml". So you will need to update your Acegi spring configuration to tell the AuthenticationProcessingFilter to look somewhere else instead:
In applicationContext-security.xml: <property name="filterProcessesUrl" value="/j_acegi_security_check.xhtml" />
The inconsistency between the navigation rule and the filterProcessesUrl still drives me nuts, but this solution does work and is very simple to implement.
Updates - 4/15/2008
Kace's and Vadus's comments below actually point out an assumption I made when originally writing this article. I assumed that the JSF servlet was mapped to .xhtml(like in the MyFaces wiki) If its not, like in the case of Kace and Vadus, your filterProcessUrl needs to be /j_acegi_security_check.[extension that JSF servlet is mapped to]. In Kace's case it should be mapped to ".html" and in Vadus's case its mapped as ".jsf". However, unless you have a compelling case not to, I would try to always map the faces servelt to .xhtml just for the added benefit that people will not be able to manually navigate to your .xhtml pages (no need to add extra security rules)
Posted at 01:34PM Oct 08, 2007 by Travis Klotz in JSF | Comments[2]
Saving Time with Spring Extensible XML Authoring
The Problem
When building CRUD screens for hibernate objects you end up building and configuring many different application layers for each and every one of your CRUD objects. For example I usually end up needing the following objects when working with JSF:
- A DAO object to handle data access.
- A Service Object to handle any business logic I may want to reuse independent of the view
- A request scoped form action/backing bean used to handle display controller logic for create/edit forms.
- A request scoped paged list action/backing bean for handling display logic for displaying paged lists of my objects.
- A session scoped ID holder for storing the id of the current object I am editing
- A session scoped Pagination info bean that stores all the current paging/sorting information for my list page.
- For many of my CRUD objects I end up configuring a request scoped bean that represents my currently selected object
That is a lot of objects to build and configure! And that?s just for one CRUD type, I may have dozens in my application. Thankfully CRUD logic is very independent of the type actually being persisted. I can build a BaseDao, BaseService, BaseAction and BasePagingAction to handle all the logic and just inject the proper hibernate persisted Class object into the DAO instance. So I really only have to write the CRUD code once for the application (or if I?m smart, write it once for a company and reuse it in library form in all my projects,) and then just configure different instances of the base classes for each of my CRUD types.
Now I still have a problem, I have seven objects to configure for each of my CRUD types. And the configuration is going to be almost identical for each type, just a different name for each, and a different Class injected into the DAO. They all get wired together in exactly the same way for each type, the DAO is injected into the service, and the service is injected into the action etc. But this isn?t simple configuration either, some beans are request scoped, others are session scoped, some have init methods that must be called while others do not. This can easily end up being 100 lines of XML per CRUD type. I don?t know about you, but I?m not going to type 100 almost identical lines of XML for each of my types. I?m going to either cut and past the entire thing (and forget to change 2 or 3 names each time as well as never refactor anything ever again so that I don?t need to change thousands of lines of xml) OR I?m going to find a better way.
Spring Extensible XML Authoring: A better way
Since version 2.0, Spring has offered me a fairly simple solution to my problem. Developers can now define their own tags to be used along side the old style bean definition syntax. Out of the box Spring 2.0 demonstrates the power of this feature by giving us greatly simplified methods of configuring AOP and transaction management. I want to use this same feature to let me transform 100 lines of xml configuring seven beans into this:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sai="http://www.sourceallies.com/spring/crud"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.sourceallies.com/spring/crud http://www.sourceallies.com/spring/crud/crud-config.xsd">
<sai:crudConfig baseName=?"person"? queryClass=?"com.sourceallies.Person?" /></beans>
It turns out this is really fairly easy, but there are many files involved.
Step 1: Define the Schema
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.sourceallies.com/spring/crud"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.sourceallies.com/spring/crud"
elementFormDefault="qualified">
<xsd:element name="crudConfig">
<xsd:complexType>
<xsd:attribute name="baseName" use="required" type="xsd:string" />
<xsd:attribute name="queryClass" use="required" type="xsd:string" />
</xsd:complexType>
</xsd:element>
</xsd:schema>
This is a very simple schema with just one element containing two attributes allowing us to define the name of our CRUD type and the underlying query class name.
Step 2: Implement a BeanDefinitionParser
This is where the meat of the implementation lies. Given a DOM element, we need to construct all the bean definition metadata for our seven beans.
public class CrudConfigBeanDefinitionParser implements BeanDefinitionParser {
public AbstractBeanDefinition parse(Element element, ParserContext parserContext) {
String baseName = element.getAttribute("baseName");
String queryClass = element.getAttribute("queryClass");
BeanDefinitionRegistry registry = parserContext.getRegistry();
registerHolder(baseName, registry);
registerPageInfo(baseName, registry);
registerDao(baseName, queryClass, registry);
registerService(baseName, registry);
registerPagedAction(baseName, registry);
registerAction(baseName, registry);
registerCurrentBean(baseName, queryClass, registry);
return null;
}
protected void registerDao(String baseName, String queryClassName, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition("com.sourceallies.BaseDaoImpl");
builder.addPropertyReference("sessionFactory", "sessionFactory");
builder.addPropertyValue("queryClass", queryClassName);
registry.registerBeanDefinition(getDaoName(baseName), builder.getBeanDefinition());
}
protected String getDaoName(String baseName) {
return baseName + "Dao";
}
.
.
.
}
This is just a partial implementation, but you can get the general idea. Spring will call the "parse" method passing in the DOM element for our crudConfig tag. We strip out the baseName and queryClass attribute and then use them to build the metadata. The code mimics the original xml file format fairly closely, i can add property values and property references to my bean defs, just like in the xml. One of the best parts of doing things this way is that I can now easily enforce naming standards for my beans, the DAO for the person object will be called personDao and the DAO for the bulding object will be buildingDao. Same goes for the service, the actions and the rest of the beans! Instant convention over configuration.
Step 3: The Rest of the Files
We have three things left to do:
- Register the CrudConfigBeanDefintiionParser to be used to parse the crudConfig tag using a NamespaceHandler
- Register our NamespaceHandler with our custom namespace
- Register our schema file(xsd) with our schema location
The NamespaceHandler is easy enough:
public class FrontNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("crudConfig", new CrudConfigBeanDefinitionParser());
}
}
You register the NamespaceHandler with your namespace by creating a file in your META-INF directory with the name "spring.handlers" This is just a simple property file:
http\://www.sourceallies.com/spring/crud=com.sourceallies.CrudNamespaceHandler
And finally you register your schema file with your schema location by creating a file in your META-INF directory with the name "spring.schemas" also a simple property file:
http\://www.sourceallies.com/spring/crud/crud-config.xsd=com/sourceallies/crud-config.xsd
Beyond the Basics
This is really just a start, I'm not going to always be able to get away with just using the base classes. In some cases i'm going to want to swap in a more specific version of Services, DAOs, Actions etc. without sacrificing the consistency I get using my custom namespace. This just involves extending my xsd file and extending my parser. For example, my parser can currently handle something like this:
<sai:crudConfig baseName="location" queryClass="com.sourceallies.example.Location">
<sai:action class="com.sourceallies.example.LocationAction">
<sai:property name="currentPolicy" ref="currentPolicy" />
</sai:action>
</sai:crudConfig>
This lets me override the class used for my Form Action as well as add extra properties on top of the normal additions(IdHolder and Service) But i dont have to worry about specifying the init method name, or the scope, and the bean name will continue to follow my conventions.
Conclusion
Spring's extensible XML authoring features are an easy way to greatly increase the amount of consistency and clarity in your applications configuration. If you find yourself repeating the same configuration patterns over and over again, there is now a better way!
To learn more, check out Appendix B in the Spring Reference Guide
Posted at 09:08PM Aug 30, 2007 by Travis Klotz in Spring | Comments[0]