apache deltaspike the cdi toolbox (java one 2015)
TRANSCRIPT
ApacheDeltaSpike-theCDItoolbox
AntoineSabot-Durand·RafaelBenevides
RafaelBenevides
DeltaSpikeP.M.CmemberRedHat,[email protected]/rafabene
AntoineSabot-Durand
CDIspecleadRedHat,Inc.@antoine_sdnext-presso.comgithub.com/antoinesd
ShouldIstayorshouldIgo?
AtalkaboutCDIeco-system
Don’tneedtobeaCDIguru
ButyouneedtoknowCDI
@Inject @ProducesEvent<T> @Observes@Qualifier InjectionPoint
ShouldIstayorshouldIgo?
Ifyouknowthemostoftheseyoucanstay
Agenda
WhatisDeltaSpike?CoreModuleOtherDeltaSpikeModulesQuestion&Answers
Slidesavailableatrafabene.github.io/deltaspike-cdi-toolbox/
WhatisDeltaSpike?
Wheredoesitcomefrom?
AbitofhistoryDec2011:projectlaunchFeb2012:version0.1May2013:version0.4(outofincubator)June2014:version1.0August2015:version1.5
CDI&DeltaSpike
CDIisaspecification.Itdoesn’tprovidebusinessfeatures
butitincludesapowerfulhooktoaddthesebusinessfeatures
The"Portableextensions"featureisthishook
Thankstoit,CDIcanbeeasilyenhancedwithnewhighlevelfeatures
CDIPortableextensions
OneofthemostpowerfulfeatureoftheCDIspecification
Notreallypopularized,partlydueto:
1. Theirhighlevelofabstraction2. ThegoodknowledgeonBasicCDIandSPI3. Lackofinformation(CDIisoftenreducedtoabasicDIsolution)
Extensions,whatfor?
Tointegrate3rdpartylibraries,frameworksorlegacycomponents
Tochangeexistingconfigurationorbehavior
ToextendCDIandJavaEE
Thankstothem,JavaEEcanevolvebetweenmajorreleases
Extensions,how?
ObservingSPIeventsatboottimerelatedtothebeanmanagerlifecycle
Checkingwhatmeta-dataarebeingcreated
Modifyingthesemeta-dataorcreatingnewones
Moreconcretely
Serviceprovideroftheservicejavax.enterprise.inject.spi.Extension declaredinMETA-INF/services
Justputthefullyqualifiednameofyourextensionclassinthisfile
import javax.enterprise.event.Observes;import javax.enterprise.inject.spi.Extension;
public class CdiExtension implements Extension {
void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd) { } //...
void afterDeploymentValidation(@Observes AfterDeploymentValidation adv) { }}
Internal Step Happen Once Loop on Elements
Beanmanagerlifecycle
DeploymentStart
BeforeBean
Discovery
ScanArchive
ProcessAnnotated
Type
AfterType
Discovery
BeanEligibility
Check
ProcessInjection
Point
ProcessInjectionTarget
ProcessBean
Attributes
ProcessBean
ProcessProducer
ProcessObserverMethod
AfterBean
Discovery
AfterDeploymentValidation
ApplicationRunning
BeforeShutdown
UndeployApplication
Example:IgnoringJPAentities
ThefollowingextensionpreventsCDItomanageentities
Thisisacommonlyadmittedgoodpractice
public class VetoEntity implements Extension {
void vetoEntity(@Observes @WithAnnotations(Entity.class) ProcessAnnotatedType<?> pat) { pat.veto(); }}
ExtensionsarelaunchedduringbootstrapandarebasedonCDIevents
Oncetheapplicationisbootstrapped,theBeanManagerisinread-onlymode(noruntimebeanregistration)
Youonlyhaveto@Observes built-inCDIeventstocreateyourextensions
Remember
ApacheDeltaSpikeis…
Acollectionofreadytouseextensionstohelpyouinyourprojects
AtoolboxtohelpyoudevelopnewCDIportableextensions
Agreatwaytolearnhowtodevelopyourownextensionbybrowsingthesourcecode
ThemostobviousentrypointtoCDIeco-system
DeltaSpikeistestedwithCDI1.0,1.1,1.2and2.0JBossWeldandApacheOpenWebBeansJBossAS7.x,WildFly8.x-10.xJBossEAP6.x-7.xApacheTomEE1.0.x-1.7.xOracleGlassFish3.x,4.xOracleWeblogic12cIBMWebsphere8.x
DeltaspikeisforallCDIdevelopers
Whilethistalkisfocusedonclassicalprojectdevelopers…
…advanceddevelopersmayfindinterestinghelpersinDeltaspike
Forinstancemetadatabuilderareusefulforportableextensiondevelopers
public void registerGenericBeans(@Observes AfterBeanDiscovery abd) { BeanBuilder<User> ubb = new BeanBuilder<User>(beanManager).readFromType(User.class) .passivationCapable(true) .addTypes(otherTypes); if (weAreOnWeb) ubb.scope(SessionScoped.class); else ubb.scope(ApplicationScoped.class); abd.addBean(ubb.create());}
MoreonDeltaSpike
ApacheDeltaSpikereceivedDuke’schoiceaward2014
Thistalkshowsonlyasmallpartoftheframework
Moreinfoon:deltaspike.apache.org/
Modulesanddependencies
CoreModule
Core-ExceptionHandlerpublic class InventoryActions { @PersistenceContext private EntityManager em;
@Inject private Event<ExceptionToCatchEvent> catchEvent;
public Integer queryForItem(Item item) { try { Query q = em.createQuery("SELECT i from Item i where i.id = :id"); q.setParameter("id", item.getId()); return q.getSingleResult(); } catch (PersistenceException e) {
catchEvent.fire(new ExceptionToCatchEvent(e)); } }}
TheEventofgenerictypeExceptionToCatchEventisinjectedintoyourclassforuselaterwithinatry/catchblock.
TheeventisfiredwithanewinstanceofExceptionToCatchEventconstructedwiththeexceptiontobehandled.
1
2
1
2
Core-ExceptionHandler
Exceptionsarehandledasynchronously.
@ExceptionHandler public class MyHandlers {
void printExceptions(@Handles ExceptionEvent<Throwable> evt) { System.out.println("Something bad happened:" + evt.getException().getMessage());
evt.handleAndContinue(); }}
Exceptionhandlermethodsareregisteredonbeansannotatedwith@ExceptionHandler
The@Handlesannotationonthefirstparameterdesignatesthismethodasanexceptionhandler.
Thishandlerdoesnotmodifytheinvocationofsubsequenthandlers,asdesignatedbyinvokinghandleAndContinue().
1
2
3
1
2
3
Core-Type-safeProjectStage
ThecurrentProjectStagecanbeinjected.
@Injectprivate ProjectStage projectStage;
//...
boolean isDevelopment = ProjectStage.Development.equals(this.projectStage);
YoucanalsousetheProjectStageatXHTMLfiles.
<h:panelGroup layout="block"rendered="#{applicationConfig.projectStage == 'Development'}" > <!-- HTML Snippet is shown only in Development stage --></h:panelGroup>
Core-Type-safeProjectStage
DeltaSpikecomeswiththefollowingpre-definedProjectStages:
1. UnitTest2. Development3. SystemTest4. IntegrationTest5. Staging6. Production
ButyoucancreateyourowncustomProjectStages.
Core-ProjectStageConfiguration
ItcanbesetusingDeltaSpikeConfigurationMechanism
-D org.apache.deltaspike.ProjectStage=Development
HowtoprovidetheseKey/ValuestoDeltaSpike?
1. Systemproperties2. Environmentproperties3. JNDIvalues-thebasenameis"java:comp/env/deltaspike/"4. Propertiesfilevalues-defaultfilenameis"META-INF/apache-
deltaspike.properties"
Core-DeltaSpikeConfigurationMechanismConfigurationAPI
String userName = ConfigResolver.getPropertyValue("user.name");
String dbUserName = ConfigResolver.getProjectStageAwarePropertyValue("db.username"); Integer dbPort = ConfigResolver
.resolve("db.port") .as(Integer.class) .withProjectStage(true) .withDefault(3306) .getValue();
Date deadline = ConfigResolver.resolve("project.deadline") .as(Date.class, new CustomDateConverter()).getValue());
Properties(Key/Value)
user.name = "Rafael"
db.username.Production = "Antoine"
db.username.Development = "Benevides"
db.port = 1234
project.deadline = 2017-04-01
12
3
4
12
23
4
Core-DeltaSpikeConfigurationMechanismInjectionofconfiguredvaluesintobeansusing@ConfigProperty@ApplicationScopedpublic class SomeRandomService{ @Inject @ConfigProperty(name = "endpoint.poll.interval") private Integer pollInterval;
@Inject @ConfigProperty(name = "endpoint.poll.servername") private String pollUrl;
... }
Core-Messagesandi18n
Type-safemessages-Beancreation
@Named("msg")@MessageBundlepublic interface MyMessages {
public String welcome();
public String welcomeTo(String username);
@MessageTemplate("{custom_message}") public String message();}
inthemessagebundle:welcometo=Welcometo%s
inthemessagebundle:custom_message=DeltaSpikeisawesome!
1
2
1
2
Core-Messagesandi18n
NowthemessagesbeanisreadytobeusedinJavaClasses
@Injectprivate MyMessages messages;//new FacesMessage(messages.welcomeTo("Rafael"));log.info(messages.message());
…oreveninsideJSP/JSFbecauseitusesa@Namedannotation.
<h1>#{msg.welcome}</h1>
Itusesthe“partialbean”moduletodynamicallycreateimplementationatruntime.
Core-@Exclude
ExcludingaBeaninanyCase@Excludepublic class NoBean{ }
ExcludingaBeaninCaseofProjectStageDevelopment@Exclude(ifProjectStage = ProjectStage.Development.class)public class MyBean{ }
ExcludingaBeaniftheProjectStageisdifferentfromDevelopment@Exclude(exceptIfProjectStage = ProjectStage.Development.class)public class MyDevBean{ }
ExcludingaBeanbasedonanExpressionwhichEvaluatestoTrue@Exclude(onExpression = "db==prodDB")public class DevDbBean { }
Core-InjectingResources
DeltaSpikehassimpleAPIsforperformingbasicresourceloadingandpropertyfilereading.
@Inject@InjectableResource("myfile.properties")private InputStream is;
public String getVersion() throws IOException { try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { return br.readLine(); }}
TheInjectableResourceProviderinterfacecanbeimplementedtoallowreadingfromalternatesourcesifneeded.
DataModule
DataModule Datamoduleisanimplementationoftherepositorypattern.
AtthemomentitonlysupportRDBMSthruJPA.
Butitcouldbeextendedtosupportotherdataservices.
“ "ARepositoryrepresentsallobjectsofacertaintypeasaconceptualset.
Itactslikeacollection,exceptwithmoreelaboratequeryingcapability."DomainDrivenDesign
—EricEvans
Repositorypattern
DataModule-CreatingaRepository@Repositorypublic interface UserRepository extends EntityRepository<User, Long> {/* DeltaSpike creates a proxy which implements:
Long count();List<E> findAll();E findBy(PK);void flush();void refresh();void remove(E);E save(E);E saveAndFlush(E);
...and many others */}
Itusesthe“partialbean”moduletodynamicallycreateimplementationatruntime.
DataModule-Makingqueries@Repositorypublic interface UserRepository extends EntityRepository<User, Long> {
public User findByUsernameAndPassword(String username, char[] password);
@Query("SELECT u FROM User AS u WHERE u.role in (?1)") public List<Role> findByRoles(List<Role> roles);
}
Thenameofthemethodautomaticallycreatesthequery.Example:"SELECTuFROMUseruWHEREu.username=?1ANDu.password=?2"
Thequeryisdefinedinsidethe@Queryannotation.
1
2
1
2
DataModule-Pagination@Repositorypublic interface UserRepository extends EntityRepository<User, Long> {
@Query("select p from Person p where p.age between ?1 and ?2") QueryResult<Person> findAllByAge(int minAge, int maxAge);
}
QueryResult<Person> paged = personRepository.findByAge(age)
// Query API stylepaged.maxResults(10).firstResult(50).getResultList();
// or paging stylepaged.withPageSize(10).toPage(5).getResultList();
int totalPages = paged.countPages();
SecurityModule
SecurityModule-Simpleinterceptor-styleauthorization
Type-safeauthorization
@Retention(value = RetentionPolicy.RUNTIME)@Target({ ElementType.TYPE, ElementType.METHOD })@SecurityBindingTypepublic @interface AdminOnly {}
@ApplicationScopedpublic class SecuredBean {
@AdminOnly public void doSomething() { //... }}
SecurityModule-Simpleinterceptor-styleauthorization
Aninterceptor-styleclassisusedtodefinetheaccess
@ApplicationScopedpublic class ApplicationAuthorizer {
@Secures @AdminOnly public boolean verifyPermission(InvocationContext invocationContext, BeanManager manager, @Loggged User user) throws Exception { return user.getRole().equalsIgnoreCase("Admin"); }}
JSFModule
JSFModule-JSFMessages@MessageBundlepublic interface Messages {
@MessageTemplate("Welcome to DeltaSpike") String welcomeToDeltaSpike();
}
@Modelpublic class MyJSFBean {
@Inject private JsfMessage<Messages> messages;
//... messages.addInfo().welcomeToDeltaSpike();}
JSFModule-@WindowScoped "Thewindow-scopeislikeasessionperwindow"
@WindowScopedpublic class PreferencesBean implements Serializable { //...}
"Thereisn’talotofuse-caseswhichneedshareddatabetweenwindows"
JSFModule-Double-SubmitPrevention
"Toavoidthatthesamecontentofaformgetssubmittedandthereforeprocessedmultipletimes"
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ds="http://deltaspike.apache.org/jsf"> <h:head> <!-- head content --> </h:head> <h:body> <h:form> <!-- form content --> <ds:preventDoubleSubmit/> </h:form> </h:body></html>
SchedulerModule
SchedulerModule
ProvidesintegrationwithQuartz.
// Job will execute each minute@Scheduled(cronExpression = "0 0/1 * * * ?", onStartup = false)public class CdiAwareQuartzJob implements org.quartz.Job {
// And it can receive CDI injections @Inject private AdminServices service;
@Override public void execute(JobExecutionContext context) throws JobExecutionException { service.executeAdministrativeTask(); }}
@Injectprivate Scheduler<Job> jobScheduler;
//...jobScheduler.registerNewJob(CdiAwareQuartzJob.class);
OtherModules
OtherModules
WanttogofartheronCDI?TUT2376:AdvancedCDIinlivecoding
Tuesday27that8:30
CyrilMagninII/III
AntoninStefanutti&AntoineSD