1 JMS as XML and Object-Based Messaging Integration Infrastructu Michael Wynholds Founder Carbon Five [email protected]
Mar 27, 2015
1
JMS as XML and Object-Based Messaging Integration Infrastructure
Michael WynholdsFounderCarbon [email protected]
2
THIS PRESENTATION
• Basics of JMS – 10%• Types of integration – 50%
– Integrate system components– Integrate dependent objects in EJBs
• Message payloads – 20%– Java objects– XML
• Q & A – 20%
3
WHAT IS JMS?
• Java Messaging Service• Java API for enterprise messaging
– Non-Java implementations available• Multiple messaging paradigms
– Point-to-point– Publish/Subscribe
4
REAL WORLD EXAMPLE #1
Major Components
vs.
Sub-Components
5
INTEGRATING SYSTEM COMPONENTS
• Major components– Crucial serial functionality– Affects user experience– Example: shopping basket
• Sub-components– Possibly crucial functionality– Slight delays acceptable– Example: Email notification engine
6
THE WRONG WAYProcesses happening serially:
– User does something in major component– Waits for sub-component to finish before
continuing on through the application
7
THE WRONG WAYTwo things wrong:
– Why should the user wait?– What if we decide later we want to perform other
non-crucial actions at this time?
8
THE RIGHT WAY:ASYNCHRONOUS
9
ASYNCHRONOUS
• Fire and continue• Can still have guaranteed delivery• Sub-components can be moved to other
machines
10
THE RIGHT WAY:LOOSE COUPLING
11
LOOSE COUPLING• Determine significant events• Major components publish• Sub-components subscribe• Addition or modification of sub-component
requires no change to major component
12
EXAMPLE:EMAIL NOTIFICATION
• Pet Store• What are significant events?
– User logs in– User status is changed– User purchases pet– Shipment is delayed (from another publisher)
13
SIGNIFICANT EVENT XML<event type="user-status-change"> <context> <timestamp>2001-03-17 12:42:06 PST</timestamp> <user> <first-name>Guy</first-name> <last-name>Incognito</last-name> <email>[email protected]</email> <status>ADMINISTRATOR</status> </user> </context>
<user> <first-name>Michael</first-name> <last-name>Wynholds</last-name> <email>[email protected]</email> <status>REGULAR</status> </user>
<new-status>PREFERRED</new-status></event>
14
SIGNIFICANT EVENT OBJECTS
15
NOTIFICATION ENGINE CODEprivate void init() throws NamingException, JMSException{ Context ctx = JNDIUtil.getContext(); String selector = new StringBuffer() .append("type = ").append(MessageTypes.CARBONFIVE_EVENT) .toString();
tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY); tcon = tconFactory.createTopicConnection(); tsession = tcon.createTopicSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); try { topic = (Topic) ctx.lookup(TOPIC_NAME); } catch (NamingException ne) { topic = tsession.createTopic(TOPIC_NAME); ctx.bind(TOPIC_NAME, topic); } tsubscriber = tsession.createSubscriber(topic, selector, false); tsubscriber.setMessageListener(this); tcon.start();}
16
public void onMessage(javax.jms.Message msg){ synchronized (this) { int type = msg.getIntProperty("type"); Event event = (Event) ((ObjectMessage) msg).getObject(); switch (msg.getIntProperty("type")) { case MessageTypes.USER_STATUS_CHANGE: Email email = generateEmail((UserStatusChangeEvent) event); email.send(); break;
default: break; } }}
NOTIFICATION ENGINE CODE
17
private Email generateEmail(UserStatusChangeEvent event){ Email email = new Email(); email.setTo(event.getUser().getEmail()); email.setFrom("[email protected]"); email.setSubject("Your status has changed"); email.setBody(getBody()); return email;}
NOTIFICATION ENGINE CODE
18
MESSAGE SENDER CODE
private void init() throws NamingException, JMSException{ Context ctx = JNDIUtil.getContext();
tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY); tcon = tconFactory.createTopicConnection(); tsession = tcon.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); try { topic = (Topic) ctx.lookup(TOPIC_NAME); } catch (NamingException ne) { topic = tsession.createTopic(TOPIC_NAME); ctx.bind(TOPIC_NAME, topic); } tpublisher = tsession.createPublisher(topic);}
19
public void send(Serializable obj, int type) throws JMSException{ if (obj == null) { throw new NullPointerException("obj is null"); } ObjectMessage msg = tsession.createObjectMessage(); msg.setObject(obj); msg.setIntProperty("type", type); tpublisher.publish(msg); msg = null; // gc}
MESSAGE SENDER CODE
20
USER STATUS CHANGE CODE
private void handleStatusChange(ServletRequest request){ HttpSession session = request.getSession(true);
User user = UserManager.getUserById(request.getParameter("user_id")); User me = session.getCurrentUser();
UserStatusChangeEvent event = new UserStatusChangeEvent(); EventContext ctx = new EventContext(); ctx.setUser(me); ctx.setTimestamp(new Date()); event.setContext(ctx); event.setUser(user); event.setNewStatus(request.getParameter("new_status")); MessageSender.send(event, MessageTypes.USER_STATUS_CHANGE_EVENT);
user.setStatus(request.getParameter("new_status"));}
21
Entity EJB persistence optimization
REAL WORLD EXAMPLE #2
22
ENTITY EJB PERSISTENCE• Entity EJB guarantees synchronization
with persistent store• Overhead in EJB container• Coarse-grained Entity Beans are better• isModified() method often used to optimize
• So what’s the problem?
23
THE PROBLEM
• Multiple beans modify same dependent object• Bean instance may be on separate machines
24
SOLUTION #1• Make dependent object an EJB• No longer coarse-grained
– EJB overhead takes toll
• Multiple machine problem not fixed
25
• Don’t use isModified()• Slooooooowwwwwww….• Every getter hits the database
– Something may have changed– But most of the time, nothing has changed
SOLUTION #2
26
• JMS-based isModified()• Dependent object publishes to topic when
a setter is called• Entity Beans subscribe to events
corresponding to their dependent objects• Efficient• Spans multiple machines
SOLUTION #3
27
DEPENDENT OBJECT CODEpublic class Thing{ private String name;
public void setName(String name) { this.name = name; fireModificationEvent(this.getClass().getName(), this.hashCode()); }}
28
EJB isModified()private void init() throws NamingException, JMSException{ Context ctx = JNDIUtil.getContext(); String selector = new StringBuffer() .append(“class = ”) .append(Thing.class.getName()) .toString();
tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY); tcon = tconFactory.createTopicConnection(); tsession = tcon.createTopicSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE); try { topic = (Topic) ctx.lookup(TOPIC_NAME); } catch (NamingException ne) { topic = tsession.createTopic(TOPIC_NAME); ctx.bind(TOPIC_NAME, topic); } tsubscriber = tsession.createSubscriber(topic, selector, false); tsubscriber.setMessageListener(this); tcon.start();}
29
EJB isModified()public void onMessage(javax.jms.Message msg){ synchronized (this) { ModEvent event = (ModEvent) ((ObjectMessage) msg).getObject(); if (Thing.class.getName().equals(event.getClassName())) { if (this.thing.hashCode == event.getHashCode()) { this.setModified(true); } } }}
30
ISSUES• Class-based, not object-based events
– May receive many messages when using common objects
• hashCode() method not always unique– Just means you do a database hit
• Must implement hashCode() in objects to work across machines
• Can use hash code in selector– Which is more efficient?– I don’t know.
31
MESSAGE PAYLOADS
• Objects– Rule of thumb: Use objects when you can
use objects.
• XML– Rule of thumb: Use XML when you need to
use XML.
32
OBJECT MESSAGES• Easy to create / use• Little processing overhead• No need for XML tools• Better within same JVM or when JVM is
guaranteed• Full functionality of Java inside message
33
XML MESSAGES• Can be much smaller size
– Better for high-traffic distributed systems
• Potential direct interaction with receiving systems
• Producer or consumer may be non-Java JMS client
• No class sync needed
34
REFERENCES
• http://www.carbonfive.com/oreilly
Contains links to this and other Carbon Five presentations.