Přeskočit na hlavní obsah
  1. Tags/

Java

2015


Jak dělám Java pohovor III: phone screen

·5 min
Jedna z věcí, ke kterým jsem došel a považuji ji za nutnost při technickém recruitingu, je phone screen. Jediný případ, kdy ho nedělám, je buď že mám s daným člověkem přímou pracovní zkušenost, anebo jsme se předtím už osobně setkali. Jak takový phone screen může vypadat?

2014


2013


Hledám do svého týmu Java vývojáře

·8 min
Rozhodl jsem se "jít tomu štěstíčku trochu naproti" a publikovat zde pracovní inzerát. Proč? Protože hledám lidi k sobě do týmu. Bude to lepší, než čekat, koho mi najde HR oddělení, nebo pošle nějaká agentura. Zkrátka, vytvářím si vlastní příležitost.

2012


Java a fault handling policies v Oracle SOA Suite

·6 min
Jednou ze součástí Oracle SOA Suite je tzv. Fault Management Framework, který se mmj. stará o zpracování výjimek v BPELu. Pokud během invoke aktivity nastane výjimka, framework ji odchytí a předá ji ke zpracování akci, která je definovaná ve fault policy.

Tyto politiky jsou zajímavou alternativou k odchytávání výjimek v samotném BPELu  pomocí fault handleru <catch>. Dá se na ně pohlížet jako na aspekt (ve smyslu AOP), který je deklarativně navěšený na procesu (nebo i celé kompozitní aplikaci).

No, pokud jsem řekl aspekt, pravděpodobně jsem vzbudil velká očekávání. Tak to bohužel není - sám jsem musel pohřbít některé své designové představy - má to spoustu omezení, resp. možnosti nejsou rozsáhlé. Takže co to vlastně umí?

V rámci politiky se dají definovat následující zotavné akce:
  • Retry. Nepovedený invoke se dá zopakovat. Dá se nastavit počet opakování, prodleva, exponenciální prodleva a následující zřetězená akce, pokud retry nezafunguje.
  • Human Intervention. Proces se zastaví a je možné ho manuálně obnovit z management konzole.
  • Terminate Process. Proces je ukončen. Totéž jako aktivita.exit.
  • Rethrow Fault. Chyba je vyhozena zpátky do BPEL procesu.
  • Replay Scope. Vyhodí reply fault, což způsobí znovu vykonání aktivit ve scope.
  • Java Code. Zavolá externí Java třídu. To je to, na co se budeme dále soustředit.

Problém

Mám pro klienty vystavenou službu SOAPFault, která má ve svém kontraktu definovaný SOAP Fault:
<xsd:element name="fault">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="resultCode"
type="xsd:string"/>
<xsd:element name="error">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="errorCode"
type="xsd:string"/>
<xsd:element name="errorDescription"
type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

Pro graficky orientované to vypadá takhle:


Tento fault je pak použit ve WSDL:
<wsdl:message name="faultMessage">
<wsdl:part name="payload" element="inp1:fault"/>
</wsdl:message>

<wsdl:portType name="SOAPFaultPort">
<wsdl:operation name="test">
<wsdl:input message="tns:requestMessage"/>
<wsdl:output message="tns:replyMessage"/>
<wsdl:fault name="testfault"
message="tns:faultMessage"/>
</wsdl:operation>
</wsdl:portType>
Služba je implementovaná pomocí BPEL procesu, který v rámci orchestrace volá další službu, nazvanou BPELFault:


Tak, to byla expozice. Teď přijde kolize. V BPELu mám definovanou invoke aktivitu, která volá externí službu BPELFault. Chtěl bych použít politiku tak, aby když externí služba vrátí chybu, aby mi politika nastavila můj definovaný SOAP fault a proces ho vrátil klientovi.

Než se pustíme do implementace politiky, musíme v BPEL procesu ještě splnit dvě podmínky. Jednak v procesu definovat proměnnou, která bude mít nastavený typ zprávy jako daný fault:
<variable name="soapFault"
messageType="ns1:faultMessage"/>
A druhak, proces musí náš fault vyhodit ven pomocí aktivity throw:
<catchAll>
<throw name="ThrowFault"
faultName="ns1:testfault"
faultVariable="soapFault"/>
</catchAll>

Jak to celé funguje?

Obrázek je za tisíc slov, takže tady je BPMN diagram. Swimliny jsou trochu nečitelný :-/ takže odshora: BPEL, External WS, Fault Management Framework a Java Class.


Java

Java třída, která bude z politiky volaná musí implementovat rohraní IFaultRecoveryJavaClass. To má dvě metody, nás bude zajímat pouze handleFault, která má jako parametr IFaultRecoveryContext. Pomocí tohoto kontextu lze přistupovat k objektům v BPEL procesu, odkud vyletěla výjimka.

Z kontextu si tak vytáhneme výše uvedenou BPEL proměnnou soapFault a pomocí XPath, nebo DOMu ji naplníme. Na závěr vrátíme z metody string RETHROW, aby politika vrátila řízení zpátky do BPEL procesu, odkud je pak už vrácena SOAP fault klientovi.

(Omlouvám se, že ten kód uvádím celý. Ale kdyby náhodou to někdo (v Česku) řešil, tak ať to má trochu jednodušší :-)
package cz.swsamuraj.soa.fault;

import com.collaxa.cube.engine.fp.BPELFaultRecoveryContextImpl;

import
oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import
oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
* This class is called by fault policy. Its purpose is to set up
* a variable which is then throwed as a SOAP fault.
*
* @author Guido
*/
public class SOAPFaultHandler implements IFaultRecoveryJavaClass {

private static final String VARIABLE = "soapFault";
private static final String PART = "payload";
private static final String RESULT_CODE_NAME = "resultCode";
private static final String RESULT_CODE_VALUE = "255";
private static final String ERROR_NAME = "error";
private static final String ERROR_CODE_NAME = "errorCode";
private static final String ERROR_CODE_VALUE =
"EXTERNAL_SERVICE_ERROR";
private static final String ERROR_DESCRIPTION_NAME =
"errorDescription";
private static final String RESULT = "RETHROW";

@Override
public void handleRetrySuccess(
IFaultRecoveryContext iFaultRecoveryContext) {
}

/**
* Method for set up a BPEL variable for SOAP fault.
*
* @param recoveryContext
* @return
*/
@Override
public String handleFault(IFaultRecoveryContext recoveryContext) {
if (recoveryContext instanceof BPELFaultRecoveryContextImpl) {
BPELFaultRecoveryContextImpl bpelContext =
(BPELFaultRecoveryContextImpl) recoveryContext;

Element root =(Element)
bpelContext.getVariableData(VARIABLE,
PART, "/");
Node soapFault = root.getFirstChild();
String namespaceURI = soapFault.getNamespaceURI();

bpelContext.addAuditTrailEntry(String.format(
"Obtained a root element: {%s}%s.", namespaceURI,
soapFault.getLocalName()));

// removes all child nodes
if (soapFault.hasChildNodes()) {
int count = soapFault.getChildNodes().getLength();

for (int i = 0; i < count; i++) {
Node child = soapFault.getFirstChild();
soapFault.removeChild(child);
}
}

Document document = soapFault.getOwnerDocument();
Node resultCode = createNode(document, namespaceURI,
RESULT_CODE_NAME, RESULT_CODE_VALUE);
soapFault.appendChild(resultCode);

Node error = createNode(document, namespaceURI,
ERROR_NAME, null);
soapFault.appendChild(error);

Node errorCode = createNode(document, namespaceURI,
ERROR_CODE_NAME,
ERROR_CODE_VALUE);
error.appendChild(errorCode);

Node errorDescription = createNode(document, namespaceURI,
ERROR_DESCRIPTION_NAME,
bpelContext.getFault()
.toString());
error.appendChild(errorDescription);

bpelContext.addAuditTrailEntry(String.format(
"SOAP fault response has been set"
+ " by fault policy '%s'.",
bpelContext.getPolicyId()));
}

return RESULT;
}

/**
* Method creates a new {@link Node} with given parameters.
*
* @param document {@link Document}
* @param qualifiedName name of the element
* @param namespaceURI namespace of the element
* @return {@link Node}
*/
private Node createNode(Document document, String namespaceURI,
String qualifiedName, String textContent) {
Node node = document.createElementNS(namespaceURI,
qualifiedName);

if (textContent != null) {
node.setTextContent(textContent);
}

return node;
}
}

Zajímavá je zde asi pouze metoda kontextu addAuditTrailEntry, která propisuje informace do auditního záznamu procesu, což je pak vidět v konzoli Enterprise Managera:


Definice politiky

Už máme ruce, teď mozek. Aby politika byla funkční, je potřeba vytvořit dva soubory. Jednak samotnou definici, soubor fault-policies.xml a potom navázání politiky na konkrétní kompozitiní aplikaci (nebo komponent), soubor fault-bindings.xml. Toto jsou defaultní názvy souborů. Pokud chceme jiné názvy, např. protože chceme politiky verzovat, je potřeba tuto odlišnost uvést v definici kompozitní aplikace.
<property name="oracle.composite.faultPolicyFile">
fault-policies-v1.0.xml</property>
<property name="oracle.composite.faultBindingFile">
fault-bindings-v1.0.xml</property>
Nebo graficky:


V definičním souboru fault-policies-v1.0.xml říkáme, že chceme odchytávat výjimku remoteFault (není to standardní chyba definovaná BPELem, ale Oracle BPEL Extension) a chceme, aby byla zpracovaná naší Java třídou:
<?xml version='1.0' encoding='UTF-8'?>
<faultPolicies xmlns="http://schemas.oracle.com/bpel/faultpolicy">
<faultPolicy version="2.0.1" id="BpelInvokeActivityFaults-v1.0">
<Conditions>
<faultName
xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
name="bpelx:remoteFault">
<condition>
<action ref="ora-java"/>
</condition>
</faultName>
</Conditions>
<Actions>
<Action id="ora-java">
<javaAction
className="cz.swsamuraj.soa.fault.SOAPFaultHandler"
defaultAction="ora-rethrow">
<returnValue value="RETRHOW" ref="ora-rethrow"/>
</javaAction>
</Action>
<Action id="ora-rethrow">
<rethrowFault/>
</Action>
</Actions>
</faultPolicy>
</faultPolicies>
Ve vazebním souboru fault-bindings-v1.0.xml jenom říkáme, že naše politika BpelInvokeActivityFaults-v1.0 je svázaná s celou kompozitní aplikací:
<?xml version='1.0' encoding='UTF-8'?>
<faultPolicyBindings
version="2.0.1"
xmlns="http://schemas.oracle.com/bpel/faultpolicy">
<composite faultPolicy="BpelInvokeActivityFaults-v1.0"/>
</faultPolicyBindings>

Deployment do runtime

Pokud máme třídu i politické :-) soubory přímo v kompozitní aplikaci, nemusíme deployment nijak řešit - prostě kompozitní aplikaci standardně nasadíme. Pokud však chceme politiky externalizovat (protože je chceme přepoužít pro více kompozitek), je vhodné umístit XML soubory do MDS (Metadata Services repository) a Java třídu nasadit do runtimu SOA Suity:
  1. Zkompilovanou třídu zabalíme do JAR souboru.
  2. JAR soubor nakopírujeme do adresáře <ORACLE_HOME>/Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1
  3. V tomto adresáři spustíme příkaz ant.
  4. Restartujeme WebLogic.

Související články


Odkazy

DOM, Java a odstranění child nodes

·2 min
Dneska to bude jen takový krátký. Řešil jsem nějaký problém, v rámci kterého se pracovalo s DOMem, do kterého jsem potřeboval přidat nějaké nody. Jak jsem průběžně zjistil, někdy mi do metody přicházel dokument, který už ty nody někdy obsahoval (a někdy ne).

Jako čistý řešení mi přišlo dané nody (včechno to byly child elementy jednoho nodu), pokud tam jsou, odstranit a pak je přidat s potřebnými hodnotami. K tomu jsem se rozhodl vzhledem k API, jež DOM v Javě nabízí - které mi tedy moc použitelné nepřijde.

Dokument, o kterém mluvím má (zjednodušeně) takovouhle strukturu:
<root>
<child1/>
<child2/>
<child3/>
</root>
Obecně jsem čekal, že <root> element bude mít nějakou metodu, která mi vrátí kolekci child nodů. Taková metoda sice existuje - getChildNodes() - ale bohužel vrací interface NodeList:
package org.w3c.dom;

public interface NodeList {
public Node item(int index);

public int getLength();
}
Nevím jak vám, ale mě kolekce s takovým rozhraním přijde dost hrozná.

A teď, proč o tom vlastně píšu. Řekl jsem si, OK, získám NodeList, projdu ho v cyklu a jednotlivé nody odstraním. Takže jsem napsal něco takového:
if (root.hasChildNodes()) {
NodeList children = root.getChildNodes();
int count = children.getLength();

for (int i = 0; i < count; i++) {
Node child = children.item(i);
root.removeChild(child);
}
}
Načež mě překvapilo, že mi to vyhazuje NullPointerException. Ono totiž, když se odstraní element z DOMu, tak se odstraní i z daného NodeListu. Divný, ale budiž. Řešením by tedy bylo
Node child = children.item(0);
ale to se mi designově nelíbilo, takže jsem skončil s tímhle kódem:
if (root.hasChildNodes()) {
int count = root.getChildNodes().getLength();

for (int i = 0; i < count; i++) {
Node child = root.getFirstChild();

root.removeChild(child);
}
}
A jak byste to řešili vy? Mě by se líbilo nějaké elegantní řešení.

Custom XSLT funkce v Oracle SOA Suite

·3 min
Už jste se s tím určitě setkali - nejednoznačnost globální definice boolean. (Globální myslím v rámci SOA napříč všemi systémy.) V každém jazyku je to definované trochu jinak. A proto pokud překládám hodnotu z jednoho systému (nebo rozhraní) na jiný, musím použít nějakou konverzi.

Obecně v tomto problému hodně pomůže kanonický datový model (Cannonical Data Model, CDM), ale pořád se nevyhneme tomu překladu (jenom jich bude méně).

Co jsem teď aktuálně řešil (a že nás to na projektu už nějakou chvilku občas drobně trápí), byl překlad boolean typu z XSD na typ v Oracle databázi. Jak asi víte, Oracle DB nemá typ boolean a nejčastěji se to řeší jako integer 0/1, nebo char Y/N apod. Když tak mě v komentářích opravte - nejsem Oraclista (= databázista).

V XSD je to sice jednoznačnější (viz specifikace boolean), ale záleží, jestli pracujeme s kanonickou (true, false), nebo lexikální (true, false, 1, 0) reprezentací.

Protože se tenhle problém čas od času opakoval, rozhodl jsem se napsat uživatelsky definovanou XSLT funkci pro překlad boolean na integer. Platforma, na které se pohybuji je Oracle SOA Suite.

Definice funkce

Protože celá(?) implementace Oracle SOA Suite je v Javě, tak nepřekvapí, že uživatelská XSLT funkce je taky v Javě:
public class CustomFunctions {

public static int booleanToInt(String bool) {
int result = 0;

if ("true".equals(bool) || "1".equals(bool)) {
result = 1;
}

return result;
}

}
Jsou tam dvě drobná omezení. (A) Metoda musí být definovaná jako statická. (B) Jak návratová hodnota, tak parametry metody musí být pouze následujících typů:
  • java.lang.String
  • int
  • float
  • double
  • boolean
  • oracle.xml.parser.v2.XMLNodeList
  • oracle.xml.parser.v2.XMLDocumentFragment

Ve výčtu je sice uvedný boolean, ale jak jsem zjistil, v rámci XSLT transformace vstupuje do metody String. Proto je v uvedené metodě v parametru String a ne boolean.

Dále potřebujeme mapovací konfigurační soubor. Musí mít následující jméno a umístění:
META-INF/ext-mapper-xpath-functions-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<soa-xpath-functions version="11.1.1"
xmlns="http://xmlns.oracle.com/soa/config/xpath"
xmlns:sws="http://www.oracle.com/XSL/Transform/java/cz.swsamuraj.xslt.CustomFunctions">
<function name="sws:booleanToInt">
<className>
cz.swsamuraj.xslt.CustomFunctions
</className>
<return type="number"/>
<params>
<param name="boolean" type="string"/>
</params>
<desc>Method transforms a boolean value to
integer. True is converted to 1 and false
to 0.
</desc>
<detail>Method transforms a boolean value to
integer. True is converted to 1 and false
to 0.
</detail>
<icon>cz/swsamuraj/xslt/Boolean.png</icon>
</function>
</soa-xpath-functions>
Tady je důležité, aby konfigurační soubor obsahoval namespace, který splňuje následující podmínky. Začíná:
http://www.oracle.com/XSL/Transform/java/

a končí plně kvalifikováným názvem Java třídy, tj.:
cz.swsamuraj.xslt.CustomFunctions

Zbytek je předpokládám zřejmý. Pak už stačí zkompilovat třídu, mapovací soubor a ev. resources (ikona) do JAR souboru.



Nastavení IDE

Aby se dala nová funkce používat v IDE (povinný JDeveloper) je potřeba ji tam zaregistrovat:
  1. Tools -> Preferences -> SOA
  2. Tlačítkem Add přidat připravený JAR soubor.
  3. Restartovat JDeveloper.
Pak již stačí otevřít nějaký XSLT soubor a naši novou funkci najdeme v Component Palette pod položkou User Defined:



Deployment do runtime

Nyní již můžeme novou funkci v IDE vyzkoušet (a otestovat), ale aby fungovala také ve službách je potřeba výše vytvořený JAR soubor dostat také na server (SOA Suita běží na WebLogicu):
  1. JAR soubor nakopírujeme do adresáře <ORACLE_HOME>/Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1
  2. V tomto adresáři spustíme příkaz ant.
  3. Restartujeme WebLogic.

Odkazy

Certifikace Java EE 6 Web Services Developer

Tak nějak jsem si poslední dobou zvykl, dělat do roka dvě certifikace (asi mi chybí školní dril :-) Takže co to bylo tentokrát? Honosný název, který se nyní skví v mém CV zní: Oracle Certified Expert, Java Platform, Enterprise Edition 6 Web Services Developer, zkráceně (ve stylu někdejších Sunovských certifikací) OCWSD.

Certifikace občas budí (zbytečné) vášně, takže základní otázka asi je: je to vůbec k něčemu? Pro mne je tím největším benefitem, že jsem se něco nového (do hloubky) naučil. A musím říct, že OSWSD je tomto směru opravdu hodnotná. Byť web servisy mastím cca poslední tři roky, ať už v Javě (JAX-WS, Spring WS nebo Axis), nebo v rámci SOA (WebSphere Message Broker, Oracle SOA Suite), tak během přípravy na certifikaci jsem dozvěděl spoustu nových věcí (třeba SOAP Message Handlers) a "dopochopil" lecos již známého.

Témata, která zkouška obsahovala jsou následující:
  • Create an SOAP web service in a servlet container
  • Create a RESTful web service in a servlet container
  • Create a SOAP based web service implemented by an EJB component
  • Create a RESTful web service implemented by an EJB component
  • Configure JavaEE security for a SOAP web service
  • Create a web service client for a SOAP based web service
  • Create a web service client for a RESTful web service
  • Create a SOAP based web service using Java SE platform
  • Create handlers for SOAP web services
  • Create low-level SOAP web services
  • Use MTOM and MIME in a SOAP web service
  • Use WS-Addressing with a SOAP web service
  • Configure Message Level security for a SOAP web service
  • Apply best practices to design and implement web services

Protože na zkoušku není žádný oficiální certifikační guide, prošel jsem trošku širší okruh materiálů. V praxi jsem zatím neměl nikdy možnost dostat se k RESTovým technologiím, takže jsem s předstihem začal s knížkou Billa Burkeho RESTful Java with JAX-RS, kterou vřele doporučuji - pokud chcete začít s RESTem v Javě (tj. libovolnou implementací JAX-RS), je to ta správná volba. Autor sice popisuje (a je tvůrcem) RESTEasy, ale je objektivní i vůči dalším implementacím.

Další knihou jsem si chtěl oživit druhou Javovskou web servisovou větev - JAX-WS. Tady je knižní situace docela slabá. V podstatě jediná aktuální kniha, která je věnována JAX-WS je Java 7 JAX-WS Web Services. Vzhledem k názvu a rozsahu (64 str.) jsem nečekal nic světoborného, ale zklamání bylo obrovské. Pokud nejste úplně nejzelenější začátečník a nevyhovují vám knížky, tvořené ze 2/3 screenshoty (NetBeansů), není to kniha pro vás. Škoda peněz, škoda času.

Jakou určitý druh přípravy můžu zmínit (celkem nudný) letošní Oracle Java Developer Day, kde jsem se šel podívat na jednu přednášku o JAX-WS a na dvě o JAX-RS. Samozřejmě, že to byly naprosté základy, ale člověk si aspoň udržuje povědomí o tématu.

Pak už začalo jít do tuhého, protože jsem potřeboval něco, co by mě připravilo na certifikaci. Nechal jsem tedy firmu zakoupit zkušební testy. Tentokrát jsem zvolil ještě nevyzkoušené řešení - kit od EPractize Labs. Jejich OCEJWSD Training Lab není úplně špatný. Sice je uživatelsky dost nepohodlný a rozložení témat mi přijde dost nevyvážené, ale myslím, že ho můžu označit jako přínosný. V dnešní době bych spíš volil kit od uCertify, s jejichž přípravnými testy mám dobrou zkušenost, který ale v té době ještě nebyl k dispozici.

Posledním materiálem, který jsem na přípravu použil je OCWSD Study Guide od Mikalaie Zaikina, který pokrývá témata zkoušky velmi pěkně. Linkovaná webová verze je zdarma, za $15 je možné si přikoupit sadu 160 otázek s odpověďmi, plus jednotlivé guidy v PDF podobě. Těch patnáct dolarů jsem investoval a můžu říct, že to stálo za to (aneb jak jsme se učili v angličtině it bang for the buck).

Pokud mám certifikaci OCWSD nějak celkově zhodnotit, musím říct, že je to určitě jedna z těch nejpřínosnějších, co dnes Oracle v oblasti Javy nabízí. Všechna témata byla víceméně ryze praktická, žádná nudná (korporátní) teorie, či dokonce ideologie. Zároveň je to taky jedna z těch, kde je těch Oraclovských technologií jen určité minimum - hodně se tam probírají věci z W3C, jako je SOAP, WSDL, XSD, WS-Addressing, nebo věci, které jsou dílem různých jiných organizací, jsou je WS-I (WS-Interoperability (Basic Profile)), nebo WS-Security.

WebSphere MQ, interakce s Javou

·3 min

Pokud se chceme k WebShere MQ (WMQ) připojit z Javy, máme k dispozici dvě možnosti - buď použít WMQ třídy pro Javu, nebo je možné komunikovat pomocí Java Message Service (JMS). Obě možnosti mají svoje pro a proti, takže krátké shrnutí v pár bodech:

  • WMQ třídy pro Javu:
    • zapouzdřují Message Queue Interface (MQI),
    • poskytují plnou sadu funkčností WMQ,
    • je to proprietární řešení, ale jednodušší k používání, než JMS.
  • (WMQ třídy pro) JMS:
    • Java “industry standard” pro messaging,
    • je součástí Java EE specifikace (a tedy součástí většiny (Java) aplikačních serverů),
    • umožňuje spravovat administrované objekty (connection factory, fronty ad.) v centrální repository.
Společná konfigurace
Ať už použijeme jeden, nebo druhý způsob, v obou případech je potřeba mít vytvořené některé objekty. Všechny použité typy objektů jsem popisoval již v minulém zápisu. Jedinou informací navíc je, že vytvořený kanál musí být typu server-connection.


WMQ třídy pro Javu
Třídy pro Javu jsou poměrně přímočaré - stačí, pokud člověk rozumí hierarchii a funkci základních objektů ve WMQ:

  1. Vytvoří se instance Queue Manageru.
  2. Z něj se získá instace Queue, s parametrem daného typu otevření (procházení, vstup, výstup atd.).
  3. Vytvoří se Message a nastaví se jí nějaká data.
  4. Zpráva se vloží do (nebo načte z) fronty.
  5. Zavřou se zdroje.
package com.adastracorp.jprase.wmq.java;

import com.ibm.mq.MQMessage;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.CMQC;


public class JavaProvider {

private static final String QM_NAME = “QM_JAVA”;
private static final String HOSTNAME =
“192.168.6.128”;
private static final String CHANNEL =
“JAVA.CHANNEL”;
private static final int PORT = 5557;
private static final String QUEUE = “JPRASE”;

private static void init() {
MQEnvironment.hostname = HOSTNAME;
MQEnvironment.channel = CHANNEL;
MQEnvironment.port = PORT;
}

public static void main(String[] args)
throws Exception {
init();

MQQueueManager queueManager =
new MQQueueManager(QM_NAME);
MQQueue queue = queueManager
.accessQueue(QUEUE,
CMQC.MQOO_OUTPUT |
CMQC.MQOO_INQUIRE);

MQMessage message = new MQMessage();
message.writeUTF(“Hello, WMQ!");

queue.put(message);

queue.close();
queueManager.disconnect();
}
}

WMQ třídy pro JMS
U JMS je trochu více konfigurace - je potřeba vytvořit Initial Context a do něj vložit Connection Factory a Destination. Destination je mapovaná na (existující) frontu a queue managera. WMQ v současné verzi (7.0.1.2) poskytuje pro JNDI dvě implementace (ale je možné použít i jiné, např. JNDI na WebSphere AS):

  • LDAP server (com.sun.jndi.ldap.com.sun.jndi.fscontext.RefFSContextFactory),
  • File system (com.sun.jndi.fscontext.RefFSContextFactory).


Výsledná konfigurace vypadá takto:


Kód samotný je pak klasické JMS:
  1. Vytvoření InitialContext.
  2. Vyhledání ConnectionFactory.
  3. Vytvoření Connection.
  4. Vytvoření Session.
  5. Vytvoření Destination.
  6. Vytvoření MessageProducer/MessageConsumer.
  7. Vytvoření Message (pro producenta).
  8. Odeslání (příjem) Message.
  9. Zavření zdrojů.
package com.adastracorp.jprase.wmq.jms;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;

public class JmsProvider {

private static final String CONTEXT_FACTORY =
“com.sun.jndi.fscontext.RefFSContextFactory”;
private static final String PROVIDER_URL =
“file:///jms”;

private static Context getContext()
throws NamingException {
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,
CONTEXT_FACTORY);
env.put(Context.PROVIDER_URL, PROVIDER_URL);

return new InitialContext(env);
}

public static void main(String[] args)
throws Exception {
Context context = getContext();

ConnectionFactory factory = (ConnectionFactory)
context.lookup(“jmsConnFact”);
Connection connection = factory
.createConnection();
Session session = connection
.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Destination destination = session
.createQueue(“JPRASE”);
MessageProducer producer = session
.createProducer(destination);
producer.setDeliveryMode(
DeliveryMode.NON_PERSISTENT);
TextMessage message = session
.createTextMessage(
“Hello, JMS!");
producer.send(message);

producer.close();
session.close();
connection.close();
}
}