package jumpstart.web.services; import java.util.Arrays; import java.util.HashSet; import jumpstart.util.JodaTimeUtil; import jumpstart.web.translators.YesNoTranslator; import jumpstart.web.validators.Letters; import org.apache.tapestry5.SymbolConstants; import org.apache.tapestry5.Translator; import org.apache.tapestry5.Validator; import org.apache.tapestry5.ioc.Configuration; import org.apache.tapestry5.ioc.MappedConfiguration; import org.apache.tapestry5.ioc.OrderedConfiguration; import org.apache.tapestry5.ioc.ServiceBinder; import org.apache.tapestry5.ioc.annotations.Primary; import org.apache.tapestry5.ioc.services.ClasspathURLConverter; import org.apache.tapestry5.ioc.services.Coercion; import org.apache.tapestry5.ioc.services.CoercionTuple; import org.apache.tapestry5.services.ComponentClassTransformWorker; import org.apache.tapestry5.services.ComponentRequestFilter; import org.apache.tapestry5.services.PageRenderLinkSource; import org.apache.tapestry5.services.RequestFilter; import org.joda.time.DateMidnight; import org.joda.time.LocalDate; /** * This module is automatically included as part of the Tapestry IoC Registry, it's a good place to configure and extend * Tapestry, or to place your own service definitions. See * http://tapestry.apache.org/tapestry5.2-dev/tapestry-ioc/module.html */ public class AppModule { // Add 2 services to those provided by Tapestry. // - CountryNames, and SelectIdModelFactory are used by pages which ask Tapestry to @Inject them. public static void bind(ServiceBinder binder) { binder.bind(CountryNames.class); binder.bind(SelectIdModelFactory.class, SelectIdModelFactoryImpl.class); // This next line addresses an issue affecting GlassFish and JBoss - see http://blog.progs.be/?p=52 javassist.runtime.Desc.useContextClassLoader = true; } // Tell Tapestry about our custom validators, translators, and their message files. // We do this by contributing to Tapestry's FieldValidatorSource service, TranslatorSource service, // and ValidationMessagesSource service. @SuppressWarnings("rawtypes") public static void contributeFieldValidatorSource(MappedConfiguration configuration) { configuration.add("letters", new Letters()); } @SuppressWarnings("rawtypes") public static void contributeTranslatorSource(MappedConfiguration configuration) { configuration.add(Boolean.class, new YesNoTranslator()); } public void contributeValidationMessagesSource(OrderedConfiguration configuration) { configuration.add("myValidationMessages", "jumpstart/web/validators/ValidationMessages"); configuration.add("myTranslationMessages", "jumpstart/web/translators/TranslationMessages"); } // Tell Tapestry about our custom ValueEncoders. // We do this by contributing to Tapestry's ValueEncoderSource service. // @SuppressWarnings("rawtypes") // public static void contributeValueEncoderSource(MappedConfiguration configuration) { // configuration.addInstance(Person.class, PersonEncoder.class); // } // Tell Tapestry which locales we support. // We do this by contributing to Tapestry's ApplicationDefaults service. public static void contributeApplicationDefaults(MappedConfiguration configuration) { configuration.add(SymbolConstants.SUPPORTED_LOCALES, "en_US,en_GB,fr"); } // Tell Tapestry how to block access to WEB-INF/, META-INF/, and assets that are not in our "whitelist". // We do this by contributing a custom RequestFilter to Tapestry's RequestHandler service. // - This is necessary due to https://issues.apache.org/jira/browse/TAP5-815 . // - RequestHandler is shown in http://tapestry.apache.org/request-processing.html#RequestProcessing-Overview . // - RequestHandler is described in http://tapestry.apache.org/request-processing.html // - Based on an entry in the Tapestry Users mailing list by martijn.list on 15 Aug 09. public void contributeRequestHandler(OrderedConfiguration configuration, PageRenderLinkSource pageRenderLinkSource) { final HashSet ASSETS_WHITE_LIST = new HashSet(Arrays.asList("jpg", "jpeg", "png", "gif", "js", "css", "ico")); configuration.add("AssetProtectionFilter", new AssetProtectionFilter(ASSETS_WHITE_LIST, pageRenderLinkSource), "before:*"); } // Tell Tapestry how to prevent access to pages marked as @ProtectedPage unless logged in. // We do this by contributing a custom ComponentRequestFilter to Tapestry's ComponentRequestHandler service. // - ComponentRequestHandler is shown in // http://tapestry.apache.org/request-processing.html#RequestProcessing-Overview // - Based on http://tapestryjava.blogspot.com/2009/12/securing-tapestry-pages-with.html public void contributeComponentRequestHandler(OrderedConfiguration configuration) { configuration.addInstance("PageProtectionFilter", PageProtectionFilter.class); } // Tell Tapestry how to handle JBoss 5, 6.0, or 6.1's classpath URLs - JBoss uses a "virtual file system". // See "Running Tapestry on JBoss" in http://wiki.apache.org/tapestry/Tapestry5HowTos . @SuppressWarnings("rawtypes") public static void contributeServiceOverride(MappedConfiguration configuration) { configuration.add(ClasspathURLConverter.class, new ClasspathURLConverterJBoss5()); // configuration.add(ClasspathURLConverter.class, new ClasspathURLConverterJBoss60()); // configuration.add(ClasspathURLConverter.class, new ClasspathURLConverterJBoss61()); } // Tell Tapestry how to handle @EJB in page and component classes // We do this by contributing to Tapestry's ComponentClassTransformWorker service. // - Based on http://wiki.apache.org/tapestry/JEE-Annotation, adapted to Tapestry 5.2 (from 5.3) and EJB 3.0 (from // 3.1). @Primary public static void contributeComponentClassTransformWorker( OrderedConfiguration configuration) { configuration.addInstance("EJB", EJBAnnotationWorker.class, "before:Property"); } // Tell Tapestry how to coerce Joda Time types to and from Java Date types // We do this by contributing to Tapestry's TypeCoercer service. // - Based on http://tapestry.apache.org/typecoercer-service.html @SuppressWarnings("rawtypes") public static void contributeTypeCoercer(Configuration configuration) { // From java.util.Date to DateMidnight Coercion toDateMidnight = new Coercion() { public DateMidnight coerce(java.util.Date input) { // TODO - confirm this conversion always works, esp. across timezones return JodaTimeUtil.toDateMidnight(input); } }; configuration.add(new CoercionTuple(java.util.Date.class, DateMidnight.class, toDateMidnight)); // From DateMidnight to java.util.Date Coercion fromDateMidnight = new Coercion() { public java.util.Date coerce(DateMidnight input) { // TODO - confirm this conversion always works, esp. across timezones return JodaTimeUtil.toJavaDate(input); } }; configuration.add(new CoercionTuple(DateMidnight.class, java.util.Date.class, fromDateMidnight)); // From java.util.Date to LocalDate Coercion toLocalDate = new Coercion() { public LocalDate coerce(java.util.Date input) { // TODO - confirm this conversion always works, esp. across timezones return JodaTimeUtil.toLocalDate(input); } }; configuration.add(new CoercionTuple(java.util.Date.class, LocalDate.class, toLocalDate)); // From LocalDate to java.util.Date Coercion fromLocalDate = new Coercion() { public java.util.Date coerce(LocalDate input) { // TODO - confirm this conversion always works, esp. across timezones return JodaTimeUtil.toJavaDate(input); } }; configuration.add(new CoercionTuple(LocalDate.class, java.util.Date.class, fromLocalDate)); } }