<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- We need a doctype to allow us to use special characters like
We use a "strict" DTD to make IE follow the alignment rules. -->
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
<body class="container">
<h3>@EJB</h3>
@EJB is a Java EE annotation to indicate a dependency on a Enterprise JavaBean.
In JumpStart, we use the @EJB annotation in pages, components, and mixins to indicate we want a Session Bean injected.
To detect @EJB and inject the Session Bean, we created a class called EJBAnnotationWorker.
It implements ComponentClassTransformWorker2 and is contributed to Tapestry in AppModule.<br/><br/>
Here we've injected a local Session Bean, IPersonFinderServiceLocal, to find entity Person with id = 1:<br/>
<div class="eg">
<t:beandisplay object="person"/>
</div>
References: <a href="http://docs.oracle.com/javaee/6/api/javax/ejb/EJB.html">@EJB</a>,
<a href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/transform/ComponentClassTransformWorker2.html">
ComponentClassTransformWorker2</a>,
<a href="http://tapestry.apache.org/defining-tapestry-ioc-services.html">Tapestry IoC Services</a>.<br/><br/>
<t:pagelink page="Index">Home</t:pagelink><br/><br/>
<t:tabgroup>
<t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/examples/state/AtEjb.tml"/>
<t:sourcecodetab src="/web/src/main/java/jumpstart/web/pages/examples/state/AtEjb.java"/>
<t:sourcecodetab src="/web/src/main/resources/META-INF/assets/css/examples/plain.css"/>
<t:sourcecodetab src="/web/src/main/java/jumpstart/web/services/EJBAnnotationWorker.java"/>
<t:sourcecodetab src="/business/src/main/java/jumpstart/client/IBusinessServicesLocator.java"/>
<t:sourcecodetab src="/business/src/main/java/jumpstart/client/BusinessServicesLocator.java"/>
<t:sourcecodetab src="/business/src/main/java/jumpstart/business/commons/jndi/JNDIObjectLocator.java"/>
<t:sourcecodetab src="/business/src/main/java/jumpstart/util/EJBProviderEnum.java"/>
<t:sourcecodetab src="/business/src/main/java/jumpstart/util/EJBProviderUtil.java"/>
<t:sourcecodetab src="/business/src/main/java/jumpstart/business/commons/exception/SystemUnavailableException.java"/>
<t:sourcecodetab src="/web/src/main/java/jumpstart/web/services/AppModule.java"/>
</t:tabgroup>
</body>
</html>
package jumpstart.web.pages.examples.state;
import javax.ejb.EJB;
import jumpstart.business.domain.person.Person;
import jumpstart.business.domain.person.iface.IPersonFinderServiceLocal;
import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.annotations.Property;
@Import(stylesheet = "css/examples/plain.css")
public class AtEjb {
// Screen fields
@Property
private Person person;
// Generally useful bits and pieces
@EJB
private IPersonFinderServiceLocal personFinderService;
// The code
void setupRender() throws Exception {
person = personFinderService.findPerson(1L);
if (person == null) {
throw new IllegalStateException("Database data has not been set up!");
}
}
}
.eg {
margin: 20px 0;
padding: 14px;
border: 1px solid #ddd;
border-radius: 6px;
-webkit-border-radius: 6px;
-mox-border-radius: 6px;
}
// Based on http://wiki.apache.org/tapestry/JEE-Annotation.
package jumpstart.web.services;
import javax.ejb.EJB;
import jumpstart.client.BusinessServicesLocator;
import jumpstart.client.IBusinessServicesLocator;
import jumpstart.util.StringUtil;
import org.apache.tapestry5.model.MutableComponentModel;
import org.apache.tapestry5.plastic.PlasticClass;
import org.apache.tapestry5.plastic.PlasticField;
import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
import org.apache.tapestry5.services.transform.TransformationSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Inject an EJB into tapestry sources
*/
public class EJBAnnotationWorker implements ComponentClassTransformWorker2 {
private static final Logger logger = LoggerFactory.getLogger(EJBAnnotationWorker.class);
private IBusinessServicesLocator locator;
public EJBAnnotationWorker() {
locator = new BusinessServicesLocator(logger);
}
@Override
public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model) {
for (PlasticField field : plasticClass.getFieldsWithAnnotation(EJB.class)) {
final EJB annotation = field.getAnnotation(EJB.class);
if (StringUtil.isNotEmpty(annotation.name())) {
throw new RuntimeException(
"This implementation of the @EJB annotation does not support the name parameter. Found name = \""
+ annotation.name() + "\".");
}
else if (StringUtil.isNotEmpty(annotation.beanName())) {
throw new RuntimeException(
"This implementation of the @EJB annotation does not support the beanName parameter. Found beanName = \""
+ annotation.beanName() + "\".");
}
else if (StringUtil.isNotEmpty(annotation.mappedName())) {
throw new RuntimeException(
"This implementation of the @EJB annotation does not support the mappedName parameter. Found mappedName = \""
+ annotation.mappedName() + "\".");
}
String fieldType = field.getTypeName();
Object injectionValue = locator.getService(fieldType);
if (injectionValue != null) {
field.inject(injectionValue);
field.claim(annotation);
}
}
}
}
package jumpstart.client;
/**
* BusinessServicesLocator is used to centralize all lookups of business services in JNDI.
*/
public interface IBusinessServicesLocator {
/**
* @param interfaceClass eg. IPersonServiceLocal.class .
* @return eg. An instance of IPersonServiceLocal as found by JNDI.
*/
public abstract Object getService(Class<?> interfaceClass);
/**
* @param canonicalInterfaceName eg. "jumpstart.business.domain.examples.iface.IPersonServiceLocal".
* @return eg. An instance of IPersonServiceLocal as found by JNDI.
*/
public abstract Object getService(String canonicalInterfaceName);
/**
* Invoked after any kind of naming or remote exception. All cached naming contexts and interfaces are discarded.
*/
public abstract void clear();
}
package jumpstart.client;
import java.util.regex.Pattern;
import jumpstart.business.commons.jndi.JNDIObjectLocator;
import jumpstart.util.EJBProviderEnum;
import jumpstart.util.EJBProviderUtil;
import org.slf4j.Logger;
/**
* BusinessServicesLocator is used to centralize all lookups of business services in JNDI. At the time of writing it is
* used by the business tier's BaseTest and the web tier's EJBAnnotationWorker and PageProtectionFilter.
*
* This version knows the formats of JNDI names assigned by OpenEJB, GlassFish, and JBoss (the EJB 3.1 specification
* only "almost" standardized them). It minimises the overhead of JNDI lookups by caching the objects it looks up. If
* this class becomes a bottleneck, then you may need to decentralise it.
*/
public class BusinessServicesLocator extends JNDIObjectLocator implements IBusinessServicesLocator {
private static final String REMOTE = "REMOTE";
private static final String LOCAL = "LOCAL";
private static final Pattern StripLocalPattern = Pattern.compile(LOCAL + "|" + REMOTE, Pattern.CASE_INSENSITIVE);
private final EJBProviderEnum ejbProvider;
public BusinessServicesLocator(Logger logger) {
super(logger);
// You wouldn't normally have to do this but JumpStart has to deal with many types of environment...
this.ejbProvider = EJBProviderUtil.detectEJBProvider(logger);
}
/**
* An example of interfaceClass is IPersonServiceLocal.
*/
@Override
public Object getService(Class<?> interfaceClass) {
return getService(interfaceClass.getCanonicalName());
}
/**
* We expect canonicalInterfaceName to be like "jumpstart.business.domain.examples.iface.IPersonServiceLocal", ie.
* its simple name has a leading "I" and trailing "Local" or "Remote".
*/
@Override
public Object getService(String canonicalInterfaceName) {
String jndiName = null;
// You wouldn't normally have to do all this work but JumpStart has to deal with many types of environment and
// EJB 3.1 still hasn't quite standardised JNDI names.
if (ejbProvider == EJBProviderEnum.OPENEJB_7_LOCAL || ejbProvider == EJBProviderEnum.TOMCAT_7_OPENEJB_7_LOCAL
|| ejbProvider == EJBProviderEnum.OPENEJB_7_REMOTE) {
// Uses the implementation class name eg. "PersonServiceLocal".
jndiName = getSimpleName(canonicalInterfaceName).substring(1);
}
else if (ejbProvider == EJBProviderEnum.GLASSFISH_3_LOCAL || ejbProvider == EJBProviderEnum.GLASSFISH_3_REMOTE) {
// Use the EJB3.1 global name eg.
// "java:global/jumpstart/jumpstartejb/PersonService!jumpstart.business.domain.examples.iface.IPersonServiceLocal".
jndiName = "java:global/jumpstart/jumpstartejb/"
+ stripOffLocalOrRemote(getSimpleName(canonicalInterfaceName).substring(1)) + "!"
+ canonicalInterfaceName;
}
else if (ejbProvider == EJBProviderEnum.WILDFLY_11_LOCAL) {
// Uses one of the ways found early in the JBoss log (logger is
// org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor).
jndiName = "java:global/jumpstart/jumpstart.jar/"
+ stripOffLocalOrRemote(getSimpleName(canonicalInterfaceName).substring(1)) + "!"
+ canonicalInterfaceName;
}
else if (ejbProvider == EJBProviderEnum.WILDFLY_11_REMOTE) {
// Uses an odd format - similar to the EJB3.1 global name, eg.
// "ejb/jumpstart/jumpstart.jar/PersonService!jumpstart.business.domain.examples.iface.IPersonServiceRemote".
jndiName = "ejb:jumpstart/jumpstart.jar/"
+ stripOffLocalOrRemote(getSimpleName(canonicalInterfaceName).substring(1)) + "!"
+ canonicalInterfaceName;
}
else {
throw new IllegalStateException("Don't know how to use ejbProvider = " + ejbProvider);
}
return getJNDIObject(jndiName);
}
private static String getSimpleName(String s) {
return s.substring(s.lastIndexOf(".") + 1);
}
private static String stripOffLocalOrRemote(String s) {
String stripped = s;
String uc = s.toUpperCase();
if (uc.endsWith(LOCAL) || uc.endsWith(REMOTE)) {
stripped = StripLocalPattern.matcher(s).replaceFirst("");
}
return stripped;
}
}
package jumpstart.business.commons.jndi;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import org.slf4j.Logger;
import jumpstart.business.commons.exception.SystemUnavailableException;
import jumpstart.util.EJBProviderEnum;
import jumpstart.util.EJBProviderUtil;
/**
* JNDIObjectLocator is used to centralize all JNDI lookups. It minimises the overhead of JNDI lookups by caching the
* objects it looks up.
*/
public class JNDIObjectLocator {
protected Logger logger;
private InitialContext initialContext;
private Map<String, Object> jndiObjectCache = Collections.synchronizedMap(new HashMap<String, Object>());
public JNDIObjectLocator(Logger logger) {
this.logger = logger;
}
public synchronized void clear() {
jndiObjectCache.clear();
}
public Object getJNDIObject(String jndiName) {
Object jndiObject = jndiObjectCache.get(jndiName);
if (jndiObject == null && !jndiObjectCache.containsKey(jndiName)) {
try {
jndiObject = lookup(jndiName);
jndiObjectCache.put(jndiName, jndiObject);
}
catch (RuntimeException e) {
clear();
throw e;
}
}
return jndiObject;
}
private synchronized Object lookup(String name) {
// Recheck the cache because the name we're looking for may have been added while we were waiting for sync.
if (!jndiObjectCache.containsKey(name)) {
try {
return getInitialContext().lookup(name);
}
catch (NameNotFoundException e) {
clear();
throw new SystemUnavailableException(
"JNDI lookup failed for \"" + name
+ "\". Is ejb server not started? Has the ejb.provider property been specified correctly",
e);
}
catch (NamingException e) {
clear();
throw new SystemUnavailableException("JNDI lookup failed for \"" + name
+ "\". Is ejb server not started? If using jboss, is jbossall-client.jar missing from classpath?"
+ " Error looking up " + e.getRemainingName() + " because of " + e.getCause() + " while "
+ e.getExplanation(), e);
}
}
else {
return jndiObjectCache.get(name);
}
}
private synchronized InitialContext getInitialContext() {
if (initialContext == null) {
try {
EJBProviderEnum ejbProvider = EJBProviderUtil.detectEJBProvider(logger);
initialContext = new InitialContext();
// Glassfish 3.1.1 can't list context - see http://java.net/jira/browse/GLASSFISH-17220
if (ejbProvider != EJBProviderEnum.GLASSFISH_3_REMOTE) {
logger.info("InitialContext environment = " + initialContext.getEnvironment());
logger.info("InitialContext contains:");
listContext(" ", initialContext);
}
}
catch (NamingException e) {
clear();
throw new SystemUnavailableException("Cannot get initial context."
+ " Is JNDI server not started? If using wildfly, is jbossall-client.jar missing from classpath?"
+ " Error looking up " + e.getRemainingName() + " because of " + e.getCause() + " while "
+ e.getExplanation(), e);
}
}
return initialContext;
}
/**
* This is not essential, but it can be handy when things go wrong to have the objects in the context listed in the
* log.
*
* @param s
* @param c
* @throws NamingException
*/
private final void listContext(String s, Context c) throws NamingException {
NamingEnumeration<NameClassPair> pairs = c.list("");
for (; pairs.hasMoreElements();) {
NameClassPair p = pairs.next();
logger.info(s + "/" + p.getName() + " : " + p.getClassName());
try {
Object o = c.lookup(p.getName());
if (o instanceof Context) {
Context child = (Context) o;
listContext(s + "/" + p.getName(), child);
}
}
catch (Throwable t) {
// Not really a problem so just log it.
logger.debug(" " + t.getClass().getName() + ": " + t.getMessage());
}
}
}
}
package jumpstart.util;
public enum EJBProviderEnum {
OPENEJB_7_LOCAL, OPENEJB_7_REMOTE, WILDFLY_11_LOCAL, WILDFLY_11_REMOTE, GLASSFISH_3_LOCAL, GLASSFISH_3_REMOTE, TOMCAT_7_OPENEJB_7_LOCAL;
}
package jumpstart.util;
import org.slf4j.Logger;
public class EJBProviderUtil {
private static String PROPERTY_EJB_PROVIDER = "jumpstart.ejb-provider";
public static EJBProviderEnum detectEJBProvider(Logger logger) {
EJBProviderEnum ejbProvider = null;
String ejbProviderStr = null;
try {
ejbProviderStr = System.getProperty(PROPERTY_EJB_PROVIDER);
if (ejbProviderStr == null) {
throw new IllegalStateException("System property \"" + PROPERTY_EJB_PROVIDER
+ "\" not found. Please set it to one of: {" + getAllowedValuesAsStr() + "}.");
}
ejbProvider = EJBProviderEnum.valueOf(ejbProviderStr);
}
catch (IllegalStateException e) {
throw e;
}
catch (SecurityException e) {
throw new IllegalStateException("Failed to get system property \"" + PROPERTY_EJB_PROVIDER + "\": " + e);
}
catch (Exception e) {
throw new IllegalStateException("Found system property \"" + PROPERTY_EJB_PROVIDER + "\" equals \""
+ ejbProviderStr + "\", expected one of: {" + getAllowedValuesAsStr() + "}.");
}
return ejbProvider;
}
private static String getAllowedValuesAsStr() {
String valuesStr = "";
EJBProviderEnum[] values = EJBProviderEnum.values();
for (EJBProviderEnum ejbProviderEnum : values) {
valuesStr += "\"" + ejbProviderEnum.name() + "\", ";
}
return valuesStr.substring(0, valuesStr.lastIndexOf(","));
}
}
package jumpstart.business.commons.exception;
import jumpstart.business.MessageUtil;
@SuppressWarnings("serial")
public class SystemUnavailableException extends SystemException {
String symptom;
/**
* Throw this exception when the system becomes unavailable eg. due to database connection failure.
*/
public SystemUnavailableException(Throwable throwable) {
super(throwable);
}
/**
* Throw this exception when the system becomes unavailable eg. due to database connection failure.
*/
public SystemUnavailableException(String symptom, Throwable throwable) {
super(throwable);
this.symptom = symptom;
}
@Override
public String getMessage() {
String msg = MessageUtil.toText("SystemUnavailableException", symptom);
return msg;
}
public String getSymptom() {
return symptom;
}
}
package jumpstart.web.services;
import java.util.Map;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.Translator;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.beanvalidator.ClientConstraintDescriptor;
import org.apache.tapestry5.internal.beanvalidator.BaseCCD;
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.EagerLoad;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Primary;
import org.apache.tapestry5.ioc.annotations.Symbol;
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.ioc.services.ThreadLocale;
import org.apache.tapestry5.services.BeanBlockContribution;
import org.apache.tapestry5.services.ComponentRequestFilter;
import org.apache.tapestry5.services.DisplayBlockContribution;
import org.apache.tapestry5.services.EditBlockContribution;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.javascript.DataConstants;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
import org.apache.tapestry5.services.security.WhitelistAnalyzer;
import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
import org.apache.tapestry5.upload.services.UploadSymbols;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;
import org.slf4j.Logger;
import jumpstart.business.validation.constraints.Letters;
import jumpstart.util.JodaTimeUtil;
import jumpstart.web.translators.MoneyTranslator;
import jumpstart.web.translators.YesNoTranslator;
/**
* 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/5.3.4/tapestry-ioc/module.html
*/
public class AppModule {
private static final String UPLOADS_PATH = "jumpstart.upload-path";
@Inject
@Symbol(SymbolConstants.PRODUCTION_MODE)
@Property(write = false)
private static boolean productionMode;
// 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);
}
// Tell Tapestry about our custom translators and their message file.
// We do this by contributing configuration to Tapestry's TranslatorAlternatesSource service, FieldValidatorSource
// service, and ComponentMessagesSource service.
@SuppressWarnings("rawtypes")
public static void contributeTranslatorAlternatesSource(MappedConfiguration<String, Translator> configuration,
ThreadLocale threadLocale) {
configuration.add("yesno", new YesNoTranslator("yesno"));
configuration.add("money2", new MoneyTranslator("money2", 2, threadLocale));
}
public void contributeComponentMessagesSource(OrderedConfiguration<String> configuration) {
configuration.add("myTranslationMessages", "jumpstart/web/translators/TranslationMessages");
}
// Tell Tapestry about the client-side (javascript) validators that corresponds to each server-side Bean Validator.
public static void contributeClientConstraintDescriptorSource(final JavaScriptSupport javaScriptSupport,
final Configuration<ClientConstraintDescriptor> configuration) {
configuration.add(new BaseCCD(Letters.class) {
public void applyClientValidation(MarkupWriter writer, String message, Map<String, Object> attributes) {
javaScriptSupport.require("beanvalidation/letters");
writer.attributes(DataConstants.VALIDATION_ATTRIBUTE, true, "data-validate-letters", true,
"data-letters-message", message);
}
});
}
// Tell Tapestry about our custom ValueEncoders.
// We do this by contributing configuration to Tapestry's ValueEncoderSource service.
// @SuppressWarnings("rawtypes")
// public static void contributeValueEncoderSource(MappedConfiguration<Class, Object> configuration) {
// configuration.addInstance(Person.class, PersonEncoder.class);
// }
// Tell Tapestry which locales we support, and tell Tapestry to use its jQuery implementation for its JavaScript.
// We do this by contributing configuration to Tapestry's ApplicationDefaults service.
public static void contributeApplicationDefaults(MappedConfiguration<String, String> configuration) {
configuration.add(SymbolConstants.SUPPORTED_LOCALES, "en_US,en_GB,fr");
configuration.add(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER, "jquery");
}
// Tell Tapestry how to detect and protect pages that require security.
// 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<ComponentRequestFilter> configuration) {
configuration.addInstance("PageProtectionFilter", PageProtectionFilter.class);
}
// Tell Tapestry how to handle WildFly 11's classpath URLs - WildFly uses a "virtual file system".
// We do this by overriding Tapestry's ClasspathURLConverter service.
// See "Running Tapestry on JBoss" (sic) in http://wiki.apache.org/tapestry/Tapestry5HowTos .
@SuppressWarnings("rawtypes")
public static void contributeServiceOverride(MappedConfiguration<Class, Object> configuration) {
// configuration.add(ClasspathURLConverter.class, new ClasspathURLConverterJBoss7());
configuration.add(ClasspathURLConverter.class, new ClasspathURLConverterWildFly11());
}
// Tell Tapestry how to handle @EJB in page and component classes.
// We do this by contributing configuration to Tapestry's ComponentClassTransformWorker service.
// - Based on http://wiki.apache.org/tapestry/JEE-Annotation.
@Primary
public static void contributeComponentClassTransformWorker(
OrderedConfiguration<ComponentClassTransformWorker2> configuration) {
configuration.addInstance("EJB", EJBAnnotationWorker.class, "before:Property");
}
// Tell Tapestry how to handle pages annotated with @WhitelistAccessOnly, eg. Tapestry's ServiceStatus and
// PageCatalog.
// The default WhitelistAnalyzer allows localhost only and only in non-production mode.
// Our aim is to make the servicestatus page available to ALL clients when not in production mode.
// We do this by contributing our own WhitelistAnalyzer to Tapestry's ClientWhitelist service.
public static void contributeClientWhitelist(OrderedConfiguration<WhitelistAnalyzer> configuration) {
if (!productionMode) {
configuration.add("NonProductionWhitelistAnalyzer", new WhitelistAnalyzer() {
@Override
public boolean isRequestOnWhitelist(Request request) {
if (request.getPath().startsWith("/core/servicestatus")) {
return true;
}
else {
// This is copied from org.apache.tapestry5.internal.services.security.LocalhostOnly
String remoteHost = request.getRemoteHost();
return remoteHost.equals("localhost") || remoteHost.equals("127.0.0.1")
|| remoteHost.equals("0:0:0:0:0:0:0:1%0") || remoteHost.equals("0:0:0:0:0:0:0:1");
}
}
}, "before:*");
}
}
// Tell Tapestry how to build our Filer service (used in the FileUpload example).
// Annotate it with EagerLoad to force resolution of symbols at startup rather than when it is first used.
@EagerLoad
public static IFiler buildFiler(Logger logger, @Inject @Symbol(UPLOADS_PATH) final String uploadsPath,
@Inject @Symbol(UploadSymbols.FILESIZE_MAX) final long fileSizeMax) {
return new Filer(logger, UPLOADS_PATH, uploadsPath, UploadSymbols.FILESIZE_MAX, fileSizeMax);
}
// Tell Tapestry how to coerce Joda Time types to and from Java Date types for the TypeCoercers example.
// We do this by contributing configuration to Tapestry's TypeCoercer service.
// - Based on http://tapestry.apache.org/typecoercer-service.html
@SuppressWarnings("rawtypes")
public static void contributeTypeCoercer(Configuration<CoercionTuple> configuration) {
// From java.util.Date to DateMidnight
Coercion<java.util.Date, DateMidnight> toDateMidnight = new Coercion<java.util.Date, DateMidnight>() {
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<DateMidnight, java.util.Date> fromDateMidnight = new Coercion<DateMidnight, java.util.Date>() {
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<java.util.Date, LocalDate> toLocalDate = new Coercion<java.util.Date, LocalDate>() {
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<LocalDate, java.util.Date> fromLocalDate = new Coercion<LocalDate, java.util.Date>() {
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));
}
// Tell Tapestry how its BeanDisplay and BeanEditor can handle the JodaTime types.
// We do this by contributing configuration to Tapestry's DefaultDataTypeAnalyzer and BeanBlockSource services.
// - Based on http://tapestry.apache.org/beaneditform-guide.html .
public static void contributeDefaultDataTypeAnalyzer(
@SuppressWarnings("rawtypes") MappedConfiguration<Class, String> configuration) {
configuration.add(DateTime.class, "dateTime");
configuration.add(DateMidnight.class, "dateMidnight");
configuration.add(LocalDateTime.class, "localDateTime");
configuration.add(LocalDate.class, "localDate");
configuration.add(LocalTime.class, "localTime");
}
public static void contributeBeanBlockSource(Configuration<BeanBlockContribution> configuration) {
configuration.add(new DisplayBlockContribution("dateTime", "infra/AppPropertyDisplayBlocks", "dateTime"));
configuration
.add(new DisplayBlockContribution("dateMidnight", "infra/AppPropertyDisplayBlocks", "dateMidnight"));
configuration
.add(new DisplayBlockContribution("localDateTime", "infra/AppPropertyDisplayBlocks", "localDateTime"));
configuration.add(new DisplayBlockContribution("localDate", "infra/AppPropertyDisplayBlocks", "localDate"));
configuration.add(new DisplayBlockContribution("localTime", "infra/AppPropertyDisplayBlocks", "localTime"));
configuration.add(new EditBlockContribution("dateMidnight", "infra/AppPropertyEditBlocks", "dateMidnight"));
configuration.add(new EditBlockContribution("localDate", "infra/AppPropertyEditBlocks", "localDate"));
}
}