Today I needed to parse some JUnit reports, generated from some old code, so they are missing namespaces. I created a trivial XSD file, but it could not validate the XML as it did not contain matching namespace.
Just a side note - if you need current XSD file, you can find it here.
This is able to parse JUnit-like reports from old Ant-based Jakarta EE 10 tests, so I can integrate the TCK to more modern build in GlassFish (another part of my "army of zombies" which ensures I will not do any mistakes in GlassFish refactoring; these TCK tests are waiting to be refactored too).
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Unmarshaller;
import java.io.File;
import java.io.FileInputStream;
import javax.xml.XMLConstants;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.StreamReaderDelegate;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import xxx.generated.Testsuite;
publicclassJUnitResultsParser {
public Testsuite parse(final File xml) {
try (FileInputStream inputStream = new FileInputStream(xml)) {
JAXBContext context = JAXBContext.newInstance(Testsuite.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(getClass().getResource("/junit-results.xsd"));
unmarshaller.setSchema(schema);
unmarshaller.setAdapter(new ClassAdapter());
XMLInputFactory xif = XMLInputFactory.newFactory();
XMLStreamReader xsr = new NamespaceURIFixer(xif.createXMLStreamReader(inputStream));
Testsuite testSuite = (Testsuite) unmarshaller.unmarshal(xsr);
return testSuite;
} catch (Exception e) {
thrownew IllegalArgumentException("Could not process the XML file: " + xml, e);
}
}
privatestaticclassNamespaceURIFixerextends StreamReaderDelegate {
public XsiTypeReader(XMLStreamReader reader) {
super(reader);
}
@Override
public String getNamespaceURI() {
String uri = super.getNamespaceURI();
if (uri == null) {
// same as in xsdreturn"urn:org:junit:results";
}
return uri;
}
}
}
Oh, and if you want to see how I generated remaining classes, it is this:
Ok, ok, you wanna know what I did in that XJB file ... I noticed there are Class values and I don't want to get just String. So I created a trivial XmlAdapter<String, Class<?>> using Class.forName() and Class.getName() to convert String and Class, and that's it!
Btw I found a minor bug - to my surprise I could use generics in the XML, but in generated code there's missing space after the class name. And when I added it to the XML, it remained even in the generated source code. Perhaps I should create an issue for that ...
And now comes the cake - I can run the TCK tests against GlassFish snapshot right from the Eclipse. Yeah, it is not without issues, they simply cannot run one after another as they leave some garbage behind ... but still - I can easily reproduce some issue locally, configure logging, or even attach debugger (I did not try yet, maybe it would need some settings).
Last note: it was rather for fun, because my side doesn't see test classes inside the TCK, so obviously javaClassName cannot be converted to a Class<?>, because the required class is not on my classpath. However - I did not do any XJB customizations for several years, so I had to try it :-)
I always feel like Frankenstein when I am doing such things 🤣
When you take a look here on the pull request I created, you will perhaps understand why I did it.
First I tried to read+search+fix everything one by one, then I tried to use regular expressions in Eclipse, but with some 15 seconds on every change ... I would spend year with that. So after several hours I resigned, time to invent the wheels.
#!/bin/bash # each line means a set of ids of the same anchor # the last id is usually the most descriptive and should be used # the others should be removed ids=$(grep -h -o -r './' --include=\*.adoc --exclude-dir=target -e '^\(\[\[[0-9A-Za-z_\\-]\+\]\]\)\+' | tr -d "[" | tr -s "]]" ",")
This found all those blocks like this one with labels. I was interested in multiple labels of the same place. Why would someone need three labels plus the implicit one? He didn't. But if some tool generated them, you simply added another. And at that time disks were slow, replacing a label by fulltext search ... eh, damn it, let's create another one. [[ghmrf]][[GSACG00088]][[osgi-alliance-module-management-subsystem]]
for line in ${ids} ; do
IFS=','
labels=($line);
unset IFS;
len=${#labels[@]};
IFS is a separator. Don't forget to unset it, because it affects further parsing otherwise.
() is an array.
length of the array ... don't let me explain this syntax, please ...
So, what we have now:
number of labels on the same line
if the number is 1, everything is alright
if the number is greater, we want to choose one of them (the last one was usually the most descriptive), and get rid of the rest.
but how? I can't keep everything in my head, so let's give names to all variables.
if [[ $len != 1 ]]
then
correctId=${labels[$len-1]};
maxIncorrectIdIndex=$(($len-2));
Do you see that evil thing? Bash doesn't subtract 2 from len without braces, ha! It took me a while until I found what to do with that.
for i in $(seq 0 $maxIncorrectIdIndex) ; do
redundantId=${labels[$i]};
if [[ "$redundantIds" == *",$redundantId,"* ]]; then
echo "Duplicit id must be fixed first: ${redundantId}";
This was quite funny, originally I tried to google some Set implementation for bash, but finally I came to a conclusion that all those implementations are bit overkill. I needed just a string containing all found labels and when I found a redundant label colliding with another redundant label, I forced user, myself, to resolve these conflicts first.
If I would replace them automatically with something else ... it could create invalid xrefs.
Time for changes. Truth is that these commands could be optimized, but why would I do that? I needed just to pass it once and then commit-push-drink a beer/ice-coffee ... while script went through some 500 files, replacing redundant label usages by the usage of chosen one, and then delete all those declarations.
echo "Replacing $redundantId by $correctId and removing [[$redundantId]] labels...";
find . -type f -name '*.adoc' ! -wholename '*/target/*' -exec sed -i -- "s/#${redundantId}/#${correctId}/g" {} +;
find . -type f -name '*.adoc' ! -wholename '*/target/*' -exec sed -i -- "s/\[\[${redundantId}\]\]//g" {} +;
done;
fi;
done;
And finally yet one thing ... replace link: by xref: where possible, because then Asciidoctor can validate these references. I found that some types of mistakes still can pass (remember those collisions?), but it is still an awesome tool.
echo "Replacing link references by xref where it is possible.";
find . -type f -name '*.adoc' ! -wholename '*/target/*' -exec sed -i -r -- 's/link:([a-zA-Z0-9\-]+)\.html#/xref:\1.adoc#/g' {} +;
find . -type f -name '*.adoc' ! -wholename '*/target/*' -exec sed -i -r -- 's/link:#/xref:#/g' {} +;
echo "Done.";
Then I started maven clean install, it failed reporting some remaining issues, so I went back to Eclipse and fixed them in an hour. And this is the result in PDF (Okular) and HTML (Opera).
I have tested the configuration on two operating systems - CentOS 7 and Kubuntu 15.10. These instructions are for CentOS, because there it is a bit more complicated. All application server instances run on Payara 4.1.1.154 - two on CentOS 7 and one on Solaris5.10. Note that for correct cluster replication you need to have configured the multicast routing - or to have all instances on the same network ;)
1) You need to do this as root:
# aka apache2 and modules in debian linuxes yum install httpd
2) You need time synchronization - one minute error is fatal. You can select another server for time sychronization - check also if it is accessible from the server.
yum installntp ntpdate
chkconfig ntpd on
ntpdate pool.ntp.org
3) Edit the httpd.conf file and add two lines (use correct hostname, valid from the outside world):
vim /etc/httpd/conf/httpd.conf
ServerName myhost.mydomain.org
LoadModule rewrite_module modules/mod_rewrite.so
4) Edit httpd configuration file and put the loadbalancer settings in it.
vim /etc/httpd/conf.d/00-default.conf
VirtualHost will run on port 80
you need some time to hold the session on one instance, where the user logs in - in this time the new session will be replicated to other payara instances in cluster. If the next request would be faster, the session would be invalidated. This is the reason why you need also the ROUTEID cookie - the stickysession changes it's value because a new session is created.
third internal host has status +H - that means "hot standby" - it will be routed only if other hosts would be inaccessible.
<VirtualHost *:80>
ProxyRequests Off
RewriteEngine Off Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/; Max-Age=60;" env=BALANCER_ROUTE_CHANGED
5) Allow the httpd service to access the outside world via TCP- without that you will get only HTTP 503 and some message in error_log that the action was declined.
/usr/sbin/setseboolhttpd_can_network_connect 1
6) Run the httpd service (and loadbalancing) and watch logs
Glassfish má za sebou dlouhatánskou cestu ... první, s čím jsem přišel do styku, byl SunOne7. Ten vznikl jako výsledek spolupráce s Netscape a Oracle stále ještě udržuje jakousi stařičkou dokumentaci.
Jeho výhodou byla jedna z prvních podpor EJB (což se ukázalo i nevýhodou, jelikož tato technologie, tj. EJB2 byla prakticky nepoužitelná) a administrační GUI, které naopak použitelné bylo. Z něj se daly konfigurovat a spouštět i vypínat instance aplikačního serveru, čili na tu dobu šlo o vskutku "enterprise" řešení, které v té době nemělo obdoby.
Výhod bylo víc, například integrace JMS a dalších J2EE technologií, aktuálních v roce 2003.
Největší výhodou byla ovšem výborná stabilita. Tenhle aplikáč nám snad nikdy nespadnul, pokud nebudu počítat memory leaky v našich vlastních aplikacích.
Mezi nevýhody patřilo využívání nativních knihoven a tudíž možnost spuštění pouze na OS Solaris, Windows a RedHat 7.2. Rozchodit monstrum jinde vyžadovalo náhodné vyměňování nativních knihoven, než se administrátor "trefil" do konstelace, která fungovala.
A jedna nevýhoda fatální - zapomeňte na zdrojáky nebo artefakty ve veřejných úložištích.
No, pryč od toho ... užili jsme si dost srandy :-)
Sun Java Application Server 8
V roce 2005 přišly specifikace JEE5, JDK5, EJB3, JPA a další, díky kterým se stal starý aplikáč v podstatě mrtvou technologií. Sun se do toho vrhnul po hlavě, část implementací integroval od jiných autorů, část napsal sám - práce odvedl mnoho a velmi rychle, byť s diskutabilní kvalitou.
Tou dobou se už začínala probouzet konkurence - z největších aktuálních jmenujme WebSphere, WebLogic, TomEE, WildFly/JBoss, Jetty, a další. Mírně zastarávající seznamy s malým srovnáním viz wiki nebo wiki.
Přiznávám, že s touto verzí jsem neměl moc zkušeností, jen si pamatuji, že to byl takový mezičlánek, ve kterém byla spousta nedodělků a chyb. V principu to fungovalo, ale ...
Sun Java Application Server 9 aneb Sun Glassfish Enterprise Server 2
SJAS8 byl v podstatě prototyp. SJAS9, později přejmenován na SGES2, znamenal dotažení technologií do konce. Velké problémy byly s JMS (OpenMQ), což byl server provozovaný v serveru, při chybné konfiguraci se prostě zasekl. Důvody jste museli hledat mimo Glassfish, přičemž trvalo dlouho, než jste přišli na to, v čem je přesně problém.
Komunikace mezi GF a MQ probíhala přes porty, a variant konfigurací bylo mnoho, snad ani autorům původně nedošlo, jakou variabilitu jim to dává. To je ale námět spíše na jiný blog - stručně - triviální varianta je "embedded", resp. "zapouzdřený" server, složitá a škálovatelná varianta je "remote" server ...
SJAS9 přišel v roce 2007, zkraje se ještě stávalo, že "zůstal viset" právě díky JMS, později ale byly i tyto chyby vyřešeny a poslední verze SGES2.1.1 byla velmi stabilní a bezproblémová (pokud jí nedestabilizovaly vaše chyby ve vašich aplikacích ;-) ).
Hlavní výhody proti dřívějším verzím:
podpora clusteringu - bylo možné provozovat n instancí na m strojích, mezi nimiž se replikovaly sessions uživatelů a bylo možné např. postupné nasazení nové verze, aniž by došlo k výpadku (to samozřejmě mělo svá pravidla, o tom zase jindy).
žádné nativní knihovny - kde běží JDK5/6, běží Glassfish (jen občas narazíte na problémy např. s Windows).
propracovaná dokumentace
kompletní podpora JEE5
Glassfish3
V roce 2010 Oracle koupil Sun a všechno se změnilo. Již předtím jaksi "v ilegalitě" vznikl tzv. Embedded Glassfish, na který jsem narazil prakticky náhodou - kupodivu ve veřejných úložištích, a začal ho používat k integračním testům. Ano, stačil mi JUnit, abych mohl testovat EJB3 s JMS, JPA a se vším všudy!
Embedded Glassfish je totiž přebalené vydání Glassfishe3 do jediného jar souboru. Chybí mu pár XML, která se dají snadno dotáhnout z jiných závislostí a jedete - tak málo stačilo k odstranění největší výtky vůči "enterprise aplikačním serverům"!
Glassfish3 náš tým nakonec přeskočil, ale pomohl nám díky zpětné kompatibilitě se SGES2 právě s testováním.
Embedded Glassfish byl nakonec opět pohlcen Glassfishem a stal se součástí jeho buildu a repository.
V roce 2011 Oracle oficiálně vydal Glassfish3 jako referenční implementaci JEE6. Vzápětí se ale probral JBoss a prakticky Glassfish3 převálcoval.
Byrokracie Oracle navíc silně rozladila některé vývojáře a byla poslední kapkou k jejich přestupu - kam jinam - často k JBoss.
Po vyjádření Oracle o ukončení komerční podpory Glassfishe a o vyčlenění "clusteringu" pouze do komerční verze to vypadalo, že Glassfish prostě skončí, zemře, je konec. Jenže se ukázalo, že tak snadné to mít Oracle nebude ...
Glassfish4 - smrt ... NEBUDE!
Oracle totiž narazil na pár háčků. Nápad s clusteringem vyprovokoval poměrně hlučnou odezvu vývojářů i mimo Oracle, takže od něj bylo ustoupeno. Nápad s ukončením komerční podpory sice Oracle dotáhl do konce, ale nikoho to zase tak moc netrápilo, protože i má osobní zkušenost s komeční podporou Sun/Oracle byla velmi špatná (a je doposud).
Licence Glassfishe ale umožňovala alespoň pasivní přístup ke zdrojákům, a bylo otázkou času, kdy dojde k tomu, kdy je někdo vyžene na GitHub (ano, byl jsem to já, ale ukázalo se, že nejsem první, viz níže :D).
Druhý háček spočíval v tom, že komunita JEE stále potřebuje referenční implementaci a nikdo si jí nemohl jen tak přivlastnit a zamezit přístupu k ní ostatním.
No a poslední háček - všechny implementace JEE7 používají komponenty svých konkurentů. Weld vyvíjí JBoss. EclipseLink vyvíjí Eclipse+Oracle. Catalinu vyvíjí Apache. Pokud by Oracle "zařízl" Glassfish, patrně by nevydal už víc jak jednu jedinou verzi WebLogic, vývoj by se zbrzdil.
A tak v roce 2013 Oracle vydal Glassfish4 jako referenční implementaci JEE7. Změn nebylo mnoho oproti GF3, spoustu práce odvedli externí programátoři, Oracle se zjevně snažil investovat minimum. Čím více chyb v GF, tím lépe pro WebLogic.
Přišel rok 2014 a náš zákazník nakonec souhlasil s "upgrade". Udělali jsme skok z JEE5+JDK6+GF2.1.1 rovnou na GF4+JDK8. Ukázalo se, že to není až tak snadné díky chybám, které ve zdrojácích zevlovaly už od Glassfishe3, čili často 5 i více let.
Payara
Začal jsem zkoumat licence a možnosti, jak se dostat do SVN. Po dnech a nocích, kdy se exporty po různu zasekávaly a padaly díky vadné integritě dat v SVN Oracle, se mi to nakonec podařilo. Nakonec jsem posílal patche přímo do JIRA ... a odezva ... na přijetí jsem čekal nějaké 3 měsíce.
To mě moc nebavilo a proběhla komunikace s šéfem Glassfishe Rezou Rahmannem - pravda, překvapilo mě už, že se se mnou baví, ale ještě víc mě překvapilo, že mě nasměroval na Steva Millige z C2B2 a Payaru.
Po další komunikaci byla moje oprava přijata během 3 dnů do Payary.
Po zastavení komerční podpory Glassfishe se totiž Steve rozhodl, že jí tudíž začne poskytovat sám. Udělal stejný krok jako já, převedl SVN na GitHub, domluvil se s Rezou, a postupně se k němu přidali další a další lidé z komunity, včetně mě.
Tým Payara a jeho přispěvatelé od té doby opravili spoustu chyb a jen tak mezi řečí pomalu posouvají Payaru dál ke specifikaci JEE8. Objevily se požadavky pro podporu Javy IBM, podporována je i Oracle JDK8 (původně 7), opravy se promítají zpětně do Glassfishe od Oracle a samozřejmě - existuje placená podpora, které bych vytkl jen to, že její ceny jsou typicky "enterprise", leč konkurenti nejsou levnější.
Krom toho žije dál i Embedded Payara a vznikly i další distribuce, většinou osekané o nepotřebnou funkcionalitu.
Nakonec vzniklo i toto zábavné reklamní video:
Placená podpora
Na druhou stranu, za Tomcat podporu taky neplatíte, že? Ale to, co umí Payara rozhodně neumí ;-)
Ve výsledku placená podpora slouží hlavně k čestné podpoře profesionálních týmů, které se o tyto projekty starají. Proto pokud pracujete na projektech pro velké firmy či stát, měli byste podporu platit.
Ve skutečnosti sice nezískáte větší podporu, než máte, leč přispíváte tím k tomu, aby aplikační server, který používáte, mohl být dál vyvíjen a udržován, tj. abyste po dvou letech nezjistili, že projekt prostě skončil a vy jedete na mrtvém koni. Což není tak málo, když si to tak vezmete, ne?
V tuto chvíli to vypadá tak, že C2B2 míří mezi velké firmy. Její vývojáři konzultují chyby ve Weld i EclipseLinku, komunita si vypomáhá, zatímco Oracle si stále něco plácá na svém písečku a o ostatní se moc nestará, ale možná je to jen můj pocit ...
Budoucnost
Kdyby někdo měl pocit, že na to má, tým Payary shání vývojáře. Já tam zatím nejdu, mám svůj boj jinde, který navíc slouží jako výborný obří reálný testovací příklad pro Payaru. A zatím můžu říct, že se všichni lepšíme.
Momentálně Websphere, WebLogic ani WildFly neumí všechno, co umí Payara. Možná umí něco navíc, možná něco umí lépe, ale ne dost na to, aby mělo cenu přecházet. Zvlášť když je Payara možná ještě převálcuje :-)
Řekl bych, že i Oracle na to nakonec nutně přijde a bude muset se k tomu postavit čelem. Těžko může komplikovat práci ostatním skrz licence, spíše bych hádal, že se C2B2 pokusí koupit a zklikvidovat, pokud tato konkurence začne být až moc silná.
Dokud ale bude Glassfish na GitHub, bude velmi těžké jeho "lepší klony" kontrolovat, uzmout zpět, takže tahle cesta Oracle asi nepomůže, ne na dlouho. Glassfish není jediný takový projekt, open source se dá sice všelijak poškodit, ale jen stěží kontrolovat, pokud má pod nohama tak silnou infrastrukturu, která má navíc pozitivní efekt i pro komerční obříky.
Časy se mění ... jedno riziko bych tu ale viděl - a tím je paradoxně TTIP (v odkazu TPP, což je podobná dohoda) a různé formy kontroly internetu. Představte si, že vám vláda zablokuje, omezí nebo zpoplatní přístup na GitHub ... že je to paranoidní nápad? Možná - ale třeba tlak například na omezování síly šifer už tu dávno je.
Mimochodem, na některé weby a videa se nedostanete už teď. BBC blokuje přístup na (některá?) videa mimo UK, Youtube "tají" videa před Němci, atd. - co nevidíme, o tom nevím, tohle jsou jen zkušenosti, na které jsme narazili náhodou s kamarády v zahraničí.
To je ale už úplně jiné téma ...
Pěkně to tu mají napsané,
pěkně. A vždycky to má háček. No, našel jsem trochu jinou cestičku.
Java si vždycky hledá takové properties soubory, ve kterých má napsanou
default implemetaci nějakého API.
Ale asi bych měl začít od
začátku - problém byl takový: Naučili jsme SGES2.1.1 novým kouskům tak,
že jsme v adresáři lib udělali pár změn (AS, ne domény!):
Souborům toplink-essentials-agent.jar, webservices-rt.jar,
webservices-tools.jar, endorsed/activation.jar a
endorsed/webservices-api.jar jsme přihodili příponu .Orig - to aby je
aplikáč nenačítal, ale abychom měli nějakou stopu po tom, že jsme tu
prováděli "psí kusy". Ještě malá poznámka - toplink-essentials.jar
nepřejmenováváme, jelikož ho potřebuje interní ejb timer a nám konec
konců nevadí, protože JPA providera si vybírá každá aplikace dle svého
gusta v persistence.xml.
Do adresáře lib nakopírujeme nové soubory. K dostání jsou obvykle na
stránkách autorů nebo v různých maven repositories. Co přesně musíte
stáhnout se může lišit podle toho, jak moc se vzdálíte od staré
implementace, ale každopádně bude třeba pokrýt to, co plnily
přejmenované knihovny. Náš seznam je následující - Javě je jedno, jak se
soubory jmenují, podstatné je, že mají příponu .jar, tudíž jsme
ponechali i čísla verzí:
To jsem napsal v podstatě totéž, co mají na odkazu v začátku. Jenže
při prvním nasazení aplikace zjistíte, že pokud v persistence.xml
vyplníte element <class>, aplikace vám neprojde validací!!!
Háček je totiž v tom, že AS se řídí různými properties, poházenými
po classpath v knihovnách v adresáři META-INF/services. Ty mu říkají
"default" implementace API, které on sám použije;
název souboru je v našem případě javax.persistence.spi.PersistenceProvider.properties Protože
jsme ale nechali na classpath TopLink, má AS na výběr mezi TopLinkem a
EclipseLinkem. Který zvolí, záleží na tom, který soubor najde dřív -
čili nejspíš TopLink, protože při startu pravděpodobně bude nahazovat
EjbTimer.
Slova "pravděpodobně" a "nejspíš" se mi nelíbí, ale řešení je snadné - do aplikace si ten property soubor přidejte taky :-) A potom zapomeňte na pokusy dávat knihovny na classpath-prefix, což navrhují v onom odkazu - zkoušel jsem to, nefunguje to.
A
ještě troška deziluze - zapomeňte na to, že vám SGES2 kdy bude dělat
JEE6 server. Takovou certifikací neprošel a nikdy neprojde, prostě
taková funkcionalita kontejneru v něm není. Nikdy nebude umět pracovat s
anotacemi podle JEE6, prostě protože se musí pevně držet JEE5.
JEE5
Aplikace sice bude bezpečně fungovat na JEE6 serveru, ale to pořád
neznamená, že vnitřně JEE6 server obsahuje JEE5 server. Toto nejsou
Windows!
Důvody zpětné kompatibility jsou jen anotace a API - vaše
JEE5 aplikace jimi deklaruje nějaké požadavky (na zdroje, transakce,
atd.), ale vůbec tím neříká, jak je server má splnit (pokud ovšem
nepoužívá "deprecated" atributy anotací nebo něco neloví přes
InitialContext).
Zkrátka, pokud chcete JEE6, musíte přejít na nějaký certifikovaný JEE6 aplikáč. Třeba Glassfish3, ať nechodíte daleko.
Tenhle návod vedl jen k tomu, abychom mohli použít např. Criteria API, nové JAX-WS a pár dalších novinek.
EDIT: Jeden příklad toho, co nebude fungovat - SGES používá tuto
implementaci EntityManager wrapperu - ano, tušíte správně, metodu z
JPA2 díky němu nevyvoláte, čili například nemůžete použít TypedQuery.
Typicky máte WSDL, ponastavujete si jaxws-maven-plugin, binding, a
vygenerujete si javovské interface (a taky klienta služby, ale toho si
tu všímat nebudu). A co dál? Implementace rozhraní je už na vás. Co
služba bude dělat, tím se tu taky nebudu zabývat. Co chvíli se ale
zamotám do atributů anotace @WebService, nemůžu se trefit na
@HandlerChain, nebo zapomenu říct, že chci automatickou validaci
požadavků i odpovědí. Jak na to?
Mé implementace služeb mají
nakonec ve výsledku obvykle čtyři anotace, jsou kompatibilní s JEE5 i
JEE6 a Glassfish je vypisuje v seznamu webových služeb vystavených na
instanci - k tomu navíc aplikáč (alespoň SGES 2.1.1) potřebuje
sun-ejb.xml, u Glassfish 3 si nejsem jist, jestli nějaké XML vůbec je
zapotřebí.
- name odpovídá ejb-name v sun-ejb.xml; slouží k propojení bean přes její název napříč komponentou.- mappedName je globální identifikátor bean přes
JNDI. To je trochu kámen úrazu mezi JEE5 a JEE6, jelikož v JEE6 došlo na
standradizaci JNDI názvů, ale u JEE5 to dělá každý aplikáč jinak.
SchemaValidation
@SchemaValidation
Tato anotace způsobí, že pokud klient pošle nevalidní SOAP
dotaz, vrátí mu AS jen SoapFault s "client error". Ovšem je to dvojsečné
a stejně tak pokud v implementaci služby vytvoříte odpověď, která
neprojde validací, klient dostane opět SoapFault, ale se "server error" a
HTTP kódem 500. To by se samozřejmě nikdy nemělo stát a je to
zodpovědnost autora implementace služby.
Atributem lze také říct, že chceme použít jinou než default implementaci validace.
Poznámka pod čarou - na klienta anotace nemá vůbec žádný vliv.
jaxws-maven-plugin, resp. wsimport, umí vygenerovat i
tento soubor - dělá jeden zvlášť pro službu i port, stačí dodat
příslušné elementy do xjb souboru používaného pro custom binding. Navíc
přidá i tuto anotaci k rozhraní i klientovi, jenže má to háček - cesta k
souboru se generuje relativně k souboru třídy a proto jí musíte
zopakovat (pokud tedy nejste ve stejném balíku, což by pro změnu mohlo
dopadnout nepěkně).
Druhá možnost je všechny handlery
přidávat programově, pokud ovšem považujete určitý handler za
neoddělitelnou vlastnost služby, se kterou si navíc nechcete "plevelit"
kód implementace služby, toto je vhodný způsob.
U mých
služeb takto konfiguruji handler pro zalogování SOAP požadavku i
odpovědi; téměř téhož mohu docílit i nastavením JVM option, leč bez
možnosti logování vypínat nebo směrovat za běhu aplikace. O tom zase
jindy ;-)
Na tuhle anotaci se mrkneme podrobněji, ať už nikoho nebolí hlava :-)
name
- tenhle atribut chybí, protože v JEE5 se <port-component-name>
v sun-ejb-xml váže na název implementující třídy. Pokud atribut přeci
jen přidáte a vyplníte i shodné port-component-name, Glassfish3 s tím
nemá problém a vystaví službu pod novým názvem. Problém ale přijde se
SGES2, kde sice nasazení projde, ale do logu hlásí WARNING se
stacktrace, že atribut name se vylučuje s atributem endpointInterface.
-
otázkou pro mě je, jestli je to drobná chybička SGES, nebo požadovaná
vlastnost JEE5 (?). Buď jak buď, zřejmě je lepší věci nekomplikovat a
implementaci služby pojmenovat, jak se sluší.
serviceName
- musí odpovídat tagu <service name=... ve WSDL
- pokud neodpovídá, glassfish upozorní, že ve WSDL jsou jiné služby ale takováhle ne, a deploy selže.
portName
- musí odpovídat tagu <port name=... ve WSDL
- pokud neodpovídá, glassfish několikrát do logu zařve, že "... could not get binding from WSDL! service ...", a deploy selže.
targetNamespace
- implicitně se generuje z názvu balíku a třídy (a s http:// na začátku), ale musí odpovídat WSDL.
-
pokud wsdlLocation nenastavíte, nasazení bude nejspíš úspěšné, jenže
žádný klient se se službou neodmluví - namespaces jsou směrodatné pro
(un)marshalling SOAP zpráv.
- ve výsledku je tedy nejsnazší zkopírovat namespace z interface
endpointInterface
- jak říká javadoc, celý název implementovaného rozhraní
-
finta je v tom, že samotná třída nemusí plně implementovat všechny
metody rozhraní, k čemuž by nás Java jinak nutila. Nikdy jsem to ovšem
nezkoušel ;)
- pokud chybí, Glassfish odmítne nasazení, protože nenajde mapování operací na metody.
wsdlLocation
- cesta k WSDL, přičemž za kořen se bere adresář classes (v jar).
- pokud atribut chybí nebo soubor není nalezen, aplikáč vygeneruje svoje vlastní WSDL podle anotací.
- pozor ještě na jednu věc, WSDL musí být v podadresáři wsdl, jinak aplikáč odmítne nasazení aplikace