Open source, commercial support.
This tutorial will show in the simplest possible way how to use milton with hibernate. It runs in tomcat and has no spring configuration. It's an eclipse project and doesnt use any build tool like ant maven.
You can check the source out of subversion here: svn://www.ettrema.com/milton/trunk/milton/examples/tutorial-1-hibernate
Or download it as a zip file here
The Task: Build a HR database
We're going to build the first part of a HR system. Our database will just be a table of departments in this installment, and a subsequent article will add employees and managers etc.
Some background
First, you'll need to setup an eclipse web project. I won't go into details, but you can find instructions here - www.ibm.com/developerworks/opensource/library/os-eclipse-tomcat/
And for more detailed information about hibernate here's a nice tutorial - www.laliluna.de/articles/first-hibernate-example-tutorial.html
Step 1 - Setup the project
Create an eclipse project called MiltonTutorial_1. Configure your tomcat instance to run on port 80. Note that this isnt strictly required but i really recommend it for MS Windows users because some functionality on some versions of windows will ONLY work on port 80.
Download the zip file and put the jar files into WEB-INF/libs, and refresh the project.
Step 2 - Create our domain object, and configure hibernate
Every good HR system starts with the Department object, and ours will be no different. For our purposes we only need a single field, the name, so we have a very simple Deparment class, see here for the source.
We need to configure hibernate and tell it what database to use. For this article we'll use an embedded HSQL database so you don't have to install anything. Here's the hibernate config file.
Step 3 - Create the milton resource classes
And now we come to the meat in the sandwich. To use milton you implement the ResourceFactory interface, which milton uses to locate instances of Resource for a given URL. And you also need to implement Resource, so you've got something to locate. So what is a Resource? Milton sees a resource very much the same way the HTTP spec does. A resource is simply something that a URL (Uniform Resource Locator) locates, which may or may not have certain well defined operations performed on it, such as GET the content, DELETE to remove it, or PUT to update it. Once located, milton will determine what operations are permitted based on what interfaces your class has implemented.
Note: A resource class which only implements Resource can't do anything!
If you want to be able to GET the content for your resource, implement GetableResource. To enable folder browsing using Windows Explorer and other webdav clients you must implement CollectionResource on all your folder resources, and PropFindableResource on both file and folder resources.
For this tutorial we want two Resource classes:
- DepartmentResource, which represents a single department. It will be a folder, because it will eventually hold employees
- AllDepartmentsResource, which is our root folder and contains all departments. If this sounds odd, remember that we need a resource to be located for every URL, including /
Implementing CollectionResource and PropFindableResource is pretty simple, as you can see from the source code linked above. Most milton properties allow you to return null. Our database doesnt have fields for created and modified dates, so we return null for them. If we did provide them milton would be able to use them for corresponding HTTP headers, but its ok not to have them.
The interesting bit is in the AllDepartmentsResource getChildren() method:
public List getChildren() {
return resourceFactory.findAllDepartments(session);
}
And the corresponding method being called in HrResourceFactory:
public List
Criteria crit = session.createCriteria(Department.class);
List list = crit.list();
if( list == null || list.size() == 0) {
return Collections.EMPTY_LIST;
} else {
List
for( Object o : list ) {
departments.add( new DepartmentResource(this, (Department)o) );
}
return departments;
}
}
The getChildren method is called on a folder when a webdav client wants to browse its contents. As you can see, its a simple matter of finding what physical resources are logically inside the folder (in this case all Department rows) and wrapping them with your corresponding Resource class (the DepartmentResource).
Step 4: Implement ResourceFactory
So now we've got two resource classes, we need to provide a way for milton to find them - ie we implement the ResourceFactory interface.
Now, resources could be located by finding the root resource and walking down though its children, and their children. But in many cases this would be inefficient. How you do it is ultimately up to you. In this case we have a very simple data model so we'll have simple lookup logic:
- if the requested URL is the root of our app return AllDepartmentsResource
Eg: http://localhost/MiltonTutorial_1 -->> return new AllDepartmentsResource(..) - if the URL has a single path component then attempt to locate a DepartmentResource with that name
Eg http://localhost/MiltonTutorial_1/Finance -->> find a Department with name=Finance
To make this process even simpler Milton has a handy little class called Path. Use it to parse the path part of a URL (ie after the port) and it then gives you a parent/child relationship between the components of the path. Using Path we end up with a getResource method in HrResourceFactory like this:
public Resource getResource(String host, String p) {
Path path = Path.path(p).getStripFirst();
log.debug("getResource: " + path);
Session session = sessionFactory.openSession();
if( path.isRoot() ) {
return new AllDepartmentsResource(this, session);
} else if( path.getLength() == 1 ) {
return findDepartment(path.getName(), session);
} else {
return null;
}
}
Note that the second argument passed to getResource is the full path component of the requested URL, this includes the application context (MiltonTutorial_1), so the first line is to strip that component out.
Step 5: Connecting it to milton
Now we've got a ResourceFactory which milton can use, we need to get it to milton. This is where things start to depend on how we're going to configure our application. In this case we're not using any configuration tool (ie like Spring) so the easiest way is to use a ResourceFactoryFactory.
This interface is used by MiltonServlet to get a reference to the ResourceFactory. The intention is so you can embed initialisation logic, and read properties files, etc to configure your application however you want. You then just pass the class name of your ResourceFactoryFactory instance to the MiltonServlet
You can see in HrResourceFactoryFactory that we initialise the hibernate sessionFactory and return the default milton response handler (more about that later!). The null checking in init is just because we're using HSQL which has issues with file locking when the app server restarts.
public void init() {
log.debug("init");
if( authenticationService == null ) {
authenticationService = new AuthenticationService();
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
resourceFactory = new HrResourceFactory(sessionFactory);
checkInitialData();
}
}
CheckInitialData just creates a few rows in the database so we have something to look at when we get started.
Step 6: Configure the milton servlet
Adding milton to your web.xml can be as simple as just specifying the ResourceFactoryFactory class in an init-param.
The tutorial code has a couple of extra goodies thrown in. It has a DebugFilter enabled to help you trace requests and responses (since there's no firebug for dav clients!) and we're disabling digest authentication to make diagnostics simpler. You can see the whole lot here - web.xml
Step 7: Configure logging
You really should keep an eye on your logs, milton can be very helpful and informative when things go wrong. Milton uses slf4j to be independent of logging frameworks. This example has slf4j wrapping log4j, so make sure you configure log4j correctly.
Step 8: Start the server
Make sure you've added your web project to your tomcat server, then use the servers panel to start it. Check the logs and make sure it all started up ok. You should see something like this:
15/05/2010 11:54:58 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The Apache Tomcat Native library which allows optimal performance in production environments was 15/05/2010 11:54:58 PM org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-80
15/05/2010 11:54:58 PM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 561 ms
15/05/2010 11:54:58 PM org.apache.catalina.realm.JAASRealm setContainer
INFO: Set JAAS app name Catalina
15/05/2010 11:54:58 PM org.apache.catalina.core.StandardService start
INFO: Starting service Catalina
15/05/2010 11:54:58 PM org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.14
DEBUG com.bradmcevoy.http.MiltonServlet - resourceFactoryFactoryClassName: com.ettrema.tutorial.hr.web.HrResourceFactoryFactory
DEBUG com.ettrema.tutorial.hr.web.HrResourceFactoryFactory - init
DEBUG com.bradmcevoy.http.http11.auth.ExpiredNonceRemover - scheduling checks for expired nonces every 10 seconds
DEBUG com.bradmcevoy.http.http11.auth.SimpleMemoryNonceProvider - created
Hibernate: select this_.id as id0_0_, this_.name as name0_0_ from Department this_
DEBUG com.ettrema.tutorial.hr.web.HrResourceFactoryFactory - creating initial data
Hibernate: insert into Department (name, id) values (?, ?)
Hibernate: insert into Department (name, id) values (?, ?)
Hibernate: insert into Department (name, id) values (?, ?)
DEBUG com.bradmcevoy.http.MiltonServlet - Configured authentication handlers: 1
DEBUG com.bradmcevoy.http.MiltonServlet - - com.bradmcevoy.http.http11.auth.BasicAuthHandler
DEBUG com.bradmcevoy.http.ServletHttpManager - init
DEBUG com.bradmcevoy.http.ServletHttpManager - init filter: com.bradmcevoy.http.DebugFilter
DEBUG com.bradmcevoy.http.DebugFilter - logging to: C:\Users\brad
15/05/2010 11:55:02 PM org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-80
15/05/2010 11:55:02 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 3619 ms
Step 9: Connect with webdav
Now for the fun bit. Use your favourite webdav browser (windows explorer for windows, finder for macos, nautilus for linux/gnome) and open http://localhost/MiltonTutorial_1
You shouldnt get asked for a password because we've stubbed out authorise and authenticate.
You should see a folder like this:

BUT, you'll quickly notice that you can't do anything more then browse. Thats because we havent implemented anything else. In the next article we'll show you how to do normal file management stuff like uploading, downloading, deleting, copying and moving.
Milton can also do much more advanced things like locking, quota management and even calendar synchronisation, but more on that later.
Where to now?
Milton comes with a few runnable demonstration projects. Check out the source and run them with maven, then you can play around with the source code. See the quick start page for details.