SlideShare uma empresa Scribd logo
1 de 112
Baixar para ler offline
Going	further	with	CDI
1.2
Antoine	Sabot-Durand	·	Antonin	Stefanutti
Antonin	Stefanutti
	Software	Engineer
	Red	Hat
	JBoss	Fuse	team
	@astefanut
	github.com/astefanutti
Antoine	Sabot-Durand
	Red	Hat
	CDI	spec	lead
	@antoine_sd
	next-presso.com
	github.com/antoinesd
Should	I	stay	or	should	I	go?
	A	talk	about	advanced	CDI
	Might	be	hard	for	beginners
	Don’t	need	to	be	a	CDI	guru
@Inject @Produces
Event<T> @Observes
@Qualifier InjectionPoint
Should	I	stay	or	should	I	go?
 If	you	know	most	of	these	you	can	stay
More	concretely
 What’s	included:
1.	 Real	use	cases	from	real	life	with	real	users
2.	 New	approach	to	introduce	portable	extension	concepts
3.	 Code	in	IDE	with	tests
 What’s	not	included:
1.	 Introduction	to	CDI
2.	 Old	content	on	extension
3.	 Work	with	Context	(need	2	more	hours)
Tools	used	in	the	code	1/2
Apache	Deltaspike
1.	 Apache	DeltaSpike	is	a	great	CDI
toolbox
2.	 Provide	helpers	to	develop	extension
3.	 And	a	collection	of	modules	like:
1.	 Security
2.	 Data
3.	 Scheduler
4.	 More	info	on	deltaspike.apache.org
Tools	used	in	the	code	2/2
Arquillian
1.	 Arquillian	is	an	integration	test	platform
2.	 It	integrates	with	JUnit
3.	 Create	your	deployment	in	a	dedicated
method
4.	 And	launch	your	tests	against	the	container
of	your	choice
5.	 We’ll	use	the	 weld-se-embedded 	and
weld-ee-embedded 	container
6.	 The	right	solution	to	test	Java	EE	code
7.	 More	info	on	arquillian.org
Agenda
 Slides	available	at	astefanutti.github.io/further-cdi
	Meet	CDI	SPI
	Introducing	CDI	Extensions
	Metrics	CDI
	Camel	CDI
Meet	CDI	SPI
SPI	can	be	split	in	4	parts
SPI	can	be	split	in	4	parts
 Type	meta-model
SPI	can	be	split	in	4	parts
 CDI	meta-model
SPI	can	be	split	in	4	parts
 CDI	entry	points
SPI	can	be	split	in	4	parts
 SPI	dedicated	to	extensions
Why	having	a	type	meta-model?
 Because	 @Annotations 	are	configuration
 but	they	are	also	read-only
 So	to	configure	we	need	a	mutable	meta-model…
 … for	annotated	types
SPI	for	type	meta-model
Annotated
Type	getBaseType()
Set<Type>	getTypeClosure()
<T	extends	Annotation>	getAnnotation(Class<T>)
Set<Annotation>	getAnnotations()
boolean	isAnnotationPresent(Class<?	extends	Annotation>)
AnnotatedMember
X
Member	getJavaMember()
boolean	isStatic()
AnnotatedType<X>	getDeclaringType()
AnnotatedParameter
X
int	getPosition()
AnnotatedCallable<X>	getDeclaringCallable()
AnnotatedType
X
Class<X>	getJavaClass()
Set<AnnotatedConstructor<X>>	getConstructors()
Set<AnnotatedMethod<?	super	X>>	getMethods()
Set<AnnotatedField<?	super	X>>	getFields()
AnnotatedCallable
X
List<AnnotatedParameter<X>>	getParameters()
AnnotatedField
X
Field	getJavaMember()
AnnotatedConstructor
X
Constructor<X>	getJavaMember()
AnnotatedMethod
X
Method	getJavaMember()
SPI	dedicated	to	CDI	meta-model
BeanAttributes
T
Set<Type>	getTypes()
Set<Annotation>	getQualifiers()
Class<?	extends	Annotation>	getScope()
String	getName()
Set<Class<?	extends	Annotation>>	getStereotypes()
boolean	isAlternative()
Bean
T
Class<?>	getBeanClass()
Set<InjectionPoint>	getInjectionPoints()
boolean	isNullable()
Interceptor
T
Set<Annotation>	getInterceptorBindings()
boolean	intercepts(InterceptionType	type)
Object	intercept(InterceptionType,	T,	InvocationContext)
Decorator
T
Type	getDelegateType()
Set<Annotation>	getDelegateQualifiers()
Set<Type>	getDecoratedTypes()
Producer
T
T	produce(CreationalContext<T>)
void	dispose(T)
Set<InjectionPoint>	getInjectionPoints()
InjectionTarget
T
void	inject(T,	CreationalContext<T>)
void	postConstruct(T)
void	preDestroy(T)
InjectionPoint
Type	getType()
Set<Annotation>	getQualifiers()
Bean<?>	getBean()
Member	getMember()
Annotated	getAnnotated()
boolean	isDelegate()
boolean	isTransient()
ObserverMethod
T
Class<?>	getBeanClass()
Type	getObservedType()
Set<Annotation>	getObservedQualifiers()
Reception	getReception()
TransactionPhase	getTransactionPhase()
void	notify(T)
EventMetadata
Set<Annotation>	getQualifiers()
InjectionPoint	getInjectionPoint()
Type	getType()
This	SPI	can	be	used	in	your	code	(1/2)
 InjectionPoint 	can	be	used	to	get	info	about	what’s	being	injected
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public	@interface	HttpParam	{
				@Nonbinding	public	String	value();
}
@Produces	@HttpParam("")
String	getParamValue(InjectionPoint	ip,	HttpServletRequest	req)	{
		return	req.getParameter(ip.getAnnotated().getAnnotation(HttpParam.class).value());
}
@Inject
@HttpParam("productId")
String	productId;
This	SPI	can	be	used	in	your	code	(2/2)
 InjectionPoint 	contains	info	about	requested	type	at	 @Inject
class	MyMapProducer()	{
				@Produces
				<K,	V>	Map<K,	V>	produceMap(InjectionPoint	ip)	{
								if	(valueIsNumber(((ParameterizedType)	ip.getType())))
												return	new	TreeMap<K,	V>();
								return	new	HashMap<K,	V>();
				}
				boolean	valueIsNumber(ParameterizedType	type)	{
								Class<?>	valueClass	=	(Class<?>)	type.getActualTypeArguments()[1];
								return	Number.class.isAssignableFrom(valueClass)
				}
}
SPI	providing	CDI	entry	points
Unmanaged
T
Unmanaged(BeanManager,	Class<T>)
Unmanaged(Class<T>)
UnmanagedInstance<T>	newInstance()
UnmanagedInstance
T
T	get()
UnmanagedInstance<T>	produce()
UnmanagedInstance<T>	inject()
UnmanagedInstance<T>	postConstruct()
UnmanagedInstance<T>	preDestroy()
UnmanagedInstance<T>	dispose()
CDIProvider
CDI<Object>	getCDI()
BeanManager
Object	getReference(Bean<?>,	Type,	CreationalContext<?>	)
Object	getInjectableReference(InjectionPoint,	CreationalContext<?>	)
Set<Bean<?>>	getBeans(Type,	Annotation[])
Bean<?	extends	X>	resolve(Set<Bean<?	extends	X>>)
void	validate(InjectionPoint)
void	fireEvent(Object,	Annotation[])
boolean	isQualifier(Class<?	extends	Annotation>)
boolean	isStereotype(Class<?	extends	Annotation>)
boolean	areQualifiersEquivalent(Annotation,	Annotation)
boolean	areInterceptorBindingsEquivalent(Annotation,	Annotation)
Context	getContext(Class<?	extends	Annotation>)
ELResolver	getELResolver()
ExpressionFactory	wrapExpressionFactory(ExpressionFactory)
AnnotatedType<T>	createAnnotatedType(Class<T>)
InjectionTarget<T>	createInjectionTarget(AnnotatedType<T>)
InjectionTargetFactory<T>	getInjectionTargetFactory(AnnotatedType<T>)
BeanAttributes<T>	createBeanAttributes(AnnotatedType<T>)
Bean<T>	createBean(BeanAttributes<T>,	Class<X>,	ProducerFactory<X>)
InjectionPoint	createInjectionPoint(AnnotatedField<?>)
some	methods	skipped
CDI
T
Set<CDIProvider>	discoveredProviders
CDIProvider	configuredProvider
CDI<Object>	current()
void	setCDIProvider(CDIProvider	provider)
BeanManager	getBeanManager()
SPI	dedicated	to	extensions
BeforeBeanDiscovery
addQualifier(Class<?	extends	Annotation>)
addScope(Class<?	extends	Annotation>,	boolean,	boolean)
addStereotype(Class<?	extends	Annotation>,	Annotation[])
addInterceptorBinding(Class<?	extends	Annotation>,	Annotation[])
addAnnotatedType(AnnotatedType<?>)
AfterTypeDiscovery
List<Class<?>>	getAlternatives()
List<Class<?>>	getInterceptors()
List<Class<?>>	getDecorators()
addAnnotatedType(AnnotatedType<?>,	String)
AfterDeploymentValidation BeforeShutdown
AfterBeanDiscovery
addBean(Bean<?>)
addObserverMethod(ObserverMethod<?>)
addContext(Context)
AnnotatedType<T>	getAnnotatedType(Class<T>,	String)
Iterable<AnnotatedType<T>>	getAnnotatedTypes(Class<T>)
ProcessAnnotatedType
X
AnnotatedType<X>	getAnnotatedType()
void	setAnnotatedType(AnnotatedType<X>)
veto()
ProcessBean
X
Annotated	getAnnotated()
Bean<X>	getBean()
ProcessBeanAttributes
T
Annotated	getAnnotated()
BeanAttributes<T>	getBeanAttributes()
setBeanAttributes(BeanAttributes<T>)
veto()
ProcessInjectionPoint
T,	X
InjectionPoint	getInjectionPoint()
setInjectionPoint(InjectionPoint)
ProcessInjectionTarget
X
AnnotatedType<X>	getAnnotatedType()
InjectionTarget<X>	getInjectionTarget()
setInjectionTarget(InjectionTarget<X>)
ProcessObserverMethod
T,	X
AnnotatedMethod<X>	getAnnotatedMethod()
ObserverMethod<T>	getObserverMethod()
ProcessProducer
T,	X
AnnotatedMember<T>	getAnnotatedMember()
Producer<X>	getProducer()
setProducer(Producer<X>)
All	these	SPI	interfaces	are	events	containing	meta-model	SPI

These	events	fired	at	boot	time	can	only	be	observed	in	CDI
extensions
 For	instance:

A	 ProcessAnnotatedType<T> 	event	is	fired
for	each	type	being	discovered	at	boot
time

Observing	 ProcessAnnotatedType<Foo>
allows	you	to	prevent	 Foo 	to	be	deployed
as	a	bean	by	calling
ProcessAnnotatedType#veto()
Introducing	CDI
Portable	Extensions
Portable	extensions

One	of	the	most	powerful	feature	of	the
CDI	specification
 Not	really	popularized,	partly	due	to:
1.	 Their	high	level	of	abstraction
2.	 The	good	knowledge	on	Basic	CDI	and	SPI
3.	 Lack	of	information	(CDI	is	often	reduced	to	a	basic	DI	solution)
Extensions,	what	for?
 To	integrate	3rd	party	libraries,	frameworks	or	legacy	components
 To	change	existing	configuration	or	behavior
 To	extend	CDI	and	Java	EE
 Thanks	to	them,	Java	EE	can	evolve	between	major	releases
Extensions,	how?

Observing	SPI	events	at	boot	time	related	to
the	bean	manager	lifecycle
 Checking	what	meta-data	are	being	created
 Modifying	these	meta-data	or	creating	new
ones
More	concretely

Service	provider	of	the	service
javax.enterprise.inject.spi.Extension 	declared	in
META-INF/services
 Just	put	the	fully	qualified	name	of	your	extension	class	in	this	file
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
Bean	manager	lifecycle
Deployment
Start
Before
Bean
Discovery
Scan
Archive
Process
Annotated
Type
After
Type
Discovery
Bean
Eligibility
Check
Process
Injection
Point
Process
Injection
Target
Process
Bean
Attributes
Process
Bean
Process
Producer
Process
Observer
Method
After
Bean
Discovery
After
Deployment
Validation
Application
Running
Before
Shutdown
Undeploy
Application
Example:	Ignoring	JPA	entities
 The	following	extension	prevents	CDI	to	manage	entities
 This	is	a	commonly	admitted	good	practice
public	class	VetoEntity	implements	Extension	{
				void	vetoEntity(@Observes	@WithAnnotations(Entity.class)
																				ProcessAnnotatedType<?>	pat)	{
								pat.veto();
				}
}
	Extensions	are	launched	during
bootstrap	and	are	based	on	CDI	events
	Once	the	application	is	bootstrapped,
the	Bean	Manager	is	in	read-only	mode	(no
runtime	bean	registration)
	You	only	have	to	@Observes 	built-in	CDI	events
to	create	your	extensions
Remember
Integrating	Dropwizard	Metrics	in	CDI
Metrics	CDI
Dropwizard	Metrics	provides
 Different	metric	types:	 Counter ,	 Gauge ,	 Meter ,	 Timer ,	…
 Different	reporter:	JMX,	console,	SLF4J,	CSV,	servlet,	…
 MetricRegistry 	object	which	collects	all	your	app	metrics
 Annotations	for	AOP	frameworks:	 @Counted ,	 @Timed ,	…
 … 	but	does	not	include	integration	with	these	frameworks
 More	at	dropwizard.github.io/metrics
Discover	how	we	created	CDI
integration	module	for	Metrics
Metrics	out	of	the	box	(without	CDI)
class	MetricsHelper	{
				public	static	MetricRegistry	registry	=	new	MetricRegistry();
}
class	TimedMethodClass	{
				void	timedMethod()	{
								Timer	timer	=	MetricsHelper.registry.timer("timer");	
								Timer.Context	time	=	timer.time();
								try	{
												/*...*/
								}	finally	{
												time.stop();
								}
				}
}
Note	that	if	a	 Timer 	named	 "timer" 	doesn’t	exist,	 MetricRegistry 	will	create	a	default	one	and	register	it
1
1
Basic	CDI	integration
class	MetricRegistryBean	{
				@Produces	@ApplicationScoped
				MetricRegistry	registry	=	new	MetricRegistry();
}
class	TimedMethodBean	{
				@Inject	MetricRegistry	registry;
				void	timedMethod()	{
								Timer	timer	=	registry.timer("timer");
								Timer.Context	time	=	timer.time();
								try	{
												/*...*/
								}	finally	{
												time.stop();
								}
				}
}
 We	could	have	a	lot	more	with	advanced	CDI	features
Our	goals	to	achieve	full	CDI
integration
 Produce	and	inject	multiple	metrics	of	the	same	type
 Apply	Metrics	with	provided	annotations
 Access	same	 Metric 	through	inject	or	 MetricRegistry 	getter
GOAL	1	Produce	and	inject
multiple	metrics	of	the	same	type
What’s	the	problem	with	multiple	Metrics	of	the	same	type?
 This	code	create	a	deployment	error	(ambiguous	dependency)
@Produces
Timer	timer	=	new	Timer(new	SlidingTimeWindowReservoir(1L,	MINUTES));	
@Produces
Timer	timer	=	new	Timer(new	SlidingTimeWindowReservoir(1L,	HOURS));	
@Inject
Timer	timer;	
This	timer	that	only	keeps	measurement	of	last	minute	is	produced	as	a	bean	of	type	 Timer
This	timer	that	only	keeps	measurement	of	last	hour	is	produced	as	a	bean	of	type	 Timer
This	injection	point	is	ambiguous	since	2	eligible	beans	exist
1
2
3
1
2
3
Solving	the	ambiguity
 We	could	use	the	provided	 @Metric 	annotation	to	qualify	our	beans
@Produces
@Metric(name	=	"myTimer")
Timer	timer	=	new	Timer(new	SlidingTimeWindowReservoir(1L,	MINUTES));
@Produces
@Metric(name	=	"mySecondTimer")
Timer	timer	=	new	Timer(new	SlidingTimeWindowReservoir(1L,	HOURS));
@Inject
@Metric(name	=	"myTimer")
Timer	timer;
 That	won’t	work	out	of	the	box	since	 @Metric 	is	not	a	qualifier
How	to	make	 @Metric 	a	qualifier?
 By	observing	 BeforeBeanDiscovery 	lifecycle	event	in	an	extension
public	interface	BeforeBeanDiscovery	{
				addQualifier(Class<?	extends	Annotation>	qualifier);		
				addQualifier(AnnotatedType<?	extends	Annotation>	qualifier);
				addScope(Class<?	extends	Annotation>	scopeType,	boolean	normal,	boolean	passivation);
				addStereotype(Class<?	extends	Annotation>	stereotype,	Annotation...	stereotypeDef);
				addInterceptorBinding(AnnotatedType<?	extends	Annotation>	bindingType);
				addInterceptorBinding(Class<?	extends	Annotation>	bindingType,	Annotation...	bindingTypeDef);
				addAnnotatedType(AnnotatedType<?>	type);
				addAnnotatedType(AnnotatedType<?>	type,	String	id);
}
This	method	is	the	one	we	need	to	declare	 @Metric 	as	qualifier
 And	use	 addQualifier() 	method	in	the	event
1
1
Internal	Step Happen	Once Loop	on	Elements
BeforeBeanDiscovery 	is	first	in	lifecycle
Deployment
Start
Before
Bean
Discovery
Scan
Archive
Process
Annotated
Type
After
Type
Discovery
Bean
Eligibility
Check
Process
Injection
Point
Process
Injection
Target
Process
Bean
Attributes
Process
Bean
Process
Producer
Process
Observer
Method
After
Bean
Discovery
After
Deployment
Validation
Application
Running
Before
Shutdown
Undeploy
Application
Our	first	extension
 A	CDI	extension	is	a	class	implementing	the	 Extension 	tag	interface
org.cdi.further.metrics.MetricsExtension
public	class	MetricsExtension	implements	Extension	{
				void	addMetricAsQualifier(@Observes	BeforeBeanDiscovery	bdd)	{
								bdd.addQualifier(Metric.class);
				}
}
 Extension	is	activated	by	adding	this	file	to	 META-INF/services
javax.enterprise.inject.spi.Extension
org.cdi.further.metrics.MetricsExtension
Goal	1	achieved
 We	can	now	write:
@Produces
@Metric(name	=	"myTimer")
Timer	timer	=	new	Timer(new	SlidingTimeWindowReservoir(1L,	MINUTES));
@Produces
@Metric(name	=	"mySecondTimer")
Timer	timer	=	new	Timer(new	SlidingTimeWindowReservoir(1L,	HOURS));
@Inject
@Metric(name	=	"myTimer")
Timer	timer;
 And	have	the	 Timer 	injection	points	satisfied
GOAL	2	Apply	Metrics	with	provided	annotations
Goal	2	in	detail
 We	want	to	be	able	to	write:
@Timed("timer")	
void	timedMethod()	{
				//...
}
 And	have	the	timer	 "timer" 	activated	during	method	invocation
 The	solution	is	to	build	and	interceptor	and	bind	it	to	 @Timed
1
Goal	2	step	by	step
 Create	an	interceptor	for	the	timer	technical	code
 Make	 @Timed 	(provided	by	Metrics)	a	valid	interceptor	binding
 Programmatically	add	 @Timed 	as	an	interceptor	binding
 Use	the	magic
Preparing	interceptor	creation
 We	should	find	the	technical	code	that	will	wrap	the	business	code
class	TimedMethodBean	{
				@Inject	MetricRegistry	registry;
				void	timedMethod()	{
								Timer	timer	=	registry.timer("timer");
								Timer.Context	time	=	timer.time();
								try	{
												//	Business	code
								}	finally	{
												time.stop();
								}
				}
}
Creating	the	interceptor
 Interceptor	code	is	highlighted	below
@Interceptor
class	TimedInterceptor	{
				@Inject	MetricRegistry	registry;	
				@AroundInvoke
				Object	timedMethod(InvocationContext	context)	throws	Exception	{
								Timer	timer	=	registry.timer(context.getMethod().getAnnotation(Timed.class).name());
								Timer.Context	time	=	timer.time();
								try	{
												return	context.proceed();	
								}	finally	{
												time.stop();
								}
				}
}
In	CDI	an	interceptor	is	a	bean,	you	can	inject	other	beans	in	it
Here	the	business	of	the	application	is	called.	All	the	code	around	is	the	technical	one.
1
2
1
2
Activating	the	interceptor
@Interceptor
@Priority(Interceptor.Priority.LIBRARY_BEFORE)		
class	TimedInterceptor	{
				@Inject
				MetricRegistry	registry;
				@AroundInvoke
				Object	timedMethod(InvocationContext	context)	throws	Exception	{
								Timer	timer	=	registry.timer(context.getMethod().getAnnotation(Timed.class).name());
								Timer.Context	time	=	timer.time();
								try	{
												return	context.proceed();
								}	finally	{
												time.stop();
								}
				}
}
Giving	a	 @Priority 	to	an	interceptor	activates	and	orders	it
1
1
Add	a	binding	to	the	interceptor
@Timed		
@Interceptor
@Priority(Interceptor.Priority.LIBRARY_BEFORE)
class	TimedInterceptor	{
				@Inject
				MetricRegistry	registry;
				@AroundInvoke
				Object	timedMethod(InvocationContext	context)	throws	Exception	{
								Timer	timer	=	registry.timer(context.getMethod().getAnnotation(Timed.class).name());
								Timer.Context	time	=	timer.time();
								try	{
												return	context.proceed();
								}	finally	{
												time.stop();
								}
				}
}
We’ll	use	Metrics	 @Timed 	annotation	as	interceptor	binding
1
1
Back	on	interceptor	binding
 An	interceptor	binding	is	an	annotation	used	in	2	places:
1.	 On	the	interceptor	class	to	bind	it	to	this	annotation
2.	 On	the	methods	or	classes	to	be	intercepted	by	this	interceptor

An	interceptor	binding	should	have	the	 @InterceptorBinding
annotation	or	should	be	declared	programmatically
 If	the	interceptor	binding	annotation	has	members:
1.	 Their	values	are	taken	into	account	to	resolve	interceptor
2.	 Unless	members	are	annotated	with	 @NonBinding
@Timed 	source	code	is	not	an	interceptor	binding
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({	ElementType.TYPE,	ElementType.CONSTRUCTOR,	ElementType.METHOD,	
ElementType.ANNOTATION_TYPE	})
public	@interface	Timed	{
				String	name()	default	"";	
				boolean	absolute()	default	false;	
}
Lack	of	 @InterceptorBinding 	annotation
None	of	the	members	have	the	 @NonBinding 	annotation,	so	 @Timed(name	=	"timer1") 	and
@Timed(name	=	"timer2") 	will	be	2	different	interceptor	bindings
1
2
2
1
2
The	required	 @Timed 	source	code	to	make	it	an	interceptor	binding
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({	ElementType.TYPE,	ElementType.CONSTRUCTOR,	ElementType.METHOD,	
ElementType.ANNOTATION_TYPE	})
@InterceptorBinding
public	@interface	Timed	{
				@NonBinding	String	name()	default	"";
				@NonBinding	boolean	absolute()	default	false;
}
	How	to	obtain	the	required	@Timed ?
	We	cannot	touch	the	component	source	/	binary!
Using	the	 AnnotatedType 	SPI
 Thanks	to	DeltaSpike	we	can	easily	create	the	required	 AnnotatedType
AnnotatedType	createTimedAnnotatedType()	throws	Exception	{
				Annotation	nonBinding	=	new	AnnotationLiteral<Nonbinding>()	{};	
				return	new	AnnotatedTypeBuilder().readFromType(Timed.class)	
								.addToMethod(Timed.class.getMethod("name"),	nonBinding)	
								.addToMethod(Timed.class.getMethod("absolute"),	nonBinding)	
								.create();
}
This	creates	an	instance	of	 @NonBinding 	annotation
It	would	have	been	possible	but	far	more	verbose	to	create	this	 AnnotatedType 	without	the	help	of
DeltaSpike.	The	 AnnotatedTypeBuilder 	is	initialized	from	the	Metrics	 @Timed 	annotation.
@NonBinding 	is	added	to	both	members	of	the	 @Timed 	annotation
1
2
3
3
1
2
3
This	extension	will	do	the	job
 We	observe	 BeforeBeanDiscovery 	to	add	a	new	interceptor	binding
public	class	MetricsExtension	implements	Extension	{
				void	addTimedBinding(@Observes	BeforeBeanDiscovery	bdd)	throws	Exception	{
								Annotation	nonBinding	=	new	AnnotationLiteral<Nonbinding>()	{};
								bdd.addInterceptorBinding(new	AnnotatedTypeBuilder<Timed>()
												.readFromType(Timed.class)
												.addToMethod(Timed.class.getMethod("name"),	nonBinding)
												.addToMethod(Timed.class.getMethod("absolute"),	nonBinding)
												.create());
				}
}
Goal	2	achieved
 We	can	now	write:
@Timed("timer")
void	timedMethod()	{
				//	Business	code
}
And	have	a	Metrics	Timer 	applied	to	the	method
 Interceptor	should	be	enhanced	to	support	 @Timed 	on	a	class
 Other	interceptor	should	be	developed	for	other	metrics
Our	goals
1.	 Apply	a	metric	with	the	provided	annotation	in	AOP	style
@Timed("timer")	
void	timedMethod()	{
				//...
}
2.	 Register	automatically	produced	custom	metrics
@Produces	@Metric(name	=	"myTimer")	
Timer	timer	=	new	Timer(new	SlidingTimeWindowReservoir(1L,	MINUTES));
//...
@Timed("myTimer")	
void	timedMethod()	{	/*...*/	}
Annotations	provided	by	Metrics
1
1
1
1
GOAL	3	Access	same	Metric	through	@Inject
or	MetricRegistry 	getter
Goal	3	in	detail
 When	Writing:
@Inject
@Metric(name	=	"myTimer")
Timer	timer1;
@Inject
MetricRegistry	registry;
Timer	timer2	=	registry.timer("myTimer");
 … 	We	want	that	 timer1	==	timer2
Goal	3	in	detail
@Produces	@Metric(name	=	"myTimer")	
Timer	timer	=	new	Timer(new	SlidingTimeWindowReservoir(1L,	TimeUnit.MINUTES));
@Inject
@Metric(name	=	"myTimer")
Timer	timer;
@Inject
MetricRegistry	registry;
Timer	timer	=	registry.timer("myTimer");	
Produced	 Timer 	should	be	added	to	MetricRegistry	when	produced
When	retrieved	from	registry	a	 Metric 	should	be	identical	to	the	produced	instance	and	vice	versa

There	are	2	 Metric :	the	 com.codahale.metrics.Metric 	interface	and
the	 com.codahale.metrics.annotation.Metric 	annotation
1
2
1
2
Goal	3	step	by	step
 We	need	to	write	an	extension	that	will:
1.	 Change	how	a	 Metric 	instance	is	produced	by	looking	it	up	in	the
registry	first	and	producing	(and	registering)	it	only	if	it’s	not	found.
We’ll	do	this	by:
1.	 observing	the	 ProcessProducer 	lifecycle	event
2.	 decorating	Metric	 Producer 	to	add	this	new	behavior
2.	 Produce	all	 Metric 	instances	at	the	end	of	boot	time	to	have	them	in
registry	for	runtime
1.	 we’ll	do	this	by	observing	 AfterDeploymentValidation 	event
Internal	Step Happen	Once Loop	on	Elements
So	we	will	 @Observes 	these	2	events	to	add	our	features
Deployment
Start
Before
Bean
Discovery
Scan
Archive
Process
Annotated
Type
After
Type
Discovery
Bean
Eligibility
Check
Process
Injection
Point
Process
Injection
Target
Process
Bean
Attributes
Process
Bean
Process
Producer
Process
Observer
Method
After
Bean
Discovery
After
Deployment
Validation
Application
Running
Before
Shutdown
Undeploy
Application
Customizing	 Metric 	producing	process
 We	first	need	to	create	our	implementation	of	the	 Producer<X> 	SPI
class	MetricProducer<X	extends	Metric>	implements	Producer<X>	{
				final	Producer<X>	decorate;
				final	String	metricName;
				MetricProducer(Producer<X>	decorate,	String	metricName)	{
								this.decorate	=	decorate;
								this.metricName	=	metricName;
				}
				//...
Customizing	 Metric 	producing	process	(continued)
				//...
				public	X	produce(CreationalContext<X>	ctx)	{	
								MetricRegistry	reg	=	BeanProvider.getContextualReference(MetricRegistry.class,	false);	
								if	(!reg.getMetrics().containsKey(metricName))	
												reg.register(metricName,	decorate.produce(ctx));
								return	(X)	reg.getMetrics().get(metricName);
				}
				public	void	dispose(X	instance)	{	}
				public	Set<InjectionPoint>	getInjectionPoints()	{
								return	decorate.getInjectionPoints();
				}
}
Produce	method	will	be	used	by	the	container	at	runtime	to	decorate	declared	producer	with	our	logic
BeanProvider 	is	a	DeltaSpike	helper	class	to	easily	retrieve	a	bean	or	bean	instance
If	metric	name	is	not	in	the	registry,	the	original	producer	is	called	and	its	result	is	added	to	registry
1
2
3
1
2
3
We’ll	use	our	 MetricProducer 	in	a	 ProcessProducer 	observer
 This	event	allow	us	to	substitute	the	original	producer	by	ours
public	interface	ProcessProducer<T,	X>	{
				AnnotatedMember<T>	getAnnotatedMember();	
				Producer<X>	getProducer();	
				void	setProducer(Producer<X>	producer);	
				void	addDefinitionError(Throwable	t);
}
Gets	the	 AnnotatedMember 	associated	to	the	 @Produces 	field	or	method
Gets	the	default	producer	(useful	to	decorate	it)
Overrides	the	producer
1
2
3
1
2
3
Customizing	 Metric 	producing	process	(end)
 Here’s	the	extension	code	to	do	this	producer	decoration
public	class	MetricsExtension	implements	Extension	{
				//...
				<X	extends	Metric>	void	decorateMetricProducer(@Observes	ProcessProducer<?,	X>	pp)	{
								String	name	=	pp.getAnnotatedMember().getAnnotation(Metric.class).name();	
								pp.setProducer(new	MetricProducer<>(pp.getProducer(),	name));	
				}
				//...
}
We	retrieve	metric	name	from	the	 name() 	member	in	 @Metric
We	replace	the	original	producer	by	our	producer	(which	decorates	the	former)
1
2
1
2
Producing	all	the	 Metric 	instances	at	the	end	of	boot	time
 We	do	that	by	observing	the	 AfterDeploymentValidation 	event
public	class	MetricsExtension	implements	Extension	{
				//...
				void	registerProducedMetrics(@Observes	AfterDeploymentValidation	adv)	{
								List<Metric>	metrics	=	BeanProvider.getContextualReferences(Metric.class,	true);	
				}
				//...
}
getContextualReferences() 	is	a	method	in	DeltaSpike	 BeanProvider 	helper	class.
It	creates	the	list	of	bean	instances	for	a	given	bean	type	(ignoring	qualifiers)
1
1
Goal	3	achieved
 We	can	now	write:
@Produces	@Metric(name	=	"myTimer")
Timer	timer	=	new	Timer(new	SlidingTimeWindowReservoir(1L,	TimeUnit.MINUTES));
@Inject
MetricRegistry	registry;
@Inject	@Metric("myTimer")
Metric	timer;

And	be	sure	that	 registry.getMetrics().get("myTimer") 	and
timer 	are	the	same	object	(our	custom	 Timer )
Complete	extension	code
public	class	MetricsExtension	implements	Extension	{
				void	addMetricAsQualifier(@Observes	BeforeBeanDiscovery	bdd)	{bdd.addQualifier(Metric.class);}
				void	addTimedBinding(@Observes	BeforeBeanDiscovery	bdd)	throws	Exception	{
								Annotation	nonBinding	=	new	AnnotationLiteral<Nonbinding>()	{};
								bdd.addInterceptorBinding(new	AnnotatedTypeBuilder<Timed>().readFromType(Timed.class)
												.addToMethod(Timed.class.getMethod("name"),	nonBinding)
												.addToMethod(Timed.class.getMethod("absolute"),nonBinding).create());
				}
				<T	extends	com.codahale.metrics.Metric>	void	decorateMetricProducer(@Observes	ProcessProducer<?,	T>	pp)	{
								if	(pp.getAnnotatedMember().isAnnotationPresent(Metric.class))	{
												String	name	=	pp.getAnnotatedMember().getAnnotation(Metric.class).name();
												pp.setProducer(new	MetricProducer(pp.getProducer(),	name));
								}
				}
				void	registerProducedMetrics(@Observes	AfterDeploymentValidation	adv)	{
								List<com.codahale.metrics.Metric>	metrics	=	BeanProvider
												.getContextualReferences(com.codahale.metrics.Metric.class,	true);
				}
}
How	to	use	CDI	as	dependency	injection	container
for	an	integration	framework	(Apache	Camel)
Camel	CDI
About	Apache	Camel

Open-source	integration	framework	based	on	known	Enterprise
Integration	Patterns
 Provides	a	variety	of	DSLs	to	write	routing	and	mediation	rules

Provides	support	for	bean	binding	and	seamless	integration	with	DI
frameworks
Discover	how	we	created	CDI
integration	module	for	Camel
Camel	out	of	the	box	(without	CDI)
	public	static	void	main(String[]	args)	{
				CamelContext	context	=	new	DefaultCamelContext();
				context.addRoutes(new	RouteBuilder()	{
						public	void	configure()	{
								from("file:target/input?delay=1000")
										.log("Sending	message	[${body}]	to	JMS	...")
										.to("sjms:queue:output");	
						}
				});
				PropertiesComponent	properties	=	new	PropertiesComponent();
				properties.setLocation("classpath:camel.properties");
				context.addComponent("properties",	properties);	//	Registers	the	"properties"	component
				SjmsComponent	component	=	new	SjmsComponent();
				component.setConnectionFactory(new	ActiveMQConnectionFactory("vm://broker?broker.persistent=false"));
				jms.setConnectionCount(Integer.valueOf(context.resolvePropertyPlaceholders("{{jms.maxConnections}}")));
				context.addComponent("sjms",	jms);	//	Registers	the	"sjms"	component
				context.start();
}
This	route	watches	a	directory	every	second	and	sends	new	files	content	to	a	JMS	queue
1
1
Why	CDI?
Basic	CDI	integration	(1/3)
1.	 Camel	components	and	route	builder	as	CDI	beans
2.	 Bind	the	Camel	context	lifecycle	to	that	of	the	CDI	container
class	FileToJmsRouteBean	extends	RouteBuilder	{
				@Override
				public	void	configure()	{
								from("file:target/input?delay=1000")
												.log("Sending	message	[${body}]	to	JMS...")
												.to("sjms:queue:output");
				}
}
Basic	CDI	integration	(2/3)
class	PropertiesComponentFactoryBean	{
				@Produces
				@ApplicationScoped
				PropertiesComponent	propertiesComponent()	{
								PropertiesComponent	properties	=	new	PropertiesComponent();
								properties.setLocation("classpath:camel.properties");
								return	properties;
				}
}
class	JmsComponentFactoryBean	{
				@Produces
				@ApplicationScoped
				SjmsComponent	sjmsComponent(PropertiesComponent	properties)	throws	Exception	{
								SjmsComponent	jms	=	new	SjmsComponent();
								jms.setConnectionFactory(new	ActiveMQConnectionFactory("vm://broker?broker.persistent=false"));
								jms.setConnectionCount(Integer.valueOf(properties.parseUri("{{jms.maxConnections}}")));
								return	component;
				}
}
Basic	CDI	integration	(3/3)
@ApplicationScoped
class	CamelContextBean	extends	DefaultCamelContext	{
				@Inject
				CamelContextBean(FileToJmsRouteBean	route,	SjmsComponent	jms,	PropertiesComponent	properties)	{
								addComponent("properties",	properties);
								addComponent("sjms",	jms);
								addRoutes(route);
				}
				@PostConstruct
				void	startContext()	{
								super.start();
				}
				@PreDestroy
				void	preDestroy()	{
								super.stop();
				}
}
 We	could	have	a	lot	more	with	advanced	CDI	features
Our	goals
1.	 Avoid	assembling	and	configuring	the	 CamelContext 	manually
2.	 Access	CDI	beans	from	the	Camel	DSL	automatically
.to("sjms:queue:output");	//	Lookup	by	name	(sjms)	and	type	(Component)
context.resolvePropertyPlaceholders("{{jms.maxConnections}}");
//	Lookup	by	name	(properties)	and	type	(Component)
3.	 Support	Camel	annotations	in	CDI	beans
@PropertyInject(value	=	"jms.maxConnections",	defaultValue	=	"10")
int	maxConnections;
Steps	to	integrate	Camel	and	CDI

Manage	the	creation	and	the	configuration	of	the	 CamelContext
bean
 Bind	the	 CamelContext 	lifecycle	to	that	of	the	CDI	container
 Implement	the	Camel	registry	SPI	to	look	up	CDI	bean	references
 Use	a	custom	 InjectionTarget 	for	CDI	beans	containing	Camel
annotations
 Use	the	magic
How	to	achieve	this?
 We	need	to	write	an	extension	that	will:
1.	 Declare	a	 CamelContext 	bean	by	observing	the	 AfterBeanDiscovery
lifecycle	event
2.	 Instantiate	the	beans	of	type	 RouteBuilder 	and	add	them	to	the	Camel
context
3.	 Start	(resp.	stop)	the	Camel	context	when	the
AfterDeploymentValidation 	event	is	fired	(resp.	the	 BeforeShutdown
event)
4.	 Customize	the	Camel	context	to	query	the	 BeanManager 	to	lookup	CDI
beans	by	name	and	type
5.	 Detect	CDI	beans	containing	Camel	annotations	by	observing	the
ProcessAnnotatedType 	event	and	modify	how	they	get	injected	by
observing	the	 ProcessInjectionTarget 	lifecycle	event
Internal	Step Happen	Once Loop	on	Elements
So	we	will	 @Observes 	these	5	events	to	add	our	features
Deployment
Start
Before
Bean
Discovery
Scan
Archive
Process
Annotated
Type
After
Type
Discovery
Bean
Eligibility
Check
Process
Injection
Point
Process
Injection
Target
Process
Bean
Attributes
Process
Bean
Process
Producer
Process
Observer
Method
After
Bean
Discovery
After
Deployment
Validation
Application
Running
Before
Shutdown
Undeploy
Application
Adding	the	 CamelContext 	bean
 Automatically	add	a	 CamelContext 	bean	in	the	deployment	archive
	How	to	add	a	bean	programmatically?
Declaring	a	bean	programmatically
 We	need	to	implement	the	 Bean 	SPI
public	interface	Bean<T>	extends	Contextual<T>,	BeanAttributes<T>	{
				Class<?>	getBeanClass();
				Set<InjectionPoint>	getInjectionPoints();
				T	create(CreationalContext<T>	creationalContext);	//	Contextual<T>
				void	destroy(T	instance,	CreationalContext<T>	creationalContext);
				Set<Type>	getTypes();	//	BeanAttributes<T>
				Set<Annotation>	getQualifiers();
				Class<?	extends	Annotation>	getScope();
				String	getName();
				Set<Class<?	extends	Annotation>>	getStereotypes();
				boolean	isAlternative();
}
Implementing	the	 Bean 	SPI
class	CamelContextBean	implements	Bean<CamelContext>	{
				public	Class<?	extends	Annotation>	getScope()	{	return	ApplicationScoped.class;	}
				public	Set<Annotation>	getQualifiers()	{
								return	Collections.<Annotation>singleton(new	AnnotationLiteral<Default>(){});
				}
				public	Set<Type>	getTypes()	{	return	Collections.<Type>singleton(CamelContext.class);	}
				public	CamelContext	create(CreationalContext<CamelContext>	creational)	{
								return	new	DefaultCamelContext();
				}
				public	void	destroy(CamelContext	instance,	CreationalContext<CamelContext>	creational)	{}
				public	Class<?>	getBeanClass()	{	return	DefaultCamelContext.class;	}
				public	Set<InjectionPoint>	getInjectionPoints()	{	return	Collections.emptySet();	}
				public	Set<Class<?	extends	Annotation>>	getStereotypes()	{	return	Collections.emptySet();	}
				public	String	getName()	{	return	null;	}	//	Only	called	for	@Named	bean
				public	boolean	isAlternative()	{	return	false;	}
				public	boolean	isNullable()	{	return	false;	}
}
Adding	a	programmatic	bean	to	the	deployment

Then	add	the	 CamelContextBean 	bean	programmatically	by	observing
the	 AfterBeanDiscovery 	lifecycle	event
public	class	CamelExtension	implements	Extension	{
				void	addCamelContextBean(@Observes	AfterBeanDiscovery	abd)	{
								abd.addBean(new	CamelContextBean());
				}
}
Instantiate	and	assemble	the	Camel	context

Instantiate	the	 CamelContext 	bean	and	the	 RouteBuilder 	beans	in	the
AfterDeploymentValidation 	lifecycle	event
public	class	CamelExtension	implements	Extension	{
				//...
				void	configureContext(@Observes	AfterDeploymentValidation	adv,	BeanManager	bm)	{
								CamelContext	context	=	getReference(bm,	CamelContext.class);
								for	(Bean<?>	bean	:	bm.getBeans(RoutesBuilder.class))
												context.addRoutes(getReference(bm,	RouteBuilder.class,	bean));
				}
				<T>	T	getReference(BeanManager	bm,	Class<T>	type)	{
								return	getReference(bm,	type,	bm.resolve(bm.getBeans(type)));
				}
				<T>	T	getReference(BeanManager	bm,	Class<T>	type,	Bean<?>	bean)	{
								return	(T)	bm.getReference(bean,	type,	bm.createCreationalContext(bean));
				}
}
Managed	the	Camel	context	lifecycle

Start	(resp.	stop)	the	Camel	context	when	the
AfterDeploymentValidation 	event	is	fired	(resp.	the	 BeforeShutdown )
public	class	CamelExtension	implements	Extension	{
				//...
				void	configureContext(@Observes	AfterDeploymentValidation	adv,	BeanManager	bm)	{
								CamelContext	context	=	getReference(bm,	CamelContext.class);
								for	(Bean<?>	bean	:	bm.getBeans(RoutesBuilder.class)
												context.addRoutes(getReference(bm,	RouteBuilder.class,	bean);
								context.start();
				}
				void	stopCamelContext(@Observes	BeforeShutdown	bs,	BeanManager	bm)	{
								CamelContext	context	=	getReference(bm,	CamelContext.class);
								context.stop();
				}
}
First	goal	achieved
 We	can	get	rid	of	the	following	code:
@ApplicationScoped
class	CamelContextBean	extends	DefaultCamelContext	{
				@Inject
				CamelContextBean(FileToJmsRouteBean	route,	SjmsComponent	jms,	PropertiesComponent	properties)	{
								addComponent("properties",	propertiesComponent);
								addComponent("sjms",	sjmsComponent);
								addRoutes(route);
				}
				@PostConstruct
				void	startContext()	{
								super.start();
				}
				@PreDestroy
				void	stopContext()	{
								super.stop();
				}
}
Second	goal:	Access	CDI	beans	from	the	Camel	DSL
	How	to	retrieve	CDI	beans	from	the	Camel	DSL?
.to("sjms:queue:output");	//	Lookup	by	name	(sjms)	and	type	(Component)
context.resolvePropertyPlaceholders("{{jms.maxConnections}}");
//	Lookup	by	name	(properties)	and	type	(Component)
//	And	also...
.bean(MyBean.class);	//	Lookup	by	type	and	Default	qualifier
.beanRef("beanName");	//	Lookup	by	name
 Implement	the	Camel	registry	SPI	and	use	the	 BeanManager 	to	lookup
for	CDI	bean	contextual	references	by	name	and	type
Implement	the	Camel	registry	SPI
class	CamelCdiRegistry	implements	Registry	{
				private	final	BeanManager	bm;
				CamelCdiRegistry(BeanManager	bm)	{	this.bm	=	bm;	}
				public	<T>	T	lookupByNameAndType(String	name,	Class<T>	type)	{
								return	getReference(bm,	type,	bm.resolve(bm.getBeans(name)));
				}
				public	<T>	Set<T>	findByType(Class<T>	type)	{
								return	getReference(bm,	type,	bm.resolve(bm.getBeans(type)));
				}
				public	Object	lookupByName(String	name)	{
								return	lookupByNameAndType(name,	Object.class);
				}
				<T>	T	getReference(BeanManager	bm,	Type	type,	Bean<?>	bean)	{
								return	(T)	bm.getReference(bean,	type,	bm.createCreationalContext(bean));
				}
}
Add	the	 CamelCdiRegistry 	to	the	Camel	context
class	CamelContextBean	implements	Bean<CamelContext>	{
				private	final	BeanManager	bm;
				CamelContextBean(BeanManager	bm)	{	this.bm	=	bm;	}
				//...
				public	CamelContext	create(CreationalContext<CamelContext>	creational)	{
								return	new	DefaultCamelContext(new	CamelCdiRegistry(bm));
				}
}
public	class	CamelExtension	implements	Extension	{
				//...
				void	addCamelContextBean(@Observes	AfterBeanDiscovery	abd	,	BeanManager	bm)	{
								abd.addBean(new	CamelContextBean(bm));
				}
}
Second	goal	achieved	1/3
 We	can	declare	the	 sjms 	component	with	the	 @Named 	qualifier
class	JmsComponentFactoryBean	{
				@Produces
				@Named("sjms")
				@ApplicationScoped
				SjmsComponent	sjmsComponent(PropertiesComponent	properties)	{
								SjmsComponent	jms	=	new	SjmsComponent();
								jms.setConnectionFactory(new	ActiveMQConnectionFactory("vm://broker?..."));
								jms.setConnectionCount(Integer.valueOf(properties.parseUri("{{jms.maxConnections}}")));
								return	component;
				}
}
…
Second	goal	achieved	2/3
 Declare	the	 properties 	component	with	the	 @Named 	qualifier
class	PropertiesComponentFactoryBean	{
				@Produces
				@Named("properties")
				@ApplicationScoped
				PropertiesComponent	propertiesComponent()	{
								PropertiesComponent	properties	=	new	PropertiesComponent();
								properties.setLocation("classpath:camel.properties");
								return	properties;
				}
}
…
Second	goal	achieved	3/3

And	get	rid	of	the	code	related	to	the	 properties 	and	 sjms
components	registration
@ApplicationScoped
class	CamelContextBean	extends	DefaultCamelContext	{
				@Inject
				CamelContextBean(FileToJmsRouteBean	route,	SjmsComponent	jms,	PropertiesComponent	properties)	{
								addComponent("properties",	propertiesComponent);
								addComponent("sjms",	sjmsComponent);
								addRoutes(route);
				}
				@PostConstruct
				void	startContext()	{
								super.start();
				}
				@PreDestroy
				void	stopContext()	{
								super.stop();
				}
}
Third	goal:	Support	Camel	annotations	in	CDI	beans

Camel	provides	a	set	of	DI	framework	agnostic	annotations	for
resource	injection
@PropertyInject(value	=	"jms.maxConnections",	defaultValue	=	"10")
int	maxConnections;
//	But	also...
@EndpointInject(uri	=	"jms:queue:foo")
Endpoint	endpoint;
@BeanInject("foo")
FooBean	foo;
	How	to	support	custom	annotations	injection?
How	to	support	custom	annotations	injection?

Create	a	custom	 InjectionTarget 	that	uses	the	default	Camel	bean
post	processor	 DefaultCamelBeanPostProcessor
public	interface	InjectionTarget<T>	extends	Producer<T>	{
				void	inject(T	instance,	CreationalContext<T>	ctx);
				void	postConstruct(T	instance);
				void	preDestroy(T	instance);
}

Hook	it	into	the	CDI	injection	mechanism	by	observing	the
ProcessInjectionTarget 	lifecycle	event
 Only	for	beans	containing	Camel	annotations	by	observing	the
ProcessAnnotatedType 	lifecycle	and	using	 @WithAnnotations
Create	a	custom	 InjectionTarget
class	CamelInjectionTarget<T>	implements	InjectionTarget<T>	{
				final	InjectionTarget<T>	delegate;
				final	DefaultCamelBeanPostProcessor	processor;
				CamelInjectionTarget(InjectionTarget<T>	target,	final	BeanManager	bm)	{
								delegate	=	target;
								processor	=	new	DefaultCamelBeanPostProcessor()	{
												public	CamelContext	getOrLookupCamelContext()	{
																return	getReference(bm,	CamelContext.class);
												}
								};
				}
				public	void	inject(T	instance,	CreationalContext<T>	ctx)	{
								processor.postProcessBeforeInitialization(instance,	null);	
								delegate.inject(instance,	ctx);
				}
				//...
}
Call	the	Camel	default	bean	post-processor	before	CDI	injection
1
1
Register	the	custom	 InjectionTarget

Observe	the	 ProcessInjectionTarget 	lifecycle	event	and	set	the
InjectionTarget
public	interface	ProcessInjectionTarget<X>	{
				AnnotatedType<X>	getAnnotatedType();
				InjectionTarget<X>	getInjectionTarget();
				void	setInjectionTarget(InjectionTarget<X>	injectionTarget);
				void	addDefinitionError(Throwable	t);
}
 To	decorate	it	with	the	 CamelInjectionTarget
class	CamelExtension	implements	Extension	{
				<T>	void	camelBeansPostProcessor(@Observes	ProcessInjectionTarget<T>	pit,	BeanManager	bm)	{
								pit.setInjectionTarget(new	CamelInjectionTarget<>(pit.getInjectionTarget(),	bm));
				}
}
But	only	for	beans	containing	Camel	annotations
class	CamelExtension	implements	Extension	{
				final	Set<AnnotatedType<?>>	camelBeans	=	new	HashSet<>();
				void	camelAnnotatedTypes(@Observes	@WithAnnotations(PropertyInject.class)
								ProcessAnnotatedType<?>	pat)	{	
												camelBeans.add(pat.getAnnotatedType());
				}
				<T>	void	camelBeansPostProcessor(@Observes	ProcessInjectionTarget<T>	pit,
								BeanManager	bm)	{
								if	(camelBeans.contains(pit.getAnnotatedType()))	
												pit.setInjectionTarget(
																new	CamelInjectionTarget<>(pit.getInjectionTarget(),	bm));
				}
}
Detect	all	the	types	containing	Camel	annotations	with	 @WithAnnotations
Decorate	the	 InjectionTarget 	corresponding	to	these	types
1
2
1
2
Third	goal	achieved	1/2

Instead	of	injecting	the	 PropertiesComponent 	bean	to	resolve	a
configuration	property
class	JmsComponentFactoryBean	{
				@Produces
				@Named("sjms")
				@ApplicationScoped
				SjmsComponent	sjmsComponent(PropertiesComponent	properties)	{
								SjmsComponent	jms	=	new	SjmsComponent();
								jms.setConnectionFactory(new	ActiveMQConnectionFactory("vm://broker?..."));
								jms.setConnectionCount(Integer.valueOf(properties.parseUri("{{jms.maxConnections}}")));
								return	component;
				}
}
Third	goal	achieved	2/2

We	can	directly	rely	on	the	 @PropertyInject 	Camel	annotation	in
CDI	beans
class	JmsComponentFactoryBean	{
				@PropertyInject("jms.maxConnections")
				int	maxConnections;
				@Produces
				@Named("sjms")
				@ApplicationScoped
				SjmsComponent	sjmsComponent()	{
								SjmsComponent	component	=	new	SjmsComponent();
								jms.setConnectionFactory(new	ActiveMQConnectionFactory("vm://broker?..."));
								component.setConnectionCount(maxConnections);
								return	component;
				}
}
Bonus	goal:	Camel	DSL	AOP
 AOP	instrumentation	of	the	Camel	DSL
from("file:target/input?delay=1000")
				.log("Sending	message	[${body}]	to	JMS...")
				.to("sjms:queue:output");
 With	CDI	observers
from("file:target/input?delay=1000")
				.to("sjms:queue:output").id("join	point");
}
void	advice(@Observes	@NodeId("join	point")	Exchange	exchange)	{
				logger.info("Sending	message	[{}]	to	JMS...",	exchange.getIn().getBody());
}
How	to	achieve	this?
 We	can	create	a	CDI	qualifier	to	hold	the	Camel	node	id	metadata:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public	@interface	NodeId	{
				String	value();
}
 And	create	an	extension	that	will:
1.	 Detect	the	CDI	beans	containing	observer	methods	with	the	 @NodeId
qualifier	by	observing	the	 ProcessObserverMethod 	event	and	collect
the	Camel	processor	nodes	to	be	instrumented
2.	 Customize	the	Camel	context	by	providing	an	implementation	of	the
Camel	 InterceptStrategy 	interface	that	will	fire	a	CDI	event	each
time	an	 Exchange 	is	processed	by	the	instrumented	nodes
Detect	the	Camel	DSL	AOP	observer	methods
 Observe	the	 ProcessObserverMethod 	lifecycle	event
public	interface	ProcessObserverMethod<T,	X>	{
				AnnotatedMethod<X>	getAnnotatedMethod();
				ObserverMethod<T>	getObserverMethod();
				void	addDefinitionError(Throwable	t);
}
 And	collect	the	observer	method	metadata
class	CamelExtension	implements	Extension	{
				final	Set<NodeId>	joinPoints	=	new	HashSet<>();
				void	pointcuts(@Observes	ProcessObserverMethod<Exchange,	?>	pom)	{
								for	(Annotation	qualifier	:	pom.getObserverMethod().getObservedQualifiers())
												if	(qualifier	instanceof	NodeId)
																joinPoints.add(NodeId.class.cast(qualifier));
				}
}
Instrument	the	Camel	context
 Intercept	matching	nodes	and	fire	a	CDI	event
void	configureCamelContext(@Observes	AfterDeploymentValidation	adv,	final	BeanManager	manager)	{
				context.addInterceptStrategy(new	InterceptStrategy()	{
						public	Processor	wrapProcessorInInterceptors(CamelContext	context,	ProcessorDefinition<?>	definition,
										Processor	target,	Processor	nextTarget)	throws	Exception	{
												if	(definition.hasCustomIdAssigned())	{
																for	(final	Node	node	:	joinPoints)	{
																				if	(node.value().equals(definition.getId()))	{
																								return	new	DelegateAsyncProcessor(target)	{
																												public	boolean	process(Exchange	exchange,	AsyncCallback	callback)	{
																																manager.fireEvent(exchange,	node);
																																return	super.process(exchange,	callback);
																												}
																								};
																				}
																}
												}
												return	target;
								}
				});
}
Bonus	goal	achieved
 We	can	define	join	points	in	the	Camel	DSL
from("file:target/input?delay=1000")
				.to("sjms:queue:output").id("join	point");
}
 And	advise	them	with	CDI	observers
void	advice(@Observes	@NodeId("join	point")	Exchange	exchange)	{
				List<MessageHistory>	history	=	exchange.getProperty(Exchange.MESSAGE_HISTORY,	List.class);
				logger.info("Sending	message	[{}]	to	[{}]...",	exchange.getIn().getBody(String.class),
								history.get(history.size()	-	1).getNode().getLabel());
}
Conclusion
References
 CDI	Specification	-	cdi-spec.org
 Slides	sources	-	github.com/astefanutti/further-cdi
 Metrics	CDI	sources	-	github.com/astefanutti/metrics-cdi
 Camel	CDI	sources	-	github.com/astefanutti/camel-cdi
 Slides	generated	with	Asciidoctor,	PlantUML	and	DZSlides	backend
 Original	slide	template	-	Dan	Allen	&	Sarah	White
Antoine	Sabot-Durand
Antonin	Stefanutti
	@antoine_sd	@astefanut
Annexes
Complete	lifecycle	events
Application lifecycle
BeforeBeanDiscovery
AfterTypeDiscovery
AfterBeanDiscovery
AfterDeploymentValidation
Type Discovery
ProcessAnnotatedType<X>
yes
while	types	in
deployment	archive?
no
Bean Discovery
For each discovered types during type discovery
ProcessInjectionPoint<T,	X>
ProcessInjectionTarget<X>
ProcessBeanAttributes<T>
ProcessManagedBean<X>
For each producer methods / fields of enabled beans
ProcessInjectionPoint<T,	X>
ProcessProducer<T,	X>
ProcessBeanAttributes<T>
ProcessProducerMethod<T,	X>
ProcessProducerField<T,	X>
For each observer methods of enabled beans
ProcessInjectionPoint<T,	X>
ProcessObserverMethod<T,	X>

Mais conteúdo relacionado

Mais procurados

Binary Authorization in Kubernetes
Binary Authorization in KubernetesBinary Authorization in Kubernetes
Binary Authorization in KubernetesAysylu Greenberg
 
Software Supply Chain Management with Grafeas and Kritis
Software Supply Chain Management with Grafeas and KritisSoftware Supply Chain Management with Grafeas and Kritis
Software Supply Chain Management with Grafeas and KritisAysylu Greenberg
 
Software Supply Chain Management with Grafeas and Kritis
Software Supply Chain Management with Grafeas and KritisSoftware Supply Chain Management with Grafeas and Kritis
Software Supply Chain Management with Grafeas and KritisAysylu Greenberg
 
Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)
Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)
Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)Mihail Stoynov
 
Scala on androids
Scala on androidsScala on androids
Scala on androidsthoraage
 
Trying to build an Open Source browser in 2020
Trying to build an Open Source browser in 2020Trying to build an Open Source browser in 2020
Trying to build an Open Source browser in 2020Patricia Aas
 
Hands on React Native: From Zero to Hero
Hands on React  Native:  From Zero to HeroHands on React  Native:  From Zero to Hero
Hands on React Native: From Zero to HeroDmitry Vinnik
 
OSGi, Eclipse and API Tooling
OSGi, Eclipse and API ToolingOSGi, Eclipse and API Tooling
OSGi, Eclipse and API ToolingChris Aniszczyk
 
Tdd is not about testing (C++ version)
Tdd is not about testing (C++ version)Tdd is not about testing (C++ version)
Tdd is not about testing (C++ version)Gianluca Padovani
 
Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Gianluca Padovani
 
Continuous Integration on my work
Continuous Integration on my workContinuous Integration on my work
Continuous Integration on my workMu Chun Wang
 
Professional iOS development
Professional iOS developmentProfessional iOS development
Professional iOS developmentAline Borges
 
Back-2-Basics: Code Contracts
Back-2-Basics: Code ContractsBack-2-Basics: Code Contracts
Back-2-Basics: Code ContractsDavid McCarter
 
QA Fest 2019. Boni Garcia. Web and Mobile testing with Selenium, JUnit 5, and...
QA Fest 2019. Boni Garcia. Web and Mobile testing with Selenium, JUnit 5, and...QA Fest 2019. Boni Garcia. Web and Mobile testing with Selenium, JUnit 5, and...
QA Fest 2019. Boni Garcia. Web and Mobile testing with Selenium, JUnit 5, and...QAFest
 
App server4rpg - English
App server4rpg - EnglishApp server4rpg - English
App server4rpg - EnglishCOMMON Europe
 
The DevSecOps Builder’s Guide to the CI/CD Pipeline
The DevSecOps Builder’s Guide to the CI/CD PipelineThe DevSecOps Builder’s Guide to the CI/CD Pipeline
The DevSecOps Builder’s Guide to the CI/CD PipelineJames Wickett
 

Mais procurados (20)

Android NDK: Entrando no Mundo Nativo
Android NDK: Entrando no Mundo NativoAndroid NDK: Entrando no Mundo Nativo
Android NDK: Entrando no Mundo Nativo
 
Binary Authorization in Kubernetes
Binary Authorization in KubernetesBinary Authorization in Kubernetes
Binary Authorization in Kubernetes
 
Software Supply Chain Management with Grafeas and Kritis
Software Supply Chain Management with Grafeas and KritisSoftware Supply Chain Management with Grafeas and Kritis
Software Supply Chain Management with Grafeas and Kritis
 
Software Supply Chain Management with Grafeas and Kritis
Software Supply Chain Management with Grafeas and KritisSoftware Supply Chain Management with Grafeas and Kritis
Software Supply Chain Management with Grafeas and Kritis
 
Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)
Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)
Modules in Java? Finally! (OpenJDK 9 Jigsaw, JSR376)
 
Let your tests drive your code
Let your tests drive your codeLet your tests drive your code
Let your tests drive your code
 
Scala on androids
Scala on androidsScala on androids
Scala on androids
 
Trying to build an Open Source browser in 2020
Trying to build an Open Source browser in 2020Trying to build an Open Source browser in 2020
Trying to build an Open Source browser in 2020
 
Hands on React Native: From Zero to Hero
Hands on React  Native:  From Zero to HeroHands on React  Native:  From Zero to Hero
Hands on React Native: From Zero to Hero
 
OSGi, Eclipse and API Tooling
OSGi, Eclipse and API ToolingOSGi, Eclipse and API Tooling
OSGi, Eclipse and API Tooling
 
Tdd is not about testing (C++ version)
Tdd is not about testing (C++ version)Tdd is not about testing (C++ version)
Tdd is not about testing (C++ version)
 
Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Tdd is not about testing (OOP)
Tdd is not about testing (OOP)
 
Continuous Integration on my work
Continuous Integration on my workContinuous Integration on my work
Continuous Integration on my work
 
Professional iOS development
Professional iOS developmentProfessional iOS development
Professional iOS development
 
Back-2-Basics: Code Contracts
Back-2-Basics: Code ContractsBack-2-Basics: Code Contracts
Back-2-Basics: Code Contracts
 
QA Fest 2019. Boni Garcia. Web and Mobile testing with Selenium, JUnit 5, and...
QA Fest 2019. Boni Garcia. Web and Mobile testing with Selenium, JUnit 5, and...QA Fest 2019. Boni Garcia. Web and Mobile testing with Selenium, JUnit 5, and...
QA Fest 2019. Boni Garcia. Web and Mobile testing with Selenium, JUnit 5, and...
 
Ard gate - English
Ard gate - EnglishArd gate - English
Ard gate - English
 
App server4rpg - English
App server4rpg - EnglishApp server4rpg - English
App server4rpg - English
 
The DevSecOps Builder’s Guide to the CI/CD Pipeline
The DevSecOps Builder’s Guide to the CI/CD PipelineThe DevSecOps Builder’s Guide to the CI/CD Pipeline
The DevSecOps Builder’s Guide to the CI/CD Pipeline
 
Webinar on Google Android SDK
Webinar on Google Android SDKWebinar on Google Android SDK
Webinar on Google Android SDK
 

Destaque

Java EE, un ami qui vous veut du bien
Java EE, un ami qui vous veut du bienJava EE, un ami qui vous veut du bien
Java EE, un ami qui vous veut du bienAntoine Sabot-Durand
 
Invoke dynamite in Java EE with invoke dynamic
Invoke dynamite in Java EE with invoke dynamicInvoke dynamite in Java EE with invoke dynamic
Invoke dynamite in Java EE with invoke dynamicAntoine Sabot-Durand
 
Introduction to cdi given at java one 2014
Introduction to cdi given at java one 2014Introduction to cdi given at java one 2014
Introduction to cdi given at java one 2014Antoine Sabot-Durand
 
CDI mis en pratique avec Seam Social et Weld OSGI
CDI mis en pratique avec Seam Social et Weld OSGICDI mis en pratique avec Seam Social et Weld OSGI
CDI mis en pratique avec Seam Social et Weld OSGIAntoine Sabot-Durand
 
The Magnificent java EE 7 in Wildfly-O-Rama
The Magnificent java EE 7 in Wildfly-O-RamaThe Magnificent java EE 7 in Wildfly-O-Rama
The Magnificent java EE 7 in Wildfly-O-RamaAntoine Sabot-Durand
 
1/3 : introduction to CDI - Antoine Sabot-Durand
1/3 : introduction to CDI - Antoine Sabot-Durand1/3 : introduction to CDI - Antoine Sabot-Durand
1/3 : introduction to CDI - Antoine Sabot-DurandSOAT
 
Fais ce que tu veux avec Java EE - Devoxx France 2014
Fais ce que tu veux avec Java EE - Devoxx France 2014Fais ce que tu veux avec Java EE - Devoxx France 2014
Fais ce que tu veux avec Java EE - Devoxx France 2014Antoine Sabot-Durand
 
Architecting Large Enterprise Projects @DevConf.CZ
Architecting Large Enterprise Projects @DevConf.CZArchitecting Large Enterprise Projects @DevConf.CZ
Architecting Large Enterprise Projects @DevConf.CZMarkus Eisele
 
Kids computer-programming
Kids computer-programmingKids computer-programming
Kids computer-programmingEdward Burns
 
Java 8, Streams & Collectors, patterns, performances and parallelization
Java 8, Streams & Collectors, patterns, performances and parallelizationJava 8, Streams & Collectors, patterns, performances and parallelization
Java 8, Streams & Collectors, patterns, performances and parallelizationJosé Paumard
 

Destaque (16)

Mute Java EE DNA with CDI
Mute Java EE DNA with CDI Mute Java EE DNA with CDI
Mute Java EE DNA with CDI
 
Java EE, un ami qui vous veut du bien
Java EE, un ami qui vous veut du bienJava EE, un ami qui vous veut du bien
Java EE, un ami qui vous veut du bien
 
Devoxx Java Social and Agorava
Devoxx Java Social and AgoravaDevoxx Java Social and Agorava
Devoxx Java Social and Agorava
 
Invoke dynamite in Java EE with invoke dynamic
Invoke dynamite in Java EE with invoke dynamicInvoke dynamite in Java EE with invoke dynamic
Invoke dynamite in Java EE with invoke dynamic
 
Apache DeltaSpike the CDI toolbox
Apache DeltaSpike the CDI toolboxApache DeltaSpike the CDI toolbox
Apache DeltaSpike the CDI toolbox
 
Going further with CDI 1.2
Going further with CDI 1.2Going further with CDI 1.2
Going further with CDI 1.2
 
Introduction to cdi given at java one 2014
Introduction to cdi given at java one 2014Introduction to cdi given at java one 2014
Introduction to cdi given at java one 2014
 
CDI mis en pratique avec Seam Social et Weld OSGI
CDI mis en pratique avec Seam Social et Weld OSGICDI mis en pratique avec Seam Social et Weld OSGI
CDI mis en pratique avec Seam Social et Weld OSGI
 
Java EE 6 & Spring: A Lover's Quarrel
Java EE 6 & Spring: A Lover's QuarrelJava EE 6 & Spring: A Lover's Quarrel
Java EE 6 & Spring: A Lover's Quarrel
 
CDI In Real Life
CDI In Real LifeCDI In Real Life
CDI In Real Life
 
The Magnificent java EE 7 in Wildfly-O-Rama
The Magnificent java EE 7 in Wildfly-O-RamaThe Magnificent java EE 7 in Wildfly-O-Rama
The Magnificent java EE 7 in Wildfly-O-Rama
 
1/3 : introduction to CDI - Antoine Sabot-Durand
1/3 : introduction to CDI - Antoine Sabot-Durand1/3 : introduction to CDI - Antoine Sabot-Durand
1/3 : introduction to CDI - Antoine Sabot-Durand
 
Fais ce que tu veux avec Java EE - Devoxx France 2014
Fais ce que tu veux avec Java EE - Devoxx France 2014Fais ce que tu veux avec Java EE - Devoxx France 2014
Fais ce que tu veux avec Java EE - Devoxx France 2014
 
Architecting Large Enterprise Projects @DevConf.CZ
Architecting Large Enterprise Projects @DevConf.CZArchitecting Large Enterprise Projects @DevConf.CZ
Architecting Large Enterprise Projects @DevConf.CZ
 
Kids computer-programming
Kids computer-programmingKids computer-programming
Kids computer-programming
 
Java 8, Streams & Collectors, patterns, performances and parallelization
Java 8, Streams & Collectors, patterns, performances and parallelizationJava 8, Streams & Collectors, patterns, performances and parallelization
Java 8, Streams & Collectors, patterns, performances and parallelization
 

Semelhante a Advanced CDI in live coding

Stanislav Khorunzhyi, "Front-end it like a PRO"
Stanislav Khorunzhyi, "Front-end it like a PRO"Stanislav Khorunzhyi, "Front-end it like a PRO"
Stanislav Khorunzhyi, "Front-end it like a PRO"Sigma Software
 
Git Tutorial A Comprehensive Guide for Beginners.pdf
Git Tutorial A Comprehensive Guide for Beginners.pdfGit Tutorial A Comprehensive Guide for Beginners.pdf
Git Tutorial A Comprehensive Guide for Beginners.pdfuzair
 
Optimizing developer onboarding
Optimizing developer onboardingOptimizing developer onboarding
Optimizing developer onboarding🌯 Brian Douglas
 
Introduction to DevOps
Introduction to DevOpsIntroduction to DevOps
Introduction to DevOpsOmid Vahdaty
 
DevOps - Interview Question.pdf
DevOps - Interview Question.pdfDevOps - Interview Question.pdf
DevOps - Interview Question.pdfMinhTrnNht7
 
Bending Open Atrium to your will!
Bending Open Atrium to your will!Bending Open Atrium to your will!
Bending Open Atrium to your will!Jeff Miccolis
 
La importancia de versionar el código: GitHub, portafolio y recursos para est...
La importancia de versionar el código: GitHub, portafolio y recursos para est...La importancia de versionar el código: GitHub, portafolio y recursos para est...
La importancia de versionar el código: GitHub, portafolio y recursos para est...CloudNativeElSalvado
 
PyCourse - Self driving python course
PyCourse - Self driving python coursePyCourse - Self driving python course
PyCourse - Self driving python courseEran Shlomo
 
A startup with no office, hipster tools and open source products
A startup with no office, hipster tools and open source productsA startup with no office, hipster tools and open source products
A startup with no office, hipster tools and open source productsFrank Rousseau
 
“TensorFlow Lite for Microcontrollers (TFLM): Recent Developments,” a Present...
“TensorFlow Lite for Microcontrollers (TFLM): Recent Developments,” a Present...“TensorFlow Lite for Microcontrollers (TFLM): Recent Developments,” a Present...
“TensorFlow Lite for Microcontrollers (TFLM): Recent Developments,” a Present...Edge AI and Vision Alliance
 
Open frameworks 101_fitc
Open frameworks 101_fitcOpen frameworks 101_fitc
Open frameworks 101_fitcbenDesigning
 
PyCon2022 - Building Python Extensions
PyCon2022 - Building Python ExtensionsPyCon2022 - Building Python Extensions
PyCon2022 - Building Python ExtensionsHenry Schreiner
 
Continuous Delivery for Python Developers – PyCon Otto
Continuous Delivery for Python Developers – PyCon OttoContinuous Delivery for Python Developers – PyCon Otto
Continuous Delivery for Python Developers – PyCon OttoPeter Bittner
 
DevOps - A Purpose for an Institution.pdf
DevOps - A Purpose for an Institution.pdfDevOps - A Purpose for an Institution.pdf
DevOps - A Purpose for an Institution.pdfVishwas N
 
Building our Component Library
Building our Component LibraryBuilding our Component Library
Building our Component LibraryClement Ho
 
Hacktoberfest 2020 - Open source for beginners
Hacktoberfest 2020 - Open source for beginnersHacktoberfest 2020 - Open source for beginners
Hacktoberfest 2020 - Open source for beginnersDeepikaRana30
 

Semelhante a Advanced CDI in live coding (20)

Is Python still production ready ? Ludovic Gasc
Is Python still production ready ? Ludovic GascIs Python still production ready ? Ludovic Gasc
Is Python still production ready ? Ludovic Gasc
 
Stanislav Khorunzhyi, "Front-end it like a PRO"
Stanislav Khorunzhyi, "Front-end it like a PRO"Stanislav Khorunzhyi, "Front-end it like a PRO"
Stanislav Khorunzhyi, "Front-end it like a PRO"
 
Git Tutorial A Comprehensive Guide for Beginners.pdf
Git Tutorial A Comprehensive Guide for Beginners.pdfGit Tutorial A Comprehensive Guide for Beginners.pdf
Git Tutorial A Comprehensive Guide for Beginners.pdf
 
Optimizing developer onboarding
Optimizing developer onboardingOptimizing developer onboarding
Optimizing developer onboarding
 
Raising the Bar
Raising the BarRaising the Bar
Raising the Bar
 
Introduction to DevOps
Introduction to DevOpsIntroduction to DevOps
Introduction to DevOps
 
From open source labs to ceo methods and advice by sysfera
From open source labs to ceo methods and advice by sysferaFrom open source labs to ceo methods and advice by sysfera
From open source labs to ceo methods and advice by sysfera
 
DevOps - Interview Question.pdf
DevOps - Interview Question.pdfDevOps - Interview Question.pdf
DevOps - Interview Question.pdf
 
Bending Open Atrium to your will!
Bending Open Atrium to your will!Bending Open Atrium to your will!
Bending Open Atrium to your will!
 
La importancia de versionar el código: GitHub, portafolio y recursos para est...
La importancia de versionar el código: GitHub, portafolio y recursos para est...La importancia de versionar el código: GitHub, portafolio y recursos para est...
La importancia de versionar el código: GitHub, portafolio y recursos para est...
 
PyCourse - Self driving python course
PyCourse - Self driving python coursePyCourse - Self driving python course
PyCourse - Self driving python course
 
A startup with no office, hipster tools and open source products
A startup with no office, hipster tools and open source productsA startup with no office, hipster tools and open source products
A startup with no office, hipster tools and open source products
 
“TensorFlow Lite for Microcontrollers (TFLM): Recent Developments,” a Present...
“TensorFlow Lite for Microcontrollers (TFLM): Recent Developments,” a Present...“TensorFlow Lite for Microcontrollers (TFLM): Recent Developments,” a Present...
“TensorFlow Lite for Microcontrollers (TFLM): Recent Developments,” a Present...
 
Open frameworks 101_fitc
Open frameworks 101_fitcOpen frameworks 101_fitc
Open frameworks 101_fitc
 
Untangling4
Untangling4Untangling4
Untangling4
 
PyCon2022 - Building Python Extensions
PyCon2022 - Building Python ExtensionsPyCon2022 - Building Python Extensions
PyCon2022 - Building Python Extensions
 
Continuous Delivery for Python Developers – PyCon Otto
Continuous Delivery for Python Developers – PyCon OttoContinuous Delivery for Python Developers – PyCon Otto
Continuous Delivery for Python Developers – PyCon Otto
 
DevOps - A Purpose for an Institution.pdf
DevOps - A Purpose for an Institution.pdfDevOps - A Purpose for an Institution.pdf
DevOps - A Purpose for an Institution.pdf
 
Building our Component Library
Building our Component LibraryBuilding our Component Library
Building our Component Library
 
Hacktoberfest 2020 - Open source for beginners
Hacktoberfest 2020 - Open source for beginnersHacktoberfest 2020 - Open source for beginners
Hacktoberfest 2020 - Open source for beginners
 

Último

SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 

Último (20)

E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 

Advanced CDI in live coding