1. Start Spring application context for your Tapestry unit tests

    Tapestry has a powerful tool to unit test your pages and services, but how to deal with it when your pages and services use Spring beans ?

    Tapestry PageTester can be extended like the TapestryFilter to provide your own ServiceModuleDef classes.  The tapestry-spring contribution already provides the one needed to load a Spring application context. Then, loading Spring for your unit tests will be as simple as extended the existing PageTester and provide the Tapestry Spring Module Definition class.

    Also, because this module definition uses the servlet application context to get the configuration files location, we will have to mock it. Let’s use Spring MockServletContext for this.

    • Update your maven dependencies to add spring web mock objects
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring-version}</version>
      </dependency>
    
    • Extend Tapestry PageTester, adapt the code below to your needs if you want to provide mock versions of your spring beans or make it more configurable
    public class WookiPageTester extends PageTester
    {
    
     private MockServletContext servletContext;
    
     public WookiPageTester(String appPackage, String appName, String contextPath,
     Class... moduleClasses)
     {
       super(appPackage, appName, contextPath, moduleClasses);
       Registry registry = this.getRegistry();
       // Set Tapestry registry in mock servlet context
       servletContext.setAttribute(TapestryFilter.REGISTRY_CONTEXT_NAME, registry);
     }
    
     public WookiPageTester(String appPackage, String appName)
     {
       super(appPackage, appName);
     }
    
     @Override
     protected ModuleDef[] provideExtraModuleDefs()
     {
       // Set spring configuration files location
       servletContext = new MockServletContext();
       servletContext.addInitParameter("contextConfigLocation", "classpath*:mock-applicationContext.xml");
       return new ModuleDef[] { new SpringModuleDef(servletContext) };
     }
    
    }
    

    Thanks for reading !

  2. Wooki 0.3 is out !

    After a few months of hard work to extract re-usable components from Wooki, the version 0.3 is finally out !

    Along with Wooki improvements, we have created three major spin-off contributions that put the basis for a strong architecture that will make Wooki evolutive and ready for production soon:

    • tapestry5-spring-tx allows you to benefit from Spring Platform Transaction management inside Tapestry
    • tapestry5-installer provides a way to easily deploy and install tapestry 5 application
    • tapestry5-db-migration, inspired from rails migrations, allows you to get full control over your database schema through your Tapestry 5 application lifecycle

    All this work justifies this wooki version. It has been the opportunity to validate and polishing these different contributions in a real context.

    Also the global code of Wooki has been reviewed to ease future evolutions and current features maintenance

    • Move to Tapestry 5.2 that make development with Tapestry more and more confortable
    • Integration of spring-acl to handle authorization on wooki’s resources
    • Creation of an abstraction layer to handle DB query parameters like range, created since
    • Centralize activity lookup for RSS feeds and front display
    • Centralize application link management and improve the application security layer

    To conclude, one important news is that wooki has moved to spreadthesource organization on github

    We hope you will find inspiration from all these as a user or a Tapestry developer ! Give it a try !

    Thanks for reading.

  3. Christophe Cordenier as an Apache Tapestry 5 committer

    Hey, two weeks ago, Christophe Cordenier has been promoted as an Apache Tapestry 5 committer. Congratulations to him. This is definitely a great opportunity for “spread the source” to contribute to the Tapestry 5 framework.

    As far as I know, his first goal is to contribute to the documentation effort started by Ulrich Stärck. By the way, Ulrich has been promoted as an Apache Tapestry 5 PMC member.

    As a side news, wooki 0.3 is almost finished. This will be a huge release in terms of refactoring and new features. We made some terrific things.  Stay tuned, the announce will come in next few days.

  4. Tapestry 5 Logo in Motion

    Thanks to my brother Matthieu co-founder of Kamélégraph, a french design agency specialized in 3D design for architects and thanks to the recent work made by Robin Komiwes on Tapestry 5 Logo

    We are pleased to suggest to the Tapestry 5 community a fun animation that should be used to start or conclude a Tapestry 5 presentation

    Here are the first two drafts of the current work, comments and suggestions are welcome !

  5. Vox Wooki : A Tapestry Community News Feed

    Tapestry community has been quite active recently with many announcements. Here is a focus on what’s new since the last three months:

    Contributions

    Tynamo guys are very actives, they provided new releases for two of their contributions :

    … and a brand new module to send alerts via email ‘if something happens to your parent process’

    Two testing frameworks announced in new version :

    The complete and so useful Tapestry JumpStart is now available in version 4.9

    From our side, GOT5 a.k.a. “Gang Of Tapestry 5″ , a new group of Tapestry developers where we (Christophe and Robin) belong too. In fact this group is the hat we are going to wear when we will publish Open Source content from work made for our employer. Anyway we released under GOT5 hat something really awesome:

    • tapestry5-jquery allows to get completely rid of prototype API and use jQuery instead, this project has started to be used by the community and we already have some feedback on it to improve and complete it

    Also, as you may have noticed, wooki has been completely refactored during the last two months. One main objective of this was to extract most of the reusable pieces of wooki into third-party contributions under spreadthesource account. Here is the list of libraries that has been extracted from wooki’s experience.

    This two contributions are used for a while now on wooki and have been confirmed to be really useful with the experience.

    One of the most important but still in progress is a tool that will allow to easily maintain your application database schema accross version of your application. It will provide a full API built on top of Hibernate tools to create/update your database schema, insert/delete datas…

    Finally we have a two-phase tapestry launcher and a contribution that allows tapestry-hibernate to work with Spring Hibernate Transaction Manager.

    We expect to provide stable releases for all of these with the next wooki’s version.

    Thanks for reading.

  6. Tapestry IOC : Implement Strategy Pattern with Enums

    Tapestry already have a StrategyBuilder that is really useful when you want to write a generic service interface and let Tapestry IOC decides which implementation to call in function of the type of the arguments. But how to do it when your strategy does not depend on a Java type but a Enum type ?

    We’ll see in this article a concrete use case of this type of strategy and see how easy it is to implement with Tapestry.

    Use Case

    We have a component that displays the activity logs on our Web site. This component is in charge of getting the list of activities to display. These latter will depend on the user context, that means not every user will see the same activities type and list.

    ActivitySource

    To avoid having boilerplate code in the component that will identify which finder method to call depending on the context. We define a simple interface that will be called by the component to obtain the list of strategy to display.

    public interface ActivitySource {
     List<Activity> listActivities(Long... context);
    }
    

    Note the ‘context’ parameters that consists in a list of ids that can be used by the implementation class to build its db query. Now we have the interface let’s create two implementations i.e. PublicActivitySource and AdminActivitySource that will list the activities in function of the logged user is a guest or a user with admin rights.

    ActivitySourceType

    This is the key concept of this article, now we have defined the interface and created two implementations classes, we will list all of these in a single Enum type called ActivitySourceType. Let’s see how it looks like :

    public enum ActivitySourceType {
    
     ADMIN_AS(AdminActivitySource.class),
    
     PUBLIC_AS(PublicActivitySource.class);
    
     private Class<? extends ActivitySource> sourceClass;
    
     private ActivitySourceType(Class<? extends ActivitySource> source) {
         this.sourceClass = source;
     }
    
     @SuppressWarnings("unchecked")
     public Class<ActivitySource> getSourceClass() {
         return (Class<ActivitySource>) sourceClass;
     }
    
    }
    

    We create on Enum type per activity source. Doing this we have a centralized lists of available sources, now let’s see how to bind all these implementation classes so we can use them in our application.

    Register your services

    Tapestry provides a convenient way to automatically bind service implementation via the ServiceBinder class. Each implementation must have a different id so we can distinguish them at runtime. Here is the code used to iterate through the list of existing implementations. This will be localized in your AppModule class.

    public static void bind(ServiceBinder binder) {
        for(ActivitySourceType type : ActivitySourceType.values()){
            binder.bind(ActivitySource.class, type.getSourceClass()).withId(type.toString());
        }
    }
    

    Now this is done, all the existing services has been registered and you can easily and dynamically retrieve a ActivitySource service reference in your Tapestry pages.

    Obtain the  service instance

    Use the Tapestry registry to dynamically access to the corresponding service in function of the context. i.e. You can see below how to get it work in a component using a dynamic parameter value of ActivitySourceType type.

     @Parameter
     private ActivitySourceType type;
    
     @Inject
     private Context context;
    
     private ActivitySource source;
    
     ActivitySourceType defaultType() {
         return ActivitySourceType.PUBLIC_AS;
     }
    
     @SetupRender
     public void defineSource() {
         Registry reg = (Registry) context.getAttribute(TapestryFilter.REGISTRY_CONTEXT_NAME);
         this.source = reg.getService(type.toString(), ActivitySource.class);
    
         List<Activity> activities = source.listActivities();
         for (Activity a : activities) {
           System.out.println(a.getLog());
         }
     }
    

    As you can see this is as simple as retrieving the service instance from the registry giving its interface and its id, and then call its ‘listActivities’ method. Doing this, we can say that we have implemented a type-safe Strategy pattern that will avoid to use ugly switch/case statements.

  7. Tapestry 5, Spring, Hibernate and Transaction

    A new project has been added at spreadthesource, it allows you to make Tapestry 5 services and Spring beans work in the same transaction. This contribution overrides the services provided by tapestry5-hibernate contribution to wrap the beans provided by spring. Also, It creates all the elements needed by Spring to work in a transaction.

    This contribution will be useful if :

    1. You want to benefit from an existing spring configuration to start writing data access code in Tapestry 5 services
    2. You have a mixed architecture (Tapestry 5 and Spring) and you have to work in the same transaction context
    3. You want to migrate from your existing spring bean to Tapestry and then benefit from the great hot reload feature

    In our case, for wooki we have used spring acl that uses a JDBCTemplate to query the database, our business layer has moved to Tapestry 5 for the hot reload feature, so we needed to find a solution to create ACLs in the same transaction than the main business method.

    The project is available on github, and you can find more information in the README and test application provided with this contribution.

  8. Decorating RenderSupport and any MarkupRendererFilter

    I recently faced to some limitations with RenderSupport. I wanted to decorate it but I realized that this filter is not a service. What a shame, one of the most important Tapestry 5 service is not customisable…

    Really? No. There is a possibility to decorate RenderSupport, and in fact any of MarkupRendererFilter and Environment objects.

    How to achieve that?

    • Create a new RenderSupport implementation that will wrap the initial object. It’s just like we normally do when creating a decorator.
    • Create a MarkupRendererFilter that will pop RenderSupport from Environment
    • Create a the interceptor from the poped RenderSupport and push it into the Environment.
    • Contribute to MarkupRenderer’s ordered configuration and add your filter just after RenderSupport.
        public void contributeMarkupRenderer(OrderedConfiguration<MarkupRendererFilter> configuration)    {
            MarkupRendererFilter renderSupportInterceptor = new MarkupRendererFilter()
            {
                public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
                {
                    RenderSupport delegate = (RenderSupport) environment.pop(RenderSupport.class);
                    RenderSupport interceptor = new RenderSupportInterceptor(delegate);
    
                    environment.push(RenderSupport.class, interceptor);
                    renderer.renderMarkup(writer);
                }
            };
            configuration.add("RenderSupportDecorator", renderSupportInterceptor, "after:RenderSupport", "before:ClientBehaviorSupport",
                    "before:InjectDefaultStyleheet", "before:Heartbeat");
        }
    
  9. Atom and RSS feeds for Tapestry 5

    Another contribution this week for Tapestry 5 after the awesome “tapestry5-installer” : an integration of the Rome library. Rome is kind of a Java standard for generating Atom and RSS feeds.

    Rome gives you all you need to produce feeds. The only thing that may be tricky for newcomers to Tapestry 5 then is not how to produce them but how to return them. This is what “tapestry5-rome” contribution is doing: offering the possibility for action methods to return feeds.

    Want to see a sample? Check out the test page source code. Install instructions can be found in the readme file.

    Don’t forget to follow “spreadthesource” on Github to stay informed for any contributions updates.

Older Posts »