scalableenterpriseapplicationswith jee7andbeyond

51
2013 © Trivadis BASEL BERN LAUSANNE ZÜRICH DÜSSELDORF FRANKFURT A.M. FREIBURG I.BR. HAMBURG MÜNCHEN STUTTGART WIEN JUG Münster Scalable enterprise applications with JEE7 and beyond Andy Moncsek 17. April 2013 18.07.2013 JEE to the Max 1

Upload: andy-moncsek

Post on 02-Jul-2015

405 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

BASEL BERN LAUSANNE ZÜRICH DÜSSELDORF FRANKFURT A.M. FREIBURG I.BR. HAMBURG MÜNCHEN STUTTGART WIEN

JUG Münster Scalable enterprise

applications with JEE7

and beyond

Andy Moncsek

17. April 2013

18.07.2013

JEE to the Max

1

Page 2: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

BASEL BERN LAUSANNE ZÜRICH DÜSSELDORF FRANKFURT A.M. FREIBURG I.BR. HAMBURG MÜNCHEN STUTTGART WIEN

Andy Moncsek

Consultant for Application Devlopment (Zürich)

Trainer for JavaEE Assembly & Deployment

Contacts: [email protected]

Twitter: @AndyAHCP

Page 3: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

AGENDA

1. Motivation

2. Server Sent Events

3. WebSocket (JSR-356)

4. SSE & WebSockets in Enterprise

Security

Loadbalancing / Failover

5. (short) JEE 7 project overview

18.07.2013

JEE to the Max

3

Page 4: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Motivation

18.07.2013

JEE to the Max

4

JEE 7

what’s new?

Page 5: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Motivation

18.07.2013

JEE to the Max

5

state: function() { return state; }, always: function() { deferred.done(

arguments ).fail( arguments ); return this; }, then: function( /*

fnDone, fnFail, fnProgress */ ) { var fns = arguments; return

jQuery.Deferred(function( newDefer ) { jQuery.each( tuples,

function( i, tuple ) { var action = tuple[ 0 ], fn = jQuery.isFunction(

fns[ i ] ) && fns[ i ]; // deferred[ done | fail | progress ] for

forwarding actions to newDefer deferred[ tuple[1] ](function() { var

returned = fn && fn.apply( this, arguments ); if ( returned &&

jQuery.isFunction( returned.promise ) ) { returned.promise() .done(

newDefer.resolve ) .fail( newDefer.reject ) .progress(

newDefer.notify ); } else { newDefer[ action + "With" ]( this ===

promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );

} }); }); fns = null; }).promise(); },

Page 6: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Focus

18.07.2013

JEE to the Max

6

Java

Page 7: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Server Sent Events

18.07.2013

JEE to the Max

7

Page 8: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Server Sent Events - Overview

• push from server to client

• SSE EventSource API part

of HTML5

• Part of Jersey 2 API’s (JAX-RS)

• JMS – Topic(Light)?

18.07.2013

JEE to the Max

8

Page 9: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

SSE

DEMO

https://bitbucket.org/amoncsek/jeemax

18.07.2013

JEE to the Max

9

Page 10: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

SSE

18.07.2013

JEE to the Max

10

TimerBean:

write(new Event(«custom»,data));

Handle:void onEvent(InboundEvent e)

@Path(«myEventStream»)

Subscibe once:new EventSource(http://.../myEventStream)

Page 11: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

SSE- ServerSide

• Subscribe an Event Stream

@GET

@Produces(SseFeature.SERVER_SENT_EVENTS)

public EventOutput getEventStream() {

return new EventOutput();

}

• Put Message to EventOutput

EventOutput.write(

new OutboundEvent("custom-message“, message))

18.07.2013

JEE to the Max

11

Page 12: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

SSE– ClientSide (Jersey 2 API’s)

• Client API

Client client = ClientBuilder.newClient();

WebTarget webTarget = client.target(TARGET_URI);

• EventSource API

new EventSource(webTarget) {

public void onEvent(InboundEvent event) {…}

}

18.07.2013

JEE to the Max

12

Page 13: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

SSE– Best Practice

• Client: EventSource.close() also closes the Server: EventOutput!

• Use SseBroadcaster to broadcast messages to EventOutput

• Register: SseBroadcaster.add(EventOutput)

• Broadcast: SseBroadcaster.broadcast(OutboundEvent)

• Use Server: OutboundEvent.name(«myMessage») to filter

messages (like JMS message-property/selector)

• Client: InboundEvent.getName().equals(«myMessage»)

18.07.2013

JEE to the Max

13

Page 14: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

SSE

Any questions?

18.07.2013

JEE to the Max

14

Page 15: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket (JSR-356)

18.07.2013

JEE to the Max

15

Page 16: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket - Overview

18.07.2013

JEE to the Max

16

• Full duplex communication in either

direction

• Java API for Server- and Client-Side

(JEE7)

• Programmatic and annotation-based

endpoints

• Support for Encoder/Decoder to map

message to Java objects

• Support for @PathParam

Page 17: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket(JSR 356) - Overview

18.07.2013

JEE to the Max

17

• Part of Glassfish 4

• Tyrus project:

• reference implementation for JSR 356 WebSocket API for Java

• http://java.net/projects/tyrus

Page 18: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket

18.07.2013

JEE to the Max

18

@ServerEndpoint("/bookings") @ClientEndpoint

Session Session

messages

Connect

Page 19: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket – ServerEndpoint (by annotation)

18.07.2013

JEE to the Max

19

• Creating Server Endpoints with annotation

@ServerEndpoint("/bookings")

public class BookingEndpoint {

@OnOpen

public void init(Session s) {}

@OnClose

@OnError

@OnMessage

public void handleMessage(Message m, Session s) {}

}

Page 20: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket – ServerEndpoint (programmatic)

18.07.2013

JEE to the Max

20

• Creating Server Endpoints programmatic

public class BookingEndpoint extends Endpoint {

@Override

public void onOpen(Session s, EndpointConfig ec) {

s.addMessageHandler(new MessageHandler() {

@Override

public void onMessage(String text) {…}

});

}

}

Page 21: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket - ServerEndpoint

18.07.2013

JEE to the Max

21

• Configuring a programmatic Endpoint (WebSocket runtime scans the

WAR)

public class WSAppConfig implements ServerApplicationConfig

{

public Set<ServerEndpointConfig> getEndpointConfigs(Set

set) {

add(ServerEndpointConfig.Builder

.create(BookingEndpoint.class, "/bookings")

.build());

}

}

Page 22: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket - ClientEndpoint

18.07.2013

JEE to the Max

22

• Creating Client Endpoints with annotation

@ClientEndpoint

public class Booking {

@OnOpen

@OnClose

@OnError

@OnMessage

}

Page 23: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket - ClientEndpoint

18.07.2013

JEE to the Max

• Creating programmatic Client Endpoint

public class Booking extends Endpoint {

@Override

public void onOpen(Session s, EndpointConfig c) {

s.addMessageHandler(…);

}

}

23

Page 24: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket - ClientEndpoint

18.07.2013

JEE to the Max

24

• Configure a Client Endpoint

ClientManager client = ClientManager.createClient();

ClientEndpointConfig config =

ClientEndpointConfig.Builder.create();

client.connectToServer(new Booking(),config

URI.create(“ws://host/bookings“));

Or

client.connectToServer(Booking.class,config

URI.create(“ws://host/bookings“));

Page 25: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket Encoder/Decoder

• Native Message-format is:

• Text

• Binary

• Pong (check connection)

• Encoders:

• Encode message from Java Object to Binary / Text

• Decoders

• Decode message from Binary / Text to Java Object

18.07.2013

JEE to the Max

25

Page 26: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket Encoder

public class MEnc implements Encoder.Binary<Message> {

@Override

public ByteBuffer encode(Message m) throws EncodeException {

return ByteBuffer.wrap(SerializationUtils.serialize(message));

}

}

Register Encoders

Client: @ClientEndpoint(encoders = {Menc.class, Menc2.class})

Server: @ServerEndpoint(encoders = {Menc.class, Menc2.class})

18.07.2013

JEE to the Max

26

Page 27: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket Decoder

public class MessageDecoder implements Decoder.Binary<Message> {

public Message decode(ByteBuffer b) throws DecodeException {

return (Message) SerializationUtils.deserialize(b.array()); }

public boolean willDecode(ByteBuffer b) {

return true }

}

Register Decoders

Client: @ClientEndpoint(decoders = {MessageDecoder.class, Dec.class})

Server: @ServerEndpoint(decoders = {MessageDecoder.class, Dec.class})

18.07.2013

JEE to the Max

27

Page 28: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSocket @PathParam

• Annotate one or more parameters on:

• @OnMessage, @OnError, @OnClose, @OnOpen

@ServerEndpoint("/bookings/{id}")

public class BookingEndpoint {

@OnMessage

public void handle(@PathParam(“id”) String id,

Message m, Session s) {}

}

18.07.2013

JEE to the Max

28

Page 29: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSockets – sending messages

• BUT… how to send messages?

• BasicRemote: blocking until message has been transmitted• session.getBasicRemote().sendObject(message);

• AsyncRemote: fire and forget• Future<Void> v =

session.getAsyncRemote().sendObject(message);

• Progress may be tracked using the Future Object

18.07.2013

JEE to the Max

29

Page 30: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSockets – Broadcasting messages

• interaction with other Sessions

• Identify Sessions by ID

• Only Sessions in same Endpoint are accessible

• Sessions only accessible trough Session:

• session.getOpenSessions()

18.07.2013

JEE to the Max

30

Page 31: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Best Practice

• No automatic reconnection:

• Use OnError to reconnect

• Use Session.getUserProperties() to store additional informations

• Server Endpoitns have full support for CDI and @Inject

• Endpoint can be @Singleton / @Stateless… but requirement was

removed from spec!

18.07.2013

JEE to the Max

31

Page 32: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Best Practice

• One handling method per type!:

• Each websocket endpoint may only have one message handling

method for each of the native websocket message formats.

• Solution: inherence, Enums,…

18.07.2013

JEE to the Max

32

@OnMessage

public void onAddUser(AddUser user) {

}

@OnMessage

public void onMessage(Message m) {

}

@OnMessage

public void onChatMessage(Message chatMessage) {

switch (chatMessage.getType()){

case MESSAGE:

break;

case ADD_USER:

break;

}

}

Page 33: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

WebSockets

Any questions?

18.07.2013

JEE to the Max

33

Page 34: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

SSE / WebSockets in Enterprise

SSE / WebSockets in Enterprise

Securtity

18.07.2013

JEE to the Max

34

Page 35: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Security – Jersey 2 SSE

• Basic authentication - Jersey 2 way:

Client client = ClientBuilder.newBuilder().build();

WebTarget webTarget = client.target(restURL);

webTarget.register(new HttpBasicAuthFilter(user, pwd));

• Easy SSL konfigurations

SslConfigurator sslConfig =

SslConfigurator.newInstance()

.keyStoreFile("keystore.jks")

.keyPassword("asdfgh")

.scurityProtocol("SSL");

18.07.2013

JEE to the Max

35

Page 36: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Security – WebSocket (Tyrus API)

• Initial handshake over HTTP/HTTPS (ws:// | wss://)

• Session.getPrincipal() available

BUT….

NO Client API for authentication!

18.07.2013

JEE to the Max

36

Page 37: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Security – WebSocket (Tyrus API)

• Authentication is nevertheless possible (request properties)

c = new ClientEndpointConfig.Configurator() {

public void beforeRequest(Map<String, List<String>> headers)

{

headers.put("Authorization",

Arrays.asList("Basic " + BASE64Enc.encode(encPwd))));

}

};

config = ClientEndpointConfig.Builder.

create().

configurator(c).build();

client.connectToServer(CEndpoint.class, config, “ws://…/endpoint");

18.07.2013

JEE to the Max

37

Page 38: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Loadbalancing

18.07.2013

JEE to the Max

38

Loadbalancing

Page 39: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Loadbalancing - SSE

• Works with mod_proxy / mod_jk

• Problem: notification of EventOutput on each Cluster-Node (Broadcast)

• Workaround: bypass the LB and notify the nodes

• Duplicate messages to other nodes

• Use JMS to notify all nodes in cluster

18.07.2013

JEE to the Max

39

Page 40: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

BASEL BERN LAUSANNE ZÜRICH DÜSSELDORF FRANKFURT A.M. FREIBURG I.BR. HAMBURG MÜNCHEN STUTTGART WIEN

18.07.2013

JEE to the Max

‹#›

Page 41: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Failover

18.07.2013

JEE to the Max

41

Failover

Page 42: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Failover SSE

• On connection drop:

• Error event

• Try to reconnect

• default wait before trying to reconnect is 3 seconds

18.07.2013

JEE to the Max

42

Page 43: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Failover WebSockets

• No Session replication available in current (Tyrus) version!

• Use @OnError to reconnect on failure

• Do NOT use properties on Session

• Problem: message broadcasting

• Set LB weight 100 to one Node

• Ensure that all sessions on one Node

• Duplicate messages to other nodes

18.07.2013

JEE to the Max

43

Page 44: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

SSE vs. WebSockets

• send/receive data from client

• provide true real-time

updates

• require servers that

understand the protocol

• Can identify peers (by ID)

18.07.2013

JEE to the Max

44

• push data to client

• can be configured to provide

close to real-time

• sent over traditional HTTP, so

no modification is required

• Can identify events (by ID)

WebSocket Server-Sent Events

Page 45: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Conclusion

Is it Enterprise Ready?

SSE – Yes

WebSocket - Nearly

18.07.2013

JEE to the Max

45

Page 46: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

JEE 7 project overview

18.07.2013

JEE to the Max

46

• Client API - using builder pattern

• asynchronous request processing

Future<String> future =

client.target("http://...").pathParam("", "")

.request("text/plain").async().get(..);

[4]

Page 47: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

JEE 7 project overview

18.07.2013

JEE to the Max

47

Example project with MongoDB

replication in Bitbucket (see Demos)

[4]

Page 48: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

JEE 7 project overview

18.07.2013

JEE to the Max

48

@Resource(lookup = "jms/connectionFactory")

ConnectionFactory connectionFactory;

@Resource(lookup="jms/inboundQueue")

Queue inboundQueue;

public void sendMessageNew (String payload) {

try (JMSContext context = connectionFactory.createContext();)

{

context.send(inboundQueue,payload);

}

}

[4]

Page 49: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

JEE 7 project overview

18.07.2013

JEE to the Max

49

@Resource(name = "concurrent/myExecutor")

ManagedExecutorService executor;

executor.execute(new MyRunnableTask(2));

[4]

Page 50: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

BASEL BERN LAUSANNE ZÜRICH DÜSSELDORF FRANKFURT A.M. FREIBURG I.BR. HAMBURG MÜNCHEN STUTTGART WIEN

VIELEN DANK.Andy Moncsek

[email protected]

www.trivadis.com

18.07.2013

JEE to the Max

50

Page 51: Scalableenterpriseapplicationswith jee7andbeyond

2013 © Trivadis

Appendix

1. Wallpaper: http://bensow.deviantart.com/art/Wallpaper-Under-Construction-

252593627

2. http://de.slideshare.net/MasoudKalali/server-sent-events-async-servlet-web-

sockets-and-json-born-to-work-together

3. Tyrus Project: http://java.net/projects/tyrus

4. Jersey 2: http://jersey.java.net/jersey20.html

5. JacpFX: https://code.google.com/p/jacp/

6. GlassFish 4 downloads: http://glassfish.java.net/public/downloadsindex.html

7. [3] http://blog.exceliance.fr/2012/11/07/websockets-load-balancing-with-

haproxy/

8. [4] http://de.slideshare.net/arungupta1/the-java-ee-7-platform-productivity-

html5-16124993

9. http://download.oracle.com/otndocs/jcp/websocket-1_0-pfd-spec/index.html

18.07.2013

JEE to the Max

51