Skip navigation

WindRide is a standalone application which helps with migration of configuration of application servers to JBoss AS 7, JBoss EAP 6 or WildFly.

See the project's wiki and other posts in this blog: Ondrej Zizka's Blog

 

Currently, the only supported source servers are JBoss AS 5 and JBoss EAP 5.

 

Anyone interested in supporting GlassFish as a source server, too?

If someone expresses some interest, it might cause this feature to land in the WindRide project sooner.

 

Comment / like / share.

What's new

Next feature to implement in WindRide was integration with WindUp 0.7.x.

From now on, WindRide unleashes WindUp to scan all the deployments in the source server (EAP 5), and includes the WindUp report in WindRide report.

For more info about WindRide, see my previous blog post EAP config migration tool - WindRide 1.0.0 released.

 

Download

As usually, you can download WindRide from the JBoss Maven Repository:

https://repository.jboss.org/nexus/content/repositories/releases/org/jboss/migr/as/WindRide/1.1.0/WindRide-1.1.0.jar

 

What's next?

In the short term future, WindRide development will focus on improving basic configuration, by covering more configuration details of things like datasources, transactions, security, etc. [MIGR-156]

Mid term, it should support IBM WebLogic configuration migration. [MIGR-171]

 

Enjoy!

To use WindUp to create a report from an archive:

 

1. Include the dependencies.

 

        <!-- WindUp -->
        <dependency>
            <groupId>org.jboss.windup</groupId>
            <artifactId>windup-engine</artifactId>
            <version>0.7.0</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.windup</groupId>
            <artifactId>windup-rules</artifactId>
            <version>0.7.0</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.windup</groupId>
            <artifactId>windup-reporting</artifactId>
            <version>0.7.0</version>
            <scope>compile</scope>
        </dependency>


 

  • `windup-engine` extracts the data from the archives.
  • `windup-reporting` creates the HTML reports.
  • `windup-rules` is a package which contains all the static files with rules, essentially giving you "full profile" of WindUp.

 

2. The code.

 

// WindUp
final WindupEnvironment windupEnv = new WindupEnvironment();
//final WindupEngine windupEng = new WindupEngine( windupEnv );
final ReportEngine windupReport = new ReportEngine( windupEnv );

windupReport.process( depl, reportDir );

This is for czech students, hence in czech only.

 

Rád bych zde shrnul pár svých poznatků z vedení diplomek.

Než to zpracuju do podoby článku, dávám k dispozici pár instruktážních mailů.

Jsou psané na konkrétní situace, v článku (snad) později zobecním.

 

Výběr tématu

Diplomová práce je jednou z vašich posledních možností, kdy se budete moci věnovat přesně tomu, co si sami vyberete.

Dále je to vaše vizitka do budoucna - první zaměstnavatel se bude na 100 % zajímat, co jste jako diplomku dělali.

Navíc je možné, že se z diplomky stane úspěšný opensourcový projekt, případně na ní založíte start-up.

 

Proto:

  • Věnujte výběru tématu dost času.
  • Téma prodiskutujte s navrhovatelem a případnými vedoucími.
  • Zjistěte si, zda by vám v případě těžkého problému pomohl nějaký expert.
  • Vyzkoušejte si pár praktických tutoriálů pro technologie, které použijete.
  • Ideální je, když už potřebné technologie znáte, ale i tak byste si měli rozšířit obzory.
  • Promyslete, zda nehrozí zákys na něčem, co technologie neumí.
  • Vyvarujte se závislosti na projektech téměř mrtvých (Caché), nevyzpytatelných (PHP), špatně zdokumentovaných nebo s nevelkou či neaktivní komunitou.

 

Zadání

Zadání obsahuje úkoly jak pro praktickou, tak textovou část práce. Mělo by z něj být jasné, co vlastně máte dělat.

Za účelem volnosti ve zpracování se někdy zadává vágně, ale je lepší, když se v závěru dá jasně posoudit, zda jste uspěli či ne.

Mělo by tedy obsahovat konkrétní cíle.

Nemusí však stanovovat, jak se těmto cílům dostanete. Proto se v zadání nelimitujte na podružné technologie a postupy (kromě těch, kterých se práce týká); spíše si určete mantinely.

 

Obvykle zadání vypadá nějak takto:

  • Seznamte se s technologií MarsShelter a systémy, kterými vytváří životní podmínky pro lidskou posádku.
  • Dále se seznamte s metodami používanými pro těžbu v antarktických oblastech.
  • Navrhněte způsob využití těchto metod k zapuštění MarsShelter pod povrch Marsu.
  • Zbudujte pokusnou podzemní základnu v Antarktidě či Grónsku obsahující aspoň dva propojené moduly MarsShelter.
    • Moduly musí být nezávisle vytápěné
    • Mezi moduly musí být schopen pohodlně projít člověk
    • Každý modul modul musí mít nezávislý vchod z povrchu.
  • Vyhodnoťte, zda systémy pro podporu života mohou v takových podmínkách fungovat.

 

Metodika práce

Při práci na prvním větším projektu se snadno stane, že se dostanete do tzv. paralýzy vyvolaná analýzou. To je stav, kdy máte natolik složité vstupní podmínky a natolik mnoho či naopak málo možností řešení, že se točíte na místě a výsledek je bobtnající chaos. Správná metodika práce je prevencí proti uvíznutí v takovém stavu. Metodika sestává z obecných pravidel.

  • Jako úplně první věc si založte textový soubor, do kterého si budete zapisovat veškeré poznámky o průběhu práce. Ten bude základem pro textovou část.
    • Soubor hned na začátku strukturujte pomocí nadpisů. Ty budou představovat fáze práce.
    • Během doby se struktura tohoto dokumentu párkrát změní - text budete přesouvat, dělit, slučovat. Více viz "Textová část".
    • Behem práce do tohoto souboru zapisujte poznámky o tom, na jaké výzvy jste narazili, jaké byly možnosti a proč jste se pro rozhodli pro ten který postup.
  • Založte online repozitář (např. na Github.com). Pokud neumíte, naučte se Git, SVN nebo Mercurial - po dohodě s vedoucím.
  • Věnujte podstatnou část času rešerši dosavadních výzkumů, stávajících řešení, jejich výhod a nevýhod.
  • Používejte cokoliv k systematizovanému sledování postupu. Může to být textový soubor a papír, ale samozřejmě je mnohem lepší online systém, abyste mohli plány a výsledky konzultovat s vedoucím, případně konzultanty. Sloužit může jednoduchý, např. issue tracker na Github.com, ale ideální je nějaký sofistikovaný, který vám umožní i sledování a plánování projektu, např. Jira.
  • Práci se věnujte pravidelně. Vyhraďte si pravidelné delší časové úseky, například každé úterý a středu od rána do čtyř, a každou neděli. Udělat diplomku na B za měsíc samozřejmě jde, ale pak budete optimalizovat na známku, a kromě odškrtnutí podmínky pro získání titulu vám takové odfláknutí nic nepřinese.
  • Pravidelně informujte vedoucího o postupu. Viz "Komunikace".
  • Postup neměřte na řádky kódu, ale na hotové úkoly. Analýza, návrh (třeba kreslení na papír) a plánování práce jsou také úkoly a můžou zabrat celé dny.

 

 

Komunikace - s vedoucím, s komunitou

 

  • Pravidelně informujte vedoucího o postupu. Pokud by delší dobu neodpovídal a o vaše výsledky nejevil zájem, zvažte změnu vedoucího. Někteří vedoucí vás budou aktivně kontaktovat s žádostí o popis stavu, jiní nechají aktivitu na vás. Každopádně byste měli mít detailnější odezvu minimálně jednou za měsíc.
  • Pravidelně commitujte do repozitáře. Commitů dělejte tak akorát - necommitujte každé písmenko, ale také ne velké nečitelné celky s mnoha nesouvisejícími změnami. Ideální (podle mě) je tak 1 až 8 commitů na jeden úkol v issue trackeru.
  • Buďte viditelní v komunitě. Založte si blog a popisujte svůj postup. Dejte vědět o svém projektu v relevantních komunitách - fóra, mailinglisty.
  • Dokumentujte veškeré funkce vaší applikace či knihovny. Pamatujte, že nezdokumentovaná funkce nikomu k ničemu nebude.
  • Pokud se na něčem zaseknete, prvně hledejte; potom se ptejte na mailinglistech, fórech a webech jako je stackoverflow.com. Pokud nezískáte odpověď, potom teprve kontaktujte experty. Pokud byste je spamovali s prkotinami, v lepším případě vám odpoví "google it", v horším ztratí chuť vám pomáhat. Na druhou stranu, pokud jste poctivě hledali a zkoumali, nebojte se jim napsat. Většina budou ráda za zájem.

 

Vedení komunitního projektu

TBD

 

Textová část

Dělí se, jak znáte ze slohu ze základky, na úvod, stať a závěr.

Úvod

V úvodu rozebíráte, o čem vlastně práce je. Tj. krátké (2-3 odstavce) pojednání o tématice.

Dále konkrétní věc, kterou chcete řešit, a proč - tj. proč je současný stav nevyhovující či co jde zlepšit.

Existující řešení - jak se problém řeší (či obchází)

Stať

Hrubý návrh vašeho řešení

Představení možných technologií

Stanovení kritérií pro výběr technologií, které použijete. Měly by korelovat se zadáním a s tím, co chcete zlepšit (rychlost, snadnost, škálovatelnost, rozšiřitelnost, ...)

Vyhodnocení kritérií a výběr technologií

Opět návrh, tentokrát detailnější, se zohledněním vybraných technologií.

Problémy při realizaci a jejich řešení

Závěr

Vyhodnocení výsledků - srovnání s dosavadními kritérii podle nějakých kritérií.

Pokud se projekt uchytil v komunitě, uveďte - vypadá to dobře.

Možnosti dalšího vývoje - co byste hrozně rádi dodělali, ale nebyl čas; nicméně projekt je na to připraven (pluginovatelný nebo API, dobrá struktura).

Typografie

  • Vyjděte z šablony vaší fakulty
  • Rozmyslete si úrovně nadpisu, odpovídají členění
  • Neodsazujte mezerami a entry
  • Pozor na mezery za interpunkcí
  • Obrázky mají mít popis ve vlastnostech
  • Používejte odrážky
  • Používejte odlišné řezy konzistentně, neplýtvejte jimi

 

Prezentace

  • Prezentaci si minimálně třikrát natrénujte. Celou řeč si napište. Při zkoušce sledujte čas a udělejte si checkpointy.
  • Nečtěte slajdy. Odrážky jsou jen odpíchnutím pro vás. Nemusíte jít bod po bodu - je to jen osnova vašeho vyprávění.
  • Slajdy pojměte jako tabuli - uberte odrážky, přidejte schémata, vizualizace a ukázky kódu. Ukázka třeba zde.
  • Na prezentaci přineste slajdy minimálně na dvou médiích, mějte je i někde online na URL, kterou si pamatujete.
  • Nespoléhejte na konkrétní software, mějte prezentaci i jako PDF, kdyby něco.
  • Mluvte hlasitě, energicky, ale ne zas pateticky. Dobře vyslovujte.
  • Nedívejte se do země. Nemusíte nutně udržovat oční kontakt, ale v pauzách se na komisi podívejte.
  • Zjistěte si zaměření členů komise.
  • Nezabíhejte do technických detailů a zkratek; zaměřte se na přínos vaší práce.
  • Pokud je práce někým použitá v praxi (firma, komunita), dejte o tom vědět.

 

 

Další zdroje

 

 

Technické zdroje - bude zpracováno do dalšího postu:

 

>> Takže, vědecká práce má nějaké metodologie a postupy. Není třeba to

>> nějak extra hrotit, ale třeba výběr SVG vs. Canvas nabízí možnost

>> předvést, jak postupovat a zjednodušit si výběr.

>>

>> 1) Založ si nějaký textový soubor, třeba ve Wordu (nebo, jestli jsi

>> linuxák, tak LibreOffice, nebo Latex, ... ale klidně i plaintext, a

>> naformátuješ potom).

>>

>> 2) Do něj si napiš osnovu. Osnova se dělá tak, že si v onom Wordu

>> vytvoříš obsah automaticky generovaný z nadpisů (kdybys nevěděl jak,

>> zeptej se, nebo to určitě najdeš na netu), a pak začneš psát nadpisy

>> (za použití stylů "Nadpis 1", "Nadpis 2", ... a rovnou do odstavců

>> pod nimi i některé poznámky. Nějak takto:

>>

>> * Úvod

>> * cíle - co chceme dosáhnout

>> * motivace - proč to chceme dosáhnout

>>

>> * Analýza

>> * Jaký je současný stav - tj. jaká existují řešení - knihovny

>> řešící daný problém. Tuto rešerši jsem dělal já sám před lety, od té

>> doby asi bude hodně nového, takže se můžeš inspirovat, ale asi najdeš

>> kupu nových:

>> http://ondra.zizka.cz/stranky/programovani/web_javascript_ajax_canvas/javascript-isometric-libraries.texy

>>

>> * Jaké jsou technologie, které můžem použít. Sem právě patří SVG,

>> Canvas, pak možná můžeš zmínit Java applety, Flash, a vykreslování

>> pomocí <div> a <img> s průhlednými .gif nebo .png. Nebo pokud tě

>> ještě něco napadne.

>>

>> * Postup

>> Zde budou jednotlivé fáze vývoje:

>> Výběr technologií - kritéria, testy, výsledný výběr

>> Popis modelového (testovacího) problému (tj. např. "zkusíme

>> naprogramovat něco, co vykreslí mapu podobně jako Transport Tycoon,

>> nebo X-COM apocalypse, nebo Civilization 4, nebo Travian, atd...)

>> Dále návrh, jak se problém bude řešit, tj. např. pokud zvolíš

>> Canvas, tak bude potřeba kreslit odzhora dolu kvůli překryvům; pokud

>> budeš řešit kopce jako jsou v Transport Tycoon, pak je třeba vymyslet

>> algoritmus na výpočet, kde má daná dlaždice být vykreslena vzhledem k

>> výšce, atd.

>> Mezitím budeš kódit, takže ti budou přicházet další myšlenky

>> a problémy a jejich řešení, to vše si tam poznamenáš, později to

>> třeba stručně rozvedeš.

>>

>> * Závěr.

>> Zde je potom:

>> * ukázka, jak to ve výsledku funguje,

>> * zhodnocení, jak jsme splnili cíle práce,

>> * limity výskedku, tedy - co tvoje implementace neumožňuje, a

>> proč, a jestli se to dá dodělat, a to už přecházíme k ->

>> * možnosti dalšího vývoje - tj. co by se s tím dalo do

>> budoucna dělat (aneb "co bych býval udělal sám kdybych měl víc času"

>>

>> (Poznámka: Vědecké práce se píšou v množném čísle, i když ji píšeš

>> celou sám.)

>>

>> A teď konečně tomu SVG vs. Canvas:

>>

>> Obě technologie jsou dobré a obě můžou vyhovět. Takže jak už jsem

>> naznačil výše: stanov si kritéria, podle kterých vybereš. Navrhoval

>> bych:

>>

>> 1) Jednoduchost implementace. Prostě s čím se ti to líp naprogramuje.

>> SVG hodně usnadní věci tím, že má eventy jako HTML, tj. když máš

>> čtverec a v něm další, a jsou vnořené i jejich elementy, a klikneš na

>> ten vnitřní element, potom událost onClick probublá i k tomu

>> vnějšímu. Také když posuneš ten vnější, posune se i vnitřní. Atd.

>> Canvas zase asi umožnuje větší skopičiny - různé naklápění, barevné

>> filtry, 3D vykreslování, video, průhlednost, atd. atd.

>>

>> 2) Technické limity. Například je dost důležité, abys mohl po

>> vykreslení "mapy" také zjistit, kam v ní uživatel kliknul. Kdysi to

>> Canvas neumožňoval, teď snad už bude. SVG to umožňuje, posílá

>> normální JavaScriptový eventy, stejně jako v HTML - onclick objekt,

>> který má vlastnosti jako srcElement atd.

>>

>> 3) Výkon. Pokud budeš vykreslovat celou obrazovku prohlížeče na

>> monitoru 1920x1200, tak tam budou tisíce položek. Je třeba zkusit,

>> jestli to dokáže prohlížeč nějak rozumně rychle vykreslovat, a to i s

>> animacemi.

>>

>> 4) Podpora v prohlížečích. Kdysi SVG podporoval jen Firefox. Teď už

>> to snad budou všechny hlavní prohlížeče. Canvas je myslím jako

>> součást HTML 5 podporovaný ve všech nových.

>>

>> To by asi mohlo stačit.

>> Ta kritéria zhodnotíš nějakým jednoduchým testem - jednoduchou

>> stránkou, kde zkusíš danou věc. Co nejjednodušeji. Nejdelší bude asi

>> ta 3), kde bude nutné vykreslit těch X * Y buněk, a pak je nějak

>> posunovat - ale i to by mělo být tak na 2 dny (vypadals jako

>> ostřílený webař, tak možná i za den

>>

>> No a výsledky si oznámkuješ a na základě toho se rozhodneš. Kdyby to

>> vyšlo nastejno, tak si prostě hodíš mincí Ale ta 1) by to měla v

>> tom případě rozhodnout.

Symptoms

Recently, my Java EE application stopped working on OpenShift, saying things like

2013/08/31 21:03:10,887 INFO [org.jboss.as.controller] (Controller Boot Thread) JBAS014774: Service status report JBAS014775: New missing/unsatisfied dependencies: service jboss.jdbc-driver.mysql (missing) dependents: [service jboss.data-source.java:jboss/datasources/MysqlDS]

At boot, this error was much more complicated as it listed all the services not started during the app boot, i.e. all DAO and service EJBs etc.

Also, I thought it was caused by running out of space on the server and damaging something that way.

 

It turned to be out that the JDBC driver module has to be in git repo under .openshift/config/modules/. It wasn't there before and the web worked, so I wonder if something changed in OpenShift. I thought this is done automatically when you add the cartridge.

 

I didn't find this specific case described somewhere clearly, so I'm puttng it here, hth.

 

Solution

So I had to add .openshift/config/modules/com/mysql/jdbc/main/mysql-connector-java-5.1.26-bin.jar

 

 

And .openshift/config/modules/com/mysql/jdbc/main/module.xml

 

<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.1" name="com.mysql.jdbc"> <resources> <resource-root path="mysql-connector-java-5.1.26-bin.jar"/> </resources> <dependencies> <module name="javax.api" /> <module name="javax.transaction.api" /> </dependencies> </module>

 

Redeploy

And, on an unrelated note, for redeploying the war, the deployment marker files may be used on OpenShift.

I'm pleased to announce that version 1.0.0 of the WindRide project, an EAP config migration tool, was released.

 

About

WindRide is a complement to WindUp. While Windup helps with application migration, WindRide migrates EAP configuration (from 5 to 6).

 

How to try it

There's a demo video which shows how to use WindRide. In short, it's these steps:

 

  1. Have EAP 5 directory with your config
  2. Download, unzip and run EAP 6
  3. Download and run WindRide, giving it the paths to both EAP 5 and EAP 6
    • java -jar WindRide-1.0.0.jar src.dir=jboss-eap-5.2/jboss-as dest.dir=jboss-eap-6.1 app.path=MyCoolApp.war
  4. Done!

 

What's new?

 

* Version 1.0.0 has externalized migration rules. You can customize existing migration steps, or write your own, e.g. for WebLogic.

* The project was renamed to WindRide from previous codename SwanLoom.

* The maven artifact used for distribution is now named org.jboss.migr.as.WindRide.

 

Download

After the artifact rename, the binaries will be available under:

https://repository.jboss.org/nexus/content/repositories/releases/org/jboss/migr/as/WindRide

 

This release's distribution jar is available at:

https://repository.jboss.org/nexus/content/repositories/releases/org/jboss/migr/as/WindRide/1.0.0/WindRide-1.0.0.jar

 

Documentation, issues, source code

Documentation: Github Wiki - https://github.com/OndraZizka/jboss-migration/wiki

Source code:     Github - https://github.com/OndraZizka/jboss-migration

Issue tracking: Jira - https://issues.jboss.org/browse/MIGR

Download from the JBoss public Maven repo.

 

The 0.11.x is a preparation for 1.0.0, which will have the externalized rules.

 

In this release, most of the externalized definition constructs work as per documentation - queries, actions, expresison language, forEach loops.

What still is not tested are the Groovy expressions in filters.

Hopefuly, that will be fixed during next week and 1.0.0 can go out!

I assume everyone knows what Minecraft is, unless you just came back from 3 years journey from Mars.

Personally I don't play it, but noticed how vast the worlds are, how many events occur, and how terribly slow the current server implementation is.

 

So I was thinking, it would be a nice showcase for our technologies - especially fast clustered messaging (HornetQ) and cache (Infinispan).

 

Perhaps a keynote demo for the next year :-)

Run this script from Cron:

 

SERVER=irc.freenode.org
CHANNEL=mychannel
NICK=mynick

git pull
git log -4 --pretty=format:'%h - %an : %s (%cr)' > commits.txt

function announceCommits(){
  (
    echo NICK $NICK
    echo USER $NICK 8 \* : Notifier
    #echo "JOIN #$CHANNEL"

    while read -r LINE ; do
      #echo "PRIVMSG #$CHANNEL $LINE" >&2
      echo "PRIVMSG #$CHANNEL :$LINE"
      sleep 1
    done < commits.txt
    echo QUIT
  ) | nc -v $SERVER 6667
}

announceCommits

 

What's missing is detection of last announced commit.

That would go along the lines of keeping the last announed commit hash in a file, and only dumping the successors.

That should work with `git log --since`, but doesn't. I didn't want to spend more time fixing that as Jenkins does this for me (git poll build trigger).

The biggest news in the SwanLoom project (to be renamed to WindRide) is that the migration rules are now externalized. But:

 

  • What are they externalized to?
  • How powerful the rules are?
  • How to add it to the application and use it?
  • When will we colonize Mars?

 

Answers to these questions can be found in this introductory video.

More videos here.

 

Sorry for my accent, I am blushing when I hear it. Still - enjoy :-)

 

 

 

Here's the text, for SEO purposes.

Hello. I'm Ondra Žižka, and I will introduce the latest feature of WindRide -

which is a tool for migrating the configuration of JBoss Enterprise Application Platform (or EAP)

from version 5 to version 6. (Support for other servers will be added later.)

 

The latest feature is that the migration logic is externalized into XML files.

Let's see how it works.

 

The big picture is:

 

1. Query the source server for collection of information,

2. Iterate over these collections,

3. Take the actions based on what is found.

 

Now let's see how to define that.

 

The XML file contains a definition of so-called migrator, which is a logical group of actions covering certain configuration area, for example, datasources.

 

Migrator has a name which is then used by the program to refer to it.

 

It contains JAXB beans declarations, queries, and actions.

 

JAXB beans declarations tell the program what classes will be used for unmarshalling the configuration.

Since all of the application servers store their configuration mostly in XML files, JAXB is a natural choice.

 

Then comes an example of a query; in this case, it's an XML query. There are more types, for example, properties file query.

Different types target different ways of how configuration is stored in the source server.

More details about queries can be found in the project's documentation.

 

All queries have an ID, by which their result is referred in the actions.

Subject label is used in user interface, and for the HTML reports and error messages.

Other query attributes are specific for the particular query type.

 

Actions define the actual steps taken during migration.

Again, there are different types, specified by the `type` attribute.

Few types are built in, like CLI command action, XSLT transform action, file copy, and so on.

Custom actions may be implemented either in Java or Groovy. See the documentation for a how to.

 

A reference to the action may be stored in a variable.

If you are familiar with Ant, you can think of the action as an Ant task.

 

Typically, you need to migrate multiple configuration items.

These items are stored in collections returned by the aforementioned queries.

To iterate over the collections, the <forEach> element is used.

You refer the query, and declare the name of variable to store the item for each iteration step.

 

Inside a loop, you may declare another loop, or an action.

This way, in cobination with queries, you have quite powerful tools at hand.

But that's not all.

 

As you probably noticed, there are expressions inside the values.

The syntax used is Java Expression Language 2.0.

The values available for the expression language are documented, but generally, you can use:

 

* application's configuration

* application's arguments

* queries' results

* Any parent in the nested constructs (like <forEach> and <action>)

 

The <filter> element is a condition in a form of a Groovy expression

which controls whether given construct will be processed for the current iteration.

The same variables are available for the script as for the expressions.

 

An action nested in another action creates a dependency of the parent action.

The inner action be performed prior to the parent action,

and if it fails, parent action also fails.

 

Lastly, the warning element attaches a warning to an action.

Each action may have a list of text messages, which are presented to the users

when their manual intervention is needed.

Typically, in these cases:

 

* Migration of certain configration item is not supported (yet)

* Migration is not possible (for example, there's no equivalent in the target server)

* Certain discrepancy or inconsistency was found in the source server configuration.

 

So these are the externalized rules in a nutshell.

And as you can see, the combination of instruments gives you quite powerful tool.

 

Please refer to the project's documentation to find out

about all the implemented JAXB beans, queries, actions, and also how to implement your own,

which will be also covered by the upcoming videos.

 

See you soon!

I have a JBoss EAP server on a OpenShift. And occassionaly, a situation occurs which makes the app start throwing exceptions with lenghty stack traces on each request. That causes the logs to reach dozens of MB per day, and after some time, the hosting runs out of disk space. 

 

I couldn't find something which would take the exception and tell me if the same exception was already seen or not. Application wide. Could be expiring cache.

I recall I've seen some RepeatedExceptionsHandler or something such for Log4j which I use, or maybe it was Hibernate, but can't find it in a quick google search.

 

So here's my solution. Just a first sketch but works.

 

Usage

    catch( Exception ex ){
        int count = repeatedExDetector.countException( ex );
        if( count < 2 )
            log.error("Error rendering: " + path, ex);
        else
            log.error("Recurring rendering error: " + path);
        add( new TexyDocumentErrorPanel("document", "Error occured when loading document.", "Couldn't load: " + path, 500));
    }

 

Results

 

02:23:18,324 DEBUG Characteristic: 46d21ef0{8a5b1c7c@293{b0d929ae@276{b0d929ae@182{de8e612a@241
02:23:18,324 ERROR Error rendering: /programovani/artificial_intelligence/covering_ai_theory.texy:
    java.lang.UnsupportedOperationException: Definition lists not supported yet.
        at cz.dynawest.jtexy.modules.ListModule$DefListPatternHandler.handle(ListModule.java:293)
        ...

02:23:19,956 DEBUG Characteristic: 46d21ef0{8a5b1c7c@293{b0d929ae@276{b0d929ae@182{de8e612a@241
02:23:19,957 ERROR Recurring rendering error: /programovani/artificial_intelligence/covering_ai_theory.texy

 

Source

 

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *  Counts the occurrences of given exception.
 *  Uses messages hashes and first 3 stack elements class name hashes to determine "same" exception.
 * 
 *  @author Ondrej Zizka, ozizka at redhat.com
 */
public class RepeatedExceptionsDetector {
    private static final Logger log = LoggerFactory.getLogger( RepeatedExceptionsDetector.class );

    private final Map<String, Integer> exCount = new ConcurrentHashMap();

    private static final int STACKTRACE_SCAN_DEPTH = 3;

    /**
     *  Counts how many times given exception was seen.
     */
    public int countException( Exception ex ){
        String chara = buildCharacteristicsString( ex );
        log.info("Characteristic: " + chara);
        Integer count = this.exCount.get( chara );
        if( count == null )
            count = new Integer(1);
        else
            count++;
        this.exCount.put( chara, count );
        return count;
    }


    /**
     *  Builds a string which can be considered as a hash of given exception.
     */
    private static String buildCharacteristicsString( Exception ex ) {
        StringBuilder sb = new StringBuilder();

        Throwable curEx = ex;
        do{
            sb.append( Integer.toHexString( curEx.getMessage().hashCode() ) );
            StackTraceElement[] stackTrace = curEx.getStackTrace();
            // For each stack trace element, append "cFooClass@72".
            for( int i = 0; i < stackTrace.length & i <= STACKTRACE_SCAN_DEPTH; i++ ) {
                StackTraceElement ste = stackTrace[i];
                sb.append('{');
                sb.append( Integer.toHexString( ste.getClassName().hashCode() ) );
                sb.append('@');
                sb.append( ste.getLineNumber() );
            }
            sb.append("\n");
            curEx = curEx.getCause();
        }while( curEx != null );

        return sb.toString();
    }

}// class
ozizka

The CDI Inspector project

Posted by ozizka Jul 18, 2013

It's quite interesting that after few years of existence of CDI, there's still no runtime debugging tool (correct me if I'm wrong).

 

But that's going to change! Check the promising CDI Inspector project, a master thesis of Jakub Niedermertl, student of Masaryk University Brno.

 

Under development, let's see where it gets.

As an evening fun, I've added JBoss AS CLI client as a plugin to the JawaBot IRC bot.

That way, more admins may see and discuss the changes they're doing on the fly.

With some security added, it could be useful for someone.

Also I'm going to add IrcAppender so that also logs can be read.

 

Enjoy :-)

 

(00:50:50) ozizka: cli connect localhost admin
(00:50:51) JawaBot: ozizka: Connected to localhost
(00:50:59) ozizka:  /system-property=foo:add(value=bar)
(00:51:00) JawaBot: ozizka: OK: {"outcome" => "success"}
(00:51:13) ozizka:  /system-property=foo:read-resource
(00:51:13) JawaBot: ozizka: {
(00:51:13) JawaBot: ozizka:     "outcome" => "success",
(00:51:13) JawaBot: ozizka:     "result" => {"value" => "bar"}
(00:51:14) JawaBot: ozizka: }
(00:51:22) ozizka:  /system-property=foo:remove(value=bar)
(00:51:22) JawaBot: ozizka: OK: {"outcome" => "success"}
(00:51:26) ozizka: cli disconnect
(00:51:26) gpark: ozizka: Closed.

 

Source:

 

 

package org.jboss.jawabot.plugin.jbossascli.irc;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import org.apache.commons.lang.StringUtils;
import org.jboss.as.cli.impl.CLIModelControllerClient;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.dmr.ModelNode;
import org.jboss.jawabot.JawaBot;
import org.jboss.jawabot.ex.JawaBotException;
import org.jboss.jawabot.ex.JawaBotIOException;
import org.jboss.jawabot.irc.IIrcPluginHook;
import org.jboss.jawabot.irc.IrcBotProxy;
import org.jboss.jawabot.irc.IrcPluginException;
import org.jboss.jawabot.irc.IrcPluginHookBase;
import org.jboss.jawabot.irc.ent.IrcEvMessage;
import org.jboss.loom.utils.as7.AS7CliUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *  JBoss AS CLI client over IRC. Could be fun.
 * 
 *  @author Ondrej Zizka
 */
@ApplicationScoped
public class JBossAsCliPlugin extends IrcPluginHookBase implements IIrcPluginHook<Object> {
    private static final Logger log = LoggerFactory.getLogger( JBossAsCliPlugin.class );

    private static final String PLUGIN_NAME = "jboss-as-cli";

    private static final Pattern PAT_CLI_CMD = Pattern.compile("((?:/\\w+)*):([\\w-]+(\\(.*\\))?)");


    // CLI
    private ModelControllerClient cli;
    private Set<String> operators = new HashSet();

    @Inject private JawaBot jawaBot;



    // Just one at a time. Could handle more connections in the future.
    @Override
    public void onMessage( IrcEvMessage msg, IrcBotProxy bot ) throws IrcPluginException {

        String pl = msg.getPayload().trim();

        // Connect
        if( msg.getPayload().startsWith("cli connect ") ){
            String[] parts = StringUtils.split( pl );
            if( parts.length < 4 ){
                bot.sendReplyTo( msg, "Try `cli connect <host> <user> [<port>]`. You'll be asked for password on PM.");
            } else {
                try {
                    int port = parts.length > 4 ? Integer.parseInt(parts[4]) : 9999;

                    //ModelControllerClientConfiguration conf = new 
                    this.cli = CLIModelControllerClient.Factory.create( parts[2], port );
                    this.operators.clear();
                    this.operators.add( msg.getUser() );
                    bot.sendReplyTo( msg, "Connected to " + parts[2]);
                } catch( Exception ex ) {
                    bot.sendReplyTo( msg, "Can't connect: " + ex.getMessage() );
                }
            }
            return;
        }

        // Disconnect
        if( msg.getPayload().startsWith("cli disconnect") ){
            if( ! this.operators.contains( msg.getUser() ) ){
                this.onlyOpsInfo( msg, bot ); return;
            }
            try {
                this.cli.close();
                this.cli = null;
                this.operators.clear();
                bot.sendReplyTo( msg, "Closed." );
            } catch( Exception ex ) {
                bot.sendReplyTo( msg, "Sorry, failed: " + ex.getMessage() );
            }
            return;
        }

        // Add operator
        if( msg.getPayload().startsWith("cli addop ") ){
            String[] parts = StringUtils.split( pl );
            if( ! this.operators.contains( msg.getUser() ) ){
                this.onlyOpsInfo( msg, bot ); return;
            }
            try {
                this.operators.add( parts[2] );
                bot.sendReplyTo( msg, "Added." );
            } catch( Exception ex ) {
                bot.sendReplyTo( msg, "Sorry, failed: " + ex.getMessage() );
            }
            this.cli = null;
            return;
        }

        // CLI Command
        boolean find = PAT_CLI_CMD.matcher(pl).find();
        if( find ){
            if( ! this.operators.contains( msg.getUser() ) ){
                this.onlyOpsInfo( msg, bot ); return;
            }
            if( this.cli == null ){
                bot.sendReplyTo( msg, "Not connected. Try `cli connect ...`" );
                return;
            }
            try {
                ModelNode res = this.cli.execute( AS7CliUtils.parseCommand( pl, true ) );
                final String resStr = res.toString();
                if( ! resStr.contains("\n") )
                    bot.sendReplyTo( msg, "OK: " + resStr );
                else {
                    for( String string : StringUtils.split( resStr, "\n")) {
                        bot.sendReplyTo( msg, string );
                    }
                }
            } catch( Exception ex ) {
                bot.sendReplyTo( msg, "Sorry, failed: " + ex.getMessage() );
            }
            return;
        }
    }// onMessage()


    private void onlyOpsInfo( IrcEvMessage msg, IrcBotProxy bot ) {
        String ops = StringUtils.join( operators, ", ");
        bot.sendReplyTo( msg, "You can't do that. Ask "+ops+" to add you. `cli addop "+msg.getUser()+"`" );
        return;
    }

}// class
ozizka

False Programming Mantras

Posted by ozizka Jul 11, 2013

I really hate when people repeat something they were taught as a "good thing to do" without thinking about it.

This is true for all aspects of life, starting with right to own a gun over various beliefs to being politically correct.

 

But there are also plenty of examples in programming.

This will be my list of arguments against illogical statements repeated all over the world by people just because some expert said so 20 years ago in totally different context.

 

Public class fields

class Foo {
    public String bar;
}

 

This is not evil. Evil is to make it part of an API. But if you use it within your package, or even a class, it's totally OK. Especially if the classes are not public.

Think of C. How did you model structures in it?  struct { ... }. A class with public members is Java's structs.

And if you have an internal algorithm which uses structures, it's nonsense to create a full-blown classes with getters and setters.

 

If you want to have some examples, check the sources of JDK. Almost any imlementation of complex algorithms uses this. E.g. regular expressions.

Sure, we can argue that JDK isn't always the best Java code. But then, what is.

 

Separating resources and java code

This nonsense came with the fame of Maven. Lazy programmers didn't separate these in Ant, because it was nearly twice as much XML code.

But Maven made it so easy - all the archetypes had it, IDEs support it, etc. Nice.

 

But then, some projects intentionally do:

 

<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes> <include>**/*</include> </includes>
        <excludes> <exclude>**/*.java</exclude> </excludes>
        <filtering>false</filtering>
    </resource>
    <resource>
        <directory>resources</directory>
        <includes> <include>**/*</include> </includes>
    </resource>
</resources>

 

Then someone comes and says, "you know nothing about resources separation, John Snow".

Well, thanks, Mr. Smart, but you're wrong.

Resources separation is not done just because "it's good, mkay?", but for a purpose, which is:

Different people sometimes work on these two, and they are handled by different processes at different time.

 

But if you have source file, which just happens not to be compiled, then it totally makes sense to have it right next to java files.

Examples of such can be various built-in scripts, Hibernate XML descriptors, log4j.properties, jaxb.properties, default config files, built-in data, etc.

All the kind which is maintained by the very same people which work on the code around. (Unless these files are supposed to be changed by admins etc).

This is especially true for test suites.

Note: Don't confuse with putting these files to the resulting distributed artefact - that's a different story.

 

"Prefer composition over inheritance"

Gavin King posted on Google Plus:

Please, please stop saying "prefer composition over inheritance", as if there were no problems best solved using subtyping. And please stop nodding sagely every time you hear someone else say it. Through unthinking repetition, this phase, originally meant as a suggestion to weigh up the advantages and disadvantages of different solutions, has totally lost its original meaning in most people's heads, and has now become a vague, general-purpose item of FUD deployed to make us feel uncomfortable about using one of the basic modeling strategies in our toolbox. There are problems best solved using subtyping (assuming our language has subtypes) and there are problems not best solved using subtyping. But "prefer composition over inheritance" taken literally and without qualification gives us exactly zero advice on how to distinguish the first set of problems from the second. We will only become better programmers when we quit mindlessly repeating vague rules of thumb passed down from the 70's or 80's, and actually start using our own brains to think things through and analyze potential solutions in terms of objective software engineering goals. Grrrr.

 

Don't use /, use File.separator

Happened to me several times that I posted a classloading code, and someone told me "don't use /, that's platform specific". Well, that's true. But only for filesystem paths. For class paths, it's always /. Someone suggested that even for an XPath expression. No comment.

Exception-driven execution flow

 

Ignoring exceptions

Sometimes, exceptions _can_ be ignored - e.g. if they are misused in a library for flow control.

 

Label and break - Java's GOTO

 

Comparing instances using == vs. equals()

Comparing objects using just Java heap address is enough in many cases - no need to call hashCode() of both objects. This is typically true for objects which are not stored anywhere during their lifespan. (Not sure if JIT compiler optimizes using equals() on objects without overriden hashCode().)

 

Using JPA Entities through all layers of the app

 

Mixing user input validation and persistence layer validation

 

Using CRC32 for hashes

There are SHA1 and MD5. But who needs such a strong hash for just hashing purposes (not security)? What's the chance that you'll find 2 same contents for which CRC32 will give you same hash?

 

Using eval() in various scripting languages

Scripting languages have the strong advantage in ability to execute code on the fly. That's almost the definition of them.

Sometimes, generating a code is the most effective way to do the job (though not the ellegant). Saying "eval() is evil" blocks you from those solutions.

 

Using with(...) in JavaScript

Javascript's stack can be a tricky beast, especially with closures. "with( ... )" should be avoided in code where you call various lib's code, but in code which is purely yours, "with()" can shorten your code neatly.

 

Single return statement in a method

Someday in the ancient ages of C or Pascal programming, someone stated that a method should only have one return point. There's no study for that, it's just the matter of taste. Actually, multiple return points can save you a lot of parentheses. If you don't like returns, don't force your taste on others.

 

Stored procedures and triggers are evil

 

Using underscores in Java method and package names

Underscore is not a common character to use in Java code, since it's so "C". But sometimes, it makes sense. Especially for internal methods. For exwemple, it can nicely denote which methods do not check the input.

 

Overrated call recursion (with recent popularity of functional languages)

Recursion can be done in few ways. With the increasing popularity of functional languages, some people solve recursive problems by recursive method calls.

Why not. But for simple problems, it's a performance issue. It's enough to put information on a stack. Additional method call consumes more data than just the payload.

 

 

To be continued...

That's not all, I often people uncritically accepting anything what reaches their ears, the only filter is "how famous the guy who said it is".

So I have a good source :-)

Motivation

Suppose you have a big project with tens or hundreds of Maven modules.

Some of them are that kind which only packages things, or intentionally has no tests, or no resources, etc.

 

Suppose the first case, when you just create a .jar with some resources.

During the build, this is what you would see:

 

[INFO] ------------------------------------------------------------------------
[INFO] Building JawaBot 2.0 conf/redhat-test 2.0.0.GA-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ JawaBot-config-redhat-test ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ JawaBot-config-redhat-test ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ JawaBot-config-redhat-test ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/ondra/work/TOOLS/JawaBot/configs/redhat-test/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ JawaBot-config-redhat-test ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-surefire-plugin:2.15:test (default-test) @ JawaBot-config-redhat-test ---
[INFO] Tests are skipped.
[INFO] 
[INFO] --- maven-jar-plugin:2.2:jar (default-jar) @ JawaBot-config-redhat-test ---
[INFO] Building jar: /home/ondra/work/TOOLS/JawaBot/configs/redhat-test/target/JawaBot-config-redhat-test-2.0.0.GA-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-install-plugin:2.3:install (default-install) @ JawaBot-config-redhat-test ---
[INFO] Installing /home/ondra/work/TOOLS/JawaBot/configs/redhat-test/target/JawaBot-config-redhat-test-2.0.0.GA-SNAPSHOT.jar to /home/ondra/.m2/repository/org/jboss/jawabot/configs/JawaBot-config-redhat-test/2.0.0.GA-SNAPSHOT/JawaBot-config-redhat-test-2.0.0.GA-SNAPSHOT.jar
[INFO] Installing /home/ondra/work/TOOLS/JawaBot/configs/redhat-test/pom.xml to /home/ondra/.m2/repository/org/jboss/jawabot/configs/JawaBot-config-redhat-test/2.0.0.GA-SNAPSHOT/JawaBot-config-redhat-test-2.0.0.GA-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.755s
[INFO] Finished at: Sun Jul 07 05:05:54 CEST 2013
[INFO] Final Memory: 10M/213M
[INFO] ------------------------------------------------------------------------

 

But you don't really need all those steps. These executions do nothing:

 

maven-compiler-plugin:3.1:compile (default-compile)
maven-resources-plugin:2.6:testResources (default-testResources)
maven-compiler-plugin:3.1:testCompile (default-testCompile)
maven-surefire-plugin:2.15:test (default-test)

 

It's just a second and something (on an SSD disk, though), but that's still worth saving.

Fortunatelly, there's a way to disable these executions.

Disabling unnecessary plugin executions

Notice the identifier in parentheses. That's the execution ID.

If you check so-called super-POM, it has default bindings of the plugin executions for some module type, which you then see even if your pom.xml doesn't define them.

 

If you re-define them and bind them to a non-existent phase, they won't run:

 

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <executions>  <execution> <id>default-test</id> <phase>none</phase> </execution> </executions>
</plugin>

 

The same way, you may disable all the other executions.

 

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <executions> <execution> <id>default-test</id> <phase>none</phase> </execution> </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <executions>
        <execution> <id>default-compile</id> <phase>none</phase> </execution>
        <execution> <id>default-testCompile</id> <phase>none</phase> </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <executions> <execution> <id>default-testResources</id> <phase>none</phase> </execution> </executions>
</plugin>

 

The result

[INFO] ------------------------------------------------------------------------
[INFO] Building JawaBot 2.0 conf/redhat-test 2.0.0.GA-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]  
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ JawaBot-config-redhat-test ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO] 
[INFO] --- maven-jar-plugin:2.2:jar (default-jar) @ JawaBot-config-redhat-test ---
[INFO] Building jar: /home/ondra/work/TOOLS/JawaBot/configs/redhat-test/target/JawaBot-config-redhat-test-2.0.0.GA-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-install-plugin:2.3:install (default-install) @ JawaBot-config-redhat-test ---
[INFO] Installing /home/ondra/work/TOOLS/JawaBot/configs/redhat-test/target/JawaBot-config-redhat-test-2.0.0.GA-SNAPSHOT.jar to /home/ondra/.m2/repository/org/jboss/jawabot/configs/JawaBot-config-redhat-test/2.0.0.GA-SNAPSHOT/JawaBot-config-redhat-test-2.0.0.GA-SNAPSHOT.jar
[INFO] Installing /home/ondra/work/TOOLS/JawaBot/configs/redhat-test/pom.xml to /home/ondra/.m2/repository/org/jboss/jawabot/configs/JawaBot-config-redhat-test/2.0.0.GA-SNAPSHOT/JawaBot-config-redhat-test-2.0.0.GA-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.181s
[INFO] Finished at: Sun Jul 07 05:28:48 CEST 2013
[INFO] Final Memory: 7M/148M
[INFO] ------------------------------------------------------------------------

 

We saved around 30 % of the build time.

 

Now you probably hate me because it only speeds up modules like this :-) But still even few seconds and smaller logs is worth doing this change.

And that's not all.

Be smart, type less

Maven's plugin configuration is inherited from parent.

So if you have multiple modules, you may put these suppressing <plugin> elements to some umbrella pom and then just use that as a parent for the modules.

 

This umbrella may inherit from your project's pom - it won't affect the rest of the project.

As you may see, I don't define plugin versions in my example above; that's because I've set them in <pluginsManagement> in my project's root.

 

Deploying only the distribution .jar

The above technique can also be used to control what artifacts to deploy.

Assume you only want to deploy (upload) a distribution .jar of your application, since the modules are useless for public users.

 

In this case, you'd disable `default-deploy` (or what the name is) in the root `pom.xml`:

 

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-deploy-plugin</artifactId>
        <executions> <execution> <id>default-deploy</id> <phase>none</phase> </execution></executions>
    </plugin>

And then enable it for submodules:

 

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-deploy-plugin</artifactId>
        <executions> <execution> <id>default-deploy</id> <phase>deploy</phase> </execution></executions>
    </plugin>

Filter Blog

By date:
By tag: