In JavaEE the throttling is often done using a stateless bean cause they are by designed pooled and the pool provide a contention point. This is however IMO a workaround more than a solution for the throttling need and a small CDI extension can be worth it.
Tag Archives: javaee
CDI: replace the configuration by a register pattern
CDI doesn’t really have a configuration file. Of course the beans.xml is used to activate few features like interceptors but you can’t register a bean in it, can’t add a qualifier on a bean etc…
When it comes to writing a CDI library the question of the configuration hits you pretty quickly. Let see how to solve it with a not very complicated pattern making users life really nicer.
JSF/Primefaces and session timeout login redirection
If you use JSF and Primefaces you can encouter the case where your session expired and the next action your user does is an Ajax request. If you configured a form login then the ajax request will get the form redirection as expected but…it is an ajax call so your user will see nothing basically excepted an irresponsive GUI.
To work around it you can implement a custom PhaseListener checking if the request is an ajax request redirected to the login page and if so enforce the redirection through JSF API.
Chunking and global report using JTA
If you have a batch processing records in chunks you probably want to keep track of what succeeds and fails. The issue is the commit is often done after your business code is executed which means you kind of loose track of what happens.
To solve it you can use TransactionSynchronizationRegistry and Synchronizations.
JavaEE and Swagger: TomEE example
More and more applications are composed of REST services. In JavaEE land it means you develop and expose JAX-RS services.
Once developped and well tested with TomEE the first thing you will realize is that to make an API useful you need to document it. There are a lot of ways to do it but Swagger seems to be the trendy one and it is indeed a nice solution as we’ll see in this post.
CDI Mapper: get rid of the proxy layer!
In a recent post (https://rmannibucau.wordpress.com/2015/12/01/write-your-own-cdi-extension-for-bean-mapping/) I explained how to implement a simple mapper with CDI integration. We can actually make it simpler leveraging on CDI a bit more.
DeltaSpike configuration: read where you want and decrypt passwords
DeltaSpike configuration: read where you want and decrypt passwords
DeltaSpike configuration is a very elegant configuration solution for CDI.
However to make it fitting your application you often need to integrate it:
- to read the configuration from the source/location you desire
- to use a custom algorithm to decrypt passwords or sensitive data
Read your own configuration file
There are generally three cases to add a custom configuration file:
- respect a company convention
- read it from outside the application (in ${tomee.base}/conf for instance ;))
- read a custom format (yaml, xml, …)
In this post we will tackle the second one since mixing the last two solves generally the first one and the last one is mainly the same solution with some specific conversion logic I don’t want to enter in for this post.
So our goal will be to read the configuration from ${catalina.base}/conf/my-app.properties and add it in deltaspike properties.
To do so we just need deltaspike core:
<dependency> <groupId>org.apache.deltaspike.core</groupId> <artifactId>deltaspike-core-api</artifactId> <version>${deltaspike.version}</version> </dependency> <dependency> <groupId>org.apache.deltaspike.core</groupId> <artifactId>deltaspike-core-impl</artifactId> <version>${deltaspike.version}</version> </dependency>
Then we need to implement a custom org.apache.deltaspike.core.spi.config.ConfigSource
reading ${catalina.base} from the corresponding system properties (our implementation will have a fallback on openejb.base property for openejb embedded tests):
import org.apache.deltaspike.core.impl.config.PropertiesConfigSource; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Properties; // uses ${base}/conf/my-app.properties as source public class MyConfigSource extends PropertiesConfigSource { public MyConfigSource() { super(loadProperties()); } public String getConfigName() { return "MyAppConfig"; } private static Properties loadProperties() { return new Properties() {{ final File config = new File( System.getProperty("catalina.base", System.getProperty("openejb.base", "")), "conf/my-app.properties"); if (config.isFile()) { try (final InputStream is = new BufferedInputStream(new FileInputStream(config))) { load(is); } catch (final IOException e) { throw new IllegalArgumentException(e); } } }}; } }
Then to “activate” it just create a META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource
containing our qualified class name.
Decrypt passwords with your own algorithm
To decrypt password DeltaSpike uses org.apache.deltaspike.core.spi.config.ConfigFilter
implementations. It has two methods:
- filterValue: actual decryption
- filterValueForLog: decryption for logging, in general I just log “xxxxxx” if my filter handles the value
For this post the decryption will just reverse the value but a real implementation can use any ciphering considered secured in your environment:
import org.apache.deltaspike.core.spi.config.ConfigFilter; public class MyConfigFilter implements ConfigFilter { @Override public String filterValue(final String key, final String value) { return isEncrypted(key) ? decrypt(value) : value; } @Override // filter passwords and secrets in logs public String filterValueForLog(final String key, final String value) { return isEncrypted(key) ? "xxxxxx" : value; } // for the sample just "reverse" the string but in real life use some encryption private String decrypt(final String value) { return new StringBuilder(value).reverse().toString(); } private boolean isEncrypted(final String key) { return key.contains("password") || key.contains("secret"); } }
As for ConfigSource and since this classes are used before CDI is started to configure DeltaSpike itself don’t forget to register the filter adding the fully qualified name in META-INF/services/org.apache.deltaspike.core.spi.config.ConfigFilter
.
Now if you set for instance in your configuration:
my.password = tset
And get my.password
injected:
@Inject @ConfigProperty(name = "my.password") private String pwd;
Then pwd
value will be test
:).
Conclusion
The code of this post can be found there: https://github.com/rmannibucau/deltaspike-config-example.
The interesting part is to understand deltaspike can be integrated with all kind of configuration and environment which is the main feature of a configuration API. Then you still get it integrated with CDI for free thanks to DeltaSpike @ConfigProperty
which makes your application simple and decoupled from your actual configuration system.
Write your own CDI extension for bean mapping
CDI descriptive bean mapping: how to write a CDI extension to map beans
The idea of this post is to show you how to end up with a CDI extension allowing you to get injected a mapper defined only doing this:
@Mapper public interface MyMapper { @Mapping(source = "inputId", target = "id") @Mapping(source = "employeeId") Output1 toOutput1(final Input2 input); @Mapping(source = "id") @Mapping(source = "name", target = "firstName") Output2 toOutput2(final Input1 input); }
Of course the API is very (very) close to mapstruct one and this post doesn’t intend to go that far but the difference is that the extension will all be built for runtime analysis using CDI. Said otherwise it is more dynamic and usable in real projects when you want a declarative API.
First define the API
The API is pretty straight forward:
@Mapper
is marking an interface as a mapper – this could be optional but makes code cleaner IMO@Mapping
is a repeatable annotation defining which field – source – is read in the input (parameter) and which field – target – is set in the output (returned type). Small sugar there, if source and target are equals, target is optional.
Since this is just defining three annotations I’ll just paste the code there:
@Target(TYPE) @Retention(RUNTIME) public @interface Mapper { } @Repeatable(Mappings.class) @Target(METHOD) @Retention(RUNTIME) public @interface Mapping { String source(); String target() default ""; } @Target(METHOD) @Retention(RUNTIME) public @interface Mappings { Mapping[] value(); }
Creating instances from the interfaces
So how to create an instance of a bean if we have such an interface? Just reading all metadata and creating a proxy!
Creaying a proxy is as simple as calling:
final MyMapper mapper = (MyMapper) Proxy.newProxyInstance(contextClassLoader, new Class<?>{} { MyMapper.class }, handler);
So the obvious thing is we need a handler able to do the conversion on each method invocation.
It is done implementing java.lang.reflect.InvocationHandler
. For this post implementation, the MapperHandler
will read from an AnnotatedType
the metadata (annotations) to build its runtime model (used to actually do the mapping) and an AtomicReference
since our implementation will just abstract the coercing of types to not make this post too long.
The idea is to build a model with a map of reader/writer pairs which will get used to map input to the output:
public class MapperHandler implements InvocationHandler { private final Map<Method, MappingMethod> mapping; private final AtomicReference<Converter> converter; public <T> MapperHandler(final AnnotatedType<Object> type, final AtomicReference<Converter> converter) { this.mapping = type.getMethods().stream() .filter(m -> m.isAnnotationPresent(Mappings.class) && m.getParameters().size() == 1) .collect(toMap(AnnotatedMethod::getJavaMember, MappingMethod::new)); this.converter = converter; } @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class) { try { return method.invoke(this, args); } catch (final InvocationTargetException ite) { throw ite.getCause(); } } return mapping.get(method).map(args[0]); } private class MappingMethod { private final Class<?> from; private final Class<?> to; private final Map<Reader, Writer> mapping; public MappingMethod(final AnnotatedMethod<?> annotatedMethod) { if (annotatedMethod.getParameters().size() != 1) { throw new IllegalArgumentException("Mapping method needs to have one parameter."); } from = Class.class.cast(annotatedMethod.getParameters().iterator().next().getBaseType()); to = annotatedMethod.getJavaMember().getReturnType(); mapping = Stream.of(annotatedMethod.getAnnotation(Mappings.class).value()) // can be extended to support field access .collect(toMap(m -> new Reader() { private final Method method = findMethod(from, mtd -> mtd.getName().equals("get" + toUppercase(m.source())) && mtd.getParameterCount() == 0, m.source()); @Override public Object get(final Object instance) { try { return method.invoke(instance); } catch (final IllegalAccessException e) { throw new IllegalStateException(e); } catch (final InvocationTargetException e) { throw new IllegalStateException(e.getCause()); } } }, m -> new Writer() { private final Method method = findMethod(to, mtd -> mtd.getName().equals("set" + toUppercase(targetField())) && mtd.getParameterCount() == 1, targetField()); @Override public void set(final Object instance, final Object value) { try { final Converter converter = MapperHandler.this.converter.get(); final boolean convert = !(converter == null || method.getParameterTypes()[0].isInstance(value)); method.invoke(instance, convert ? converter.to(value, method.getParameterTypes()[0]) : value); } catch (final IllegalAccessException e) { throw new IllegalStateException("error invoking " + method, e); } catch (final InvocationTargetException e) { throw new IllegalStateException("error invoking " + method, e.getCause()); } } private String targetField() { return m.target().isEmpty() ? m.source() : m.target(); } })); } public Object map(final Object args) { if (!from.isInstance(args)) { throw new IllegalArgumentException(args + " not an instance of " + from); } try { final Object newInstance = to.newInstance(); mapping.forEach((r, w) -> ofNullable(r.get(args)).ifPresent(v -> w.set(newInstance, v))); return newInstance; } catch (final IllegalAccessException | InstantiationException e) { throw new IllegalStateException(e); } } } private static String toUppercase(final String m) { return Character.toUpperCase(m.charAt(0)) + (m.length() == 1 ? "" : m.substring(1)); } private static Method findMethod(final Class<?> type, final Predicate<Method> matcher, final String name) { for (final Method m : type.getMethods()) { if (matcher.test(m)) { return m; } } throw new IllegalArgumentException("Missing " + name); } @FunctionalInterface private interface Reader { Object get(Object instance); } @FunctionalInterface private interface Writer { void set(Object instance, Object value); } }
Be able to register our proxy as a CDI Bean
To be able to add an “implementation” to CDI context we need to wrap our proxy in a javax.enterprise.inject.spi.Bean
.
The implementation is straight forward and starts from the same input parameter as our handler:
public class MapperBean<T> implements Bean<T> { private final Set<Type> types; private final Set<Annotation> qualifiers; private final Class<T> clazz; private final Class<?>[] proxyTypes; private final MapperHandler handler; public MapperBean(final AnnotatedType at, final AtomicReference<Converter> converter) { clazz = at.getJavaClass(); types = new HashSet<>(asList(clazz, Object.class)); qualifiers = new HashSet<>(asList(DefaultLiteral.INSTANCE, AnyLiteral.INSTANCE)); proxyTypes = new Class<?>[] { clazz }; handler = new MapperHandler(at, converter); } @Override public Set<Type> getTypes() { return types; } @Override public Set<Annotation> getQualifiers() { return qualifiers; } @Override public Class<? extends Annotation> getScope() { return ApplicationScoped.class; } @Override public String getName() { return null; } @Override public boolean isNullable() { return false; } @Override public Set<InjectionPoint> getInjectionPoints() { return emptySet(); } @Override public Class<?> getBeanClass() { return clazz; } @Override public Set<Class<? extends Annotation>> getStereotypes() { return emptySet(); } @Override public boolean isAlternative() { return false; } @Override public T create(final CreationalContext<T> context) { final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); return (T) Proxy.newProxyInstance( contextClassLoader == null ? ClassLoader.getSystemClassLoader() : contextClassLoader, proxyTypes, handler); } @Override public void destroy(final T instance, final CreationalContext<T> context) { // no-op } }
Things to note are:
- We scoped our implementation
@ApplicationScoped
since the proxy is stateless - Most of methods are using default values since our proxy doesn’t need any injection or specific model
- We set the
@Default
and@Any
qualifiers to be able to retrieve our implementation without any specific qualifiers
Wire it all in an extension
Now all our implementation is ready we just need to make it real in a CDI extension (dont forget to register it in META-INF/services/javax.enterprise.inject.spi.Extension).
This extension will be responsible to capture mapper interface types and register the MapperBean
to make them available in CDI context.
This sample implementation of this extension handles the retrieval of an optional Converter
if you want to plug some advanced coercing for type conversion:
public class MapperExtension implements Extension { private final Collection<AnnotatedType<?>> detectedMappers = new ArrayList<>(); private final AtomicReference<Converter> converterRef = new AtomicReference<>(); void captureMapper(@Observes final ProcessAnnotatedType<?> potentialMapper) { final AnnotatedType<?> annotatedType = potentialMapper.getAnnotatedType(); if (annotatedType.isAnnotationPresent(Mapper.class)) { detectedMappers.add(annotatedType); } } void addMapperBeans(@Observes final AfterBeanDiscovery abd) { detectedMappers.stream().forEach(at -> abd.addBean(new MapperBean(at, converterRef))); detectedMappers.clear(); } void findConverter(@Observes final AfterDeploymentValidation adv, final BeanManager beanManager) { final Set<Bean<?>> beans = beanManager.getBeans(Converter.class); final Bean<?> bean = beanManager.resolve(beans); // converter should be normal-scoped otherwise we need to release the creational context when shutdown event is fired ofNullable(bean).ifPresent(b -> converterRef.set(Converter.class.cast(beanManager.getReference(bean, Converter.class, null)))); } }
Use your CDI Mapper extension!
Now suppose you deploy your extension with the initial sample of this post, then you can simply use it as in this example:
@Path("test") @ApplicationScoped public class MyEndpoint { @Inject private MyMapper mapper; @Inject private MyService service; @GET @Path("{id}") public Output1 findOutput(@PathParam("id) String id) { return mapper.toOutput1(service.findInput2(id)); } }
What is nice about such a solution – this includes mapstruct 🙂 – is you define your mapping in a well defined place. This means the behavior is well defined and dedicated to the mapping which avoid a lot of boilerplate code on one side and makes it easy to understand and maintain on the other side. The awesome CDI feature is thanks to AnnotatedType
you can change the mapping dynamically and programmatically if you need without hanging the mapper (if they don’t belong to your own codebase for instance).
Happy mapping!
CDI Context: it is possible without scope annotations in your API!
If you never implemented a CDI context/scope it is a simple as implementing this interface:
public interface Context { Class<? extends Annotation> getScope(); <T> T get(Contextual<T> component, CreationalContext<T> creationalContext); <T> T get(Contextual<T> component); boolean isActive(); }
Note: in CDI 1.1 there is AlterableContext too which just adds a destroy(Contextual) method which is not important for this post so I will ignore it but I would recommand you to use it instead of Context if you can rely on CDI 1.1.
The Context implementation is quite simple:
- isActive() returns true if the context is usable by the CDI container
- getScope() returns the associated annotation (often @XXXScoped)
- get(Contextual) returns the instance of the Contextual (~= Bean) for “current” context
- get(Contextual, CreationalContext) creates or returns current instance
Creating a scope “annotation” is as easy as creating a runtime annotation:
// @NormalScope(passivating=false) @Target({ METHOD, TYPE, FIELD }) @Retention(RUNTIME) public @interface WrappingMethodScoped { }
Note: the @NormalScope is optional since it can be done by an extension – this is what we’ll do.
Now we know what is a CDI scope let see how to activate it programmatically.
BatchEE: avoid CDI integration issues
If you use BatchEE as JBatch implementation with a EE container which doesn’t integrate directly with it you can get some surprises like not using the right bean manager or just getting errors about CDI context.
This is because by default BatchEE uses its own pool of threads as needed by the spec but then in these threads CDI is not initialized and the lazy lookup of the bean manager done by BatchEE to avoid to use a “startup” bean manager at runtime in some – expensive – containers can fail cause of it.