apache deltaspike the cdi toolbox (java one 2015)

Post on 21-Feb-2017

884 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

ApacheDeltaSpike-theCDItoolbox

AntoineSabot-Durand·RafaelBenevides

RafaelBenevides

DeltaSpikeP.M.CmemberRedHat,Inc.@rafabenerafabene.comgithub.com/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

It’slike@VetoedfromCDI1.1butbetter!

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

Questions???

deltaspike.apache.org/

top related