Patrik has posted 9 posts at DZone. View Full User Profile

Sculptor: DSL in Practice

02.11.2009
| 4912 views |
  • submit to reddit

Sculptor is an Open Source tool that applies the concepts from Domain-Driven Design and Domain Specific Languages. The main purpose is to improve productivity and quality when developing enterprise Java applications.

You express your design intent in a textual specification, from which Sculptor generates high quality Java code and configuration. Sculptor takes care of the technical details, the tedious repetitive work, and let you focus on delivering more business value – and have more fun.

The DSL and the code generation drives the development and is not a one time shot. It is an iterative process, which can be combined with Test Driven Development and evolutionary design.

Sculptor is useful when developing typical enterprise or web applications that benefit from a rich and persistent domain model. The target implementation is based on well known frameworks, such as Hibernate and Spring.

There is often a need for a user interface with classical CRUD functionality. Sculptor helps you with that, by generating a CRUD GUI with sophisticated management of associations. The functionality of the front end is customized with another textual DSL with linking to the business tier model. The target implementation of the CRUD GUI comes in two flavors: - web application based on Spring Webflow and JSF - rich client based on Eclipse Rich Client Platform and Spring

Let me illustrate Sculptor in practice using the DDD Sample, and the cargo domain described in Eric Evans' book.

We need a service to book a cargo from one location to another. This is expressed in Sculptor DSL:

        Service BookingService {
            @TrackingId bookNewCargo(@UnLocode origin, @UnLocode destination);
        }

        BasicType TrackingId {
            String identifier key;
        }

        BasicType UnLocode {
            String unlocode key
        }

Sculptor takes this model as input and generates an EJB service and a separate implementation, in which you manually add the the logic for the service. Spring dependency injection and AOP for things like error handling is also generated.

When thinking about the implementation we identify the need for a few more things, a persistent Location object and a way to find it.

        Service BookingService {
            inject @CargoRepository
            @TrackingId bookNewCargo(@UnLocode origin, @UnLocode destination)
                throws LocationNotFoundException;
                        
            protected findLocation => LocationRepository.find;
        }

        Entity Location {
            not optimisticLocking
            scaffold
            - @UnLocode unLocode key
            String name not changeable
            
            Repository LocationRepository {
                @Location find(@UnLocode unLocode) throws LocationNotFoundException;
                protected findByKeys;
            }
        }

The result of the booking should be a saved Cargo Entity.

        Entity Cargo {
            - @TrackingId trackingId key
            - @Location origin required
            - @Location destination required
            
            Repository CargoRepository {
                 save;
                 TrackingId nextTrackingId;
            }
        }

We generate again and a few seconds later we have two persistent objects with Hibernate mapping and Repositories. We complete the booking service by adding the hand written java code:

    public TrackingId bookNewCargo(ServiceContext ctx, UnLocode originCode,
        UnLocode destinationCode) throws LocationNotFoundException {

        TrackingId trackingId = getCargoRepository().nextTrackingId();
        Location origin = findLocation(ctx, originCode);
        Location destination = findLocation(ctx, destinationCode);
        Cargo cargo = new Cargo(trackingId, origin, destination);

        getCargoRepository().save(cargo);
        return cargo.getTrackingId();
    } 

Let's say we need a CRUD GUI for administration of the locations. Therefore we add the scaffold keyword to the Location Entity to get the ordinary CRUD operations. In this simple case we don't need to customize it by specifying things in the GUI DSL. - Done!

You will find a lot more samples and explanations in the Sculptor wiki.

A success story from one of our users:

It was a completely new project started from scratch. The main goal of a project was processing of a big files and then generates reports. Despite the fact that installation of a product includes configuration for personal and network use, we choose choose architecture of app that includes Tomcat and Hibernate. After some investigation I found Sculptor. It uses well known (by me) technologies and best practices for that moment. When main functionality was implemented in a draft state Sculptor helped to start with a simple domain model. It was not really big model. This model includes about 50 entities and services (Users, Reports, Settings, Schedule, Directory objects, ...). It was implemented by a team with a different experience in JEE technologies. And almost all of them started to use Sculptor model very quickly. Our team used SCRUM as a development process. So, it was really exciting "Agile" process implementation. Even Domain Model was agile! There were several serious refactorings that includes changes in Domain Model and Sculptor framework supported this in several ways. First, It requires tests implementation, so our changes was tested just after applying. Second, the way Sculptor uses to separate generated and hand-written code doesn't prevent refactorings. Sure, there were some minor problems, e.g. with using "lazy" initialization. But they were successfully solved and now product is on the market. – Regards, Vladimir

AttachmentSize
sculptor.gif4.29 KB
0
Published at DZone with permission of its author, Patrik Nordwall.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)