Integrate 3rd party library with CDI, part 1: what are the challenges? Shiro case!
Integrating a third party library with CDI - or developping a CDI support for a library - can be done in two ways:
- cheap: just provide a lookup solution to get CDI beans but keep the framework configuration
- complete: make CDI the first class citizen of the framework and bring the framework to CDI
Both solutions are valid even if drastically opposed.
In this post serie we'll investigate the last one since the first one is generally "easy".
One example: Apache Shiro
Before starting with code snippets, let's use this first post to really understand the difference between both.
Let's have a look to a common way to setup and use Apache Shiro before adding CDI into the game:
- you add the needed dependencies (shiro-web for instance). This part is one which will not change with or without CDI.
- you configure the web integration through web.xml add shiro filter and environment intializer
- you configure shiro itself in shiro.ini
- you use the programmatic API or annotation API to validate the user (Subject in Shiro semantic) context
Shiro configuration
Here is a sample for shiro.ini (taken from shiro master):
[main]
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionManager.sessionIdUrlRewritingEnabled = false
securityManager.sessionManager = $sessionManager
securityManager.cacheManager = $cacheManager
[urls]
/** = authcBasic[permissive]
[users]
root = secret,admin
guest = guest,guest
presidentskroob = 12345,president
darkhelmet = ludicrousspeed,darklord,schwartz
lonestarr = vespa,goodguy,schwartz
[roles]
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5
What do we observe?
- The main part defines the wiring of the runtime. This is a shiro specific IoC.
- The other parts just configure some special beans (in real life users/roles are not in this file but in a database or ldap for instance)
So what would it mean to migrate it to CDI? After previous analyzis we identify that CDI integration will happen mainly at [main] part. The first challenge will be to use CDI as the main IoC for Shiro and not rely on a custom one (the one Shiro built on top of shiro.ini).
If you pause a second and check the proposed model in spring you will quickly see it is close to that philosophy:
@Configuration
@Import({ShiroBeanConfiguration.class})
public class ShiroConfiguration extends AbstractShiroConfiguration {
@Bean
@Override
protected SessionsSecurityManager securityManager(List<Realm> realms) {
return super.securityManager(realms);
}
@Bean
@Override
protected SessionManager sessionManager() {
return super.sessionManager();
}
@Bean
@Override
protected SubjectDAO subjectDAO() {
return super.subjectDAO();
}
@Bean
@Override
protected SessionStorageEvaluator sessionStorageEvaluator() {
return super.sessionStorageEvaluator();
}
@Bean
@Override
protected SubjectFactory subjectFactory() {
return super.subjectFactory();
}
@Bean
@Override
protected SessionFactory sessionFactory() {
return super.sessionFactory();
}
@Bean
@Override
protected SessionDAO sessionDAO() {
return super.sessionDAO();
}
@Bean
@Override
protected Authorizer authorizer() {
return super.authorizer();
}
@Bean
@Override
protected AuthenticationStrategy authenticationStrategy() {
return super.authenticationStrategy();
}
@Bean
@Override
protected Authenticator authenticator() {
return super.authenticator();
}
@Bean
@Override
protected RememberMeManager rememberMeManager() {
return super.rememberMeManager();
}
}
All the goal of shiro.ini is to build a Shiro SecurityManager fully intiialized. Using CDI as backbone just consists to build it based on CDI beans.
Shiro usage
Once you have a SecurityManager and it is initialized properly (I'll skip the ThreadContext setup there since it is very specific to Shiro and far from our original topic), you can use the programmatic or annotation based API:
@ApplicationScoped
public class Service {
@RequiresRoles("admin")
public Result stopBatch(BatchId id) {
// ...
}
}
What's the challenge there in CDI? Shiro not being CDI integrated you need an @InterceptorBinding which means the actual service will look like:
@ApplicationScoped
public class BatchService {
@Shiro
@RequiresRoles("admin")
public Result stopBatch(BatchId id) {
// ...
}
}
Adding this marker will slowly result in a lot of boilerplate (suppose you use multiple frameworks for the same method).
Here is our second challenge: avoid to require the user to use other annotations.
Conclusion
Integrating with CDI a third party library has mainly two challenges:
- replace the library initialization by CDI using CDI beans directly and avoiding any custom configuration not integrated to CDI or requiring some specific files
- avoid to add new API/annotations
Next posts will deal with these two aspects still using Shiro example.
From the same author:
In the same category: