Lottery WebLogic JMS, Jersey, JMX, JNDI Óbudai Egyetem, Java Enterprise Edition Műszaki Informatika szak Labor 8 Bedők Dávid 2016.01.25. v0.3
Feladat ● A Lottery alkalmazás portolása WebLogic alkalmazás szerverre. ● Remote JMS client készítése ● Local JMS client készítése ● JMX management lehetőségek Nehézségek: bár az implementált osztályok csekély mértékben módosulnak, a környezeti beállítások eltérnek, és “természetesen” teljesen már library-k (implementációk) vannak használva runtime WebLogicnál (JBoss-szal összehasonlítva). 2
Architektúra (változatlan)
3
RedHat JBoss vs. Oracle WebLogic JBoss 6.4
WebLogic 12.2.1
JEE version
JEE6
JEE6
Logging
JBoss Logging, Log4J, ..
JDK Logging, ..
REST WS
RESTEasy 2.3.10.Final
Jersey 1.18
JPA Provider
Hibernate 4.2.18.Final
EclipseLink 2.5.2
JMS Provider
HornetQ 2.3.25.Final
WebLogic JMS
JAXB
JAXB 2.2.5-redhat-9
JAXB 2.2.10 Oracle 4
JMS Provider beállítása I JMS Server and JMS Module
WebLogic Administration Console ● Services | Messaging | JMS Servers ○ New ■ name: demoJMSserver ■ persistence store: none ■ target: myserver
● Services | Messaging | JMS Modules ○ New ■ name: demoJMSmodule ■ location in domain: blank ■ target: myserver ■ Would you like to add resources to this JMS system module? yes
5
JMS Provider beállítása II JMS Submodule és JMS Destination (queue)
● Services | Messaging | JMS Modules ○ demoJMSmodule | Subdeployments | New ■ name: demoJMSsubmodule ■ target/server: demoJMSserver ■ target: myserver ■ Would you like to add resources to this JMS system module? yes
● Services | Messaging | JMS Modules ○ demoJMSmodule | Configuration | New ■ type: Queue ■ name: lotteryqueue ■ JNDI name: jms/queue/lotteryqueue ■ subdeployments: demoJMSsubmodule
6
JMS Provider beállítása III Connection Factory
● Services | Messaging | JMS Modules ○ demoJMSmodule | Configuration | New ■ type: Connection Factory ■ name: demoConnectionFactory ■ JNDI name: jms/demoConnectionFactory ■ target: myserver
7
Message Driven Bean LotteryListener.java @MessageDriven(name = "LotteryListener", activationConfig = { // @ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue = "jms/demoConnectionFactory"), @ActivationConfigProperty(propertyName = "initialContextFactory", propertyValue = "weblogic.jndi.WLInitialContextFactory"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destinationJndiName", propertyValue = "jms/queue/lotteryqueue"), @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") }) public class LotteryListener implements MessageListener, MessageDrivenBean { .. }
MessageDrivenBean implementálása nem kötelező, de lehetőséget ad az MDB életciklusába való beavatkozásra (setMessageDrivenContext(..) és ejbRemove() metódusok által).
8
Message Driven Bean JBoss vs. WebLogic Activation Config Property name
JBoss property value
WebLogic property value
Megjegyzés
connectionFactory JndiName
jms/demoConnec tionFactory
Megadása külső JMS Provider esetén érdekes (pl. ActiveMQ-t). Nem kötelező.
initialContextFacto org.jboss.naming. remote.client. ry
weblogic.jndi. Nem kötelező WLInitialContextFact ory
InitialContextFacto ry
destinationType
javax.jms.Queue
javax.jms.Queue
Másik lehetséges érték a javax.jms. Topic
destinationJndiNa me
jms/queue/lottery queue
jms/queue/lotteryq ueue
A destinationJndiName és destination közül csak egy egyik szükséges.
destination
lotteryqueue
-
WebLogic nem támogatja, JBoss-ban van “belső rövid név”, de használható a JNDI név is!
acknowledgeMode
Auto-acknowledge
Auto-acknowledge
WebLogic dokumentáció szerint nem veszi figyelembe. Sok helyen írják nagybetűvel (AUTO_ACKNOWLEDGE).
9
Remote JMS Client SimpleClient.java final Properties environment = new Properties(); environment.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi. WLInitialContextFactory"); environment.put(Context.PROVIDER_URL, "t3://localhost:7001"); environment.put(Context.SECURITY_PRINCIPAL, "weblogic"); environment.put(Context.SECURITY_CREDENTIALS, "AlmafA1#"); Context context = new InitialContext(environment); final ConnectionFactory connectionFactory = (ConnectionFactory) context. lookup("jms/demoConnectionFactory"); final Destination destination = (Destination) context.lookup ("jms/queue/lotteryqueue"); Connection connection = connectionFactory.createConnection("weblogic", "AlmafA1#"); final Session session = connection.createSession(false, Session. AUTO_ACKNOWLEDGE); final MessageProducer producer = session.createProducer(destination); connection.start(); final TextMessage textMessage = session.createTextMessage("1, 2, 3, 4, 5"); producer.send(textMessage); connection.close(); 10
Remote JMS Client JBoss vs. WebLogic JBoss PROVIDER URL
WebLogic
remote://localhost:4447
t3://localhost:7001
USERNAME
jmstestuser
weblogic
PASSWORD
User#70365
AlmafA1#
jms/queue/lotteryqueue
jms/queue/lotteryqueue
DESTINATION JNDI INITIAL CONTEXT FACTORY
org.jboss.naming.remote. weblogic.jndi. client.InitialContextFactory WLInitialContextFactory
CONNECTION FACTORY JNDI jms/RemoteConnectionFactory CLASSPATH org.jboss.as:jboss-as-jms(Initial Context Factory osztálya) client-bom:7.2.0.Final
jms/demoConnectionFactory [WL-HOME] \wlserver\server\lib\wlthint3cl ient.jar
JBoss esetén külön guest user-t hoztunk létre, míg weblogic-nál az Admin user-t használhatjuk. A Connection Factory-t JBoss esetén a standalone-full.xml-ből előre konfigurálva kaptuk, míg WebLogic esetén mi hoztuk létre Admin console-on.
11
Internal JMS Client SendQueueServlet.java InitialContext context = new InitialContext(); QueueConnectionFactory connectionFactory = (QueueConnectionFactory) context. lookup("javax.jms.QueueConnectionFactory"); QueueConnection connection = connectionFactory.createQueueConnection(); QueueSession session = connection.createQueueSession(false, Session. AUTO_ACKNOWLEDGE); Queue queue = (Queue) context.lookup(" jms/queue/lotteryqueue"); QueueSender sender = session.createSender(queue); TextMessage textMessage = session.createTextMessage(); connection.start(); textMessage.setText(" 1, 2, 3, 4, 5"); sender.send(textMessage); sender.close(); session.close(); connection.close();
Üzenetet küldeni container-en belül mindig egyszerűbb, lévén InitialContext-et “konfiguráció nélkül” egyszerűen elkérhetjük (hiszen már inicializálva van), illetve nem csak “remote” connection factory-kat érünk el, hanem a szabvány által definiált JNDI néven regisztrált specifikusabbakat is (pl. a példában ilyen a QueueConnectionFactory). 12
Java Management Extensions WebLogic
Hasonlóan a JBoss esetén már bemutatott példához, JMX segítségével szeretnénk beállítani az aktuális “sorsoló” személy nevét, a nyereményalapot és a nyeremény eloszlását meghatározó “szabály-vektort”. A lényeg természetesen a példa szempontjából a monitorozás és a beavatkozás bemutatása. 13
Managed Bean készítése kezdő lépések LotteryMonitor.java public class LotteryMonitor extends StandardMBean implements LotteryMonitorMBean, MBeanRegistration { public LotteryMonitor() { super(LotteryMonitorMBean. class, false); } Fontos! Az ős (StandardMBean ) ctor-a az MBean interface osztályát várja!
Az üzleti igények, és ezáltal a LotteryMonitorMBean interface megegyezik a JBossos példában bemutatottal.
@Override public ObjectName preRegister(MBeanServer server, ObjectName name) Exception { return name; } @Override public void postRegister(Boolean registrationDone) {} @Override public void preDeregister() throws Exception {} @Override public void postDeregister() {} }
throws
A MBeanRegistration interface használata lehetővé teszi az életciklusba való beavatkozást. 14
MBean regisztrációja JBoss esetén az MBean-t az EJB module jbossservice.xml leíró segítségével regisztráltuk. WebLogic esetén “programozottan” kell a regisztrációt elvégezni, és e programozott részt szükséges az EAR weblogic-application. xml leíró segítségével láthatóvá tenni.
15
Managed Bean regisztrációja programozott megoldás ApplicationMBeanLifeCycleListener.java package hu.qwaevisz.lottery.ejbservice.management; public class ApplicationMBeanLifeCycleListener extends ApplicationLifecycleListener { private static final String MBEAN_SERVER_JNDI = "java:comp/jmx/runtime"; private static final String OBJECT_PACKAGE = "hu.qwaevisz.lottery.ejbservice. management"; @Override public void postStart(ApplicationLifecycleEvent e) throws ApplicationException { InitialContext context = new InitialContext(); MBeanServer mbeanServer = MBeanServer. class.cast( context.lookup (MBEAN_SERVER_JNDI) ); LotteryMonitor mbean = new LotteryMonitor(); JBoss esetén az ObjectName a ObjectName oname = this.buildObjectName(); jboss-service.xml-ben volt definiálva. mbeanServer.registerMBean(mbean, oname); } private ObjectName buildObjectName() throws MalformedObjectNameException { return new ObjectName(OBJECT_PACKAGE + ":type="+LotteryMonitor. class. getSimpleName()+",name="+LotteryMonitor. class.getSimpleName()); Az ApplicationLifecycleListener osztály miatt a[WL-HOME] } \wlserver\server\lib\wls-api.jar-t el kell helyezni a ClassPath-on! @Override public void preStop(ApplicationLifecycleEvent e) throws ApplicationException {} 16 }
Listener leírója weblogic-application.xml weblogic-application.xml <weblogic-application xmlns="http://xmlns.oracle. com/weblogic/weblogic-application"> <listener> <listener-class>hu.qwaevisz.lottery.ejbservice.management. ApplicationMBeanLifeCycleListener
A weblogic-application.xml az EAR application.xml-jének conatiner specifikus párja. Ennek megfelelően az EAR META-INF könyvtárába kell elhelyezni. Ennek legegyszerűbb módja, ha a root Gradle project (EAR plugin) src/main/application könyvtárában elhelyezzük! 17
jconsole Hasonlóan a JBoss-hoz, a WebLogic esetén is szükséges a jconsole classpath-ához container specifikus JAR-ok hozzáadása. > jconsole -J-Djava.class.path=%JAVA_HOME%\lib\jconsole.jar;%JAVA_HOME% \lib\tools.jar;%MW_HOME%\wlserver\server\lib\wljmxclient.jar;%MW_HOME% \wlserver\server\lib\wlclient.jar -J-Djmx.remote.protocol.provider. pkgs=weblogic.management.remote -debug
A ClassPath beállításának egyszerű módja, ha lefuttatjuk a setDomainEnv.[sh|cmd] parancsot, majd ezt követően (azonos terminalban/command ablakban) a jconsole-t elindítjuk. > [WL-HOME]/user_projects/domains/mydomain/bin/setDomainEnv.[sh|cmd] > jconsole 18
EJB elérése MBean osztályból JBoss esetén ennek semmilyen akadálya nincsen, egyszerűen az @EJB annotáció segítségével inject-áljuk a megfelelő EJB-t, és már használhatjuk is. Az MBean azonosan EJB managed elem lesz (csak managed elemek esetén használható az “injectálás”). Ott, ahol ez nem érhető el, JNDI fából kell kikérnünk az EJB-t, hasonlóan mint ahogy egy remote EJB kliensből tennénk, azonban természetesen az Initial Context-et a helyi container már inicializálta számunkra. WebLogic esetén ez utóbbit alkalmazzuk, az @EJB annotáció ott nem működik egy MBean esetén. 19
Managed Bean regisztrációja programozott megoldás LotteryMonitor.java public class LotteryMonitor extends StandardMBean implements LotteryMonitorMBean, MBeanRegistration { private static final String LOTTERY_STATE_HOLDER_JNDI = " java:global.lottery1.0.lot-ejbservice.lotteryState"; Honnan tudjuk hogy a LotteryStateHolder Singleton private LotteryStateHolder getStateHolder() { EJB-nek mi a pontos JNDI neve? LotteryStateHolder holder = null; try { InitialContext context = new InitialContext(); holder = LotteryStateHolder. class.cast( context.lookup (LOTTERY_STATE_HOLDER_JNDI) ); } catch (NamingException e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } return holder; } @Override public String getPuller() { LotteryStateHolder holder = this.getStateHolder() return holder != null ? holder.getCurrentPuller() : ""; } 20 }
WebLogic JNDI Tree WebLogic Administration Console ● Environment | Server | Configuration ○ General tab → VIEW JNDI Tree link! Deploy-olt alkalmazások EJB-inek elérése (a JNDI fa felépítése container specifikus, bár a JEE szabvány megpróbálta már szabványosítani): ●
java:global ○ lottery-1.0 (deployolt EAR neve (a pont miatt a browser ketté szedi)) ■ lot-ejbservice (az EJB module neve az EAR-on belül) ● lotteryState (az EJB name attribútuma (def: impl. osztály neve)) ○ Overview tab Binding Name tulajdonság értéke
@Singleton(mappedName = "ejb/lotteryState", name = "lotteryState") public class LotteryStateHolderImpl implements LotteryStateHolder {}
21
Java Management Extensions JBoss vs. WebLogic JBoss MBean interface Java interface az MBean készítés szabályai szerint*.
WebLogic Java interface az MBean készítés szabályai szerint*.
EJB managed
Not EJB managed (JNDI lookup szükséges)
MBean regisztráció
EJB module META-INF-jében elhelyezett jboss-service.xml segíségével.
EAR csomag META-INF-jében elhelyezett weblogic-application.xml segítségével egy leszármaztatott ApplicationLifecycleListener regisztrációja.
jconsole futtatása
[JBOSS HOME]/bin/jconsole. [bat|sh]
[WL-HOME] /user_projects/domains/mydomain/bin/set DomainEnv.[sh|cmd] jconsole
MBean implementáció
*: https://docs.oracle.com/javase/tutorial/jmx/mbeans/standard.html
22