Controller for views in root

Yesterday while developping ukazbobra I realized, that I don’t know how to map controller for my index view in root of Spring MVC project. I searched and experimented a bit and here is a solution. Please note I’m using Spring Roo and annotation driven setup. First thing is to create controller, for example simple one … Pokračovat ve čtení „Controller for views in root“

Yesterday while developping ukazbobra I realized, that I don’t know how to map controller for my index view in root of Spring MVC project. I searched and experimented a bit and here is a solution. Please note I’m using Spring Roo and annotation driven setup.

First thing is to create controller, for example simple one like this:

[code language=“java“]@RequestMapping("/")
@Controller
public class RootController {

@RequestMapping(method = RequestMethod.GET)
public String index(Model model) {
model.addAttribute("foo", "bar");
return "index";
}
. . .
[/code]

Now you have to turn off thing named ParameterizableViewController, which staticaly selects a view for for rendering. So open up webmvc-config.xml and remove line with mapping for index view:

[code language=“xml“]<mvc:view-controller path="/" view-name="index"/>[/code]

That is all, nothing more, nothing less – you have working controller for your index page in root and also for other views.

Komunikace se zabezpecenymi webovymi sluzbami

Dnes jsem se trapil s tvorbou klienta, ktery se mel pripojit na vzdalenou webovou sluzbu s klientskym certifikatem a predevsim – autentikovat se pomoci jmena a hesla. Nakonec se chyba ukazala byt trochu jinde, nez jsem ji cekal, ale kdyz uz jsem s tim stravil cas, tak to tu trochu popisu, kdyby nahodou nekdo resil … Pokračovat ve čtení „Komunikace se zabezpecenymi webovymi sluzbami“

Dnes jsem se trapil s tvorbou klienta, ktery se mel pripojit na vzdalenou webovou sluzbu s klientskym certifikatem a predevsim – autentikovat se pomoci jmena a hesla. Nakonec se chyba ukazala byt trochu jinde, nez jsem ji cekal, ale kdyz uz jsem s tim stravil cas, tak to tu trochu popisu, kdyby nahodou nekdo resil podobny problem.

Nejprve ona chyba – mam zdrojak pro klienta vygenerovany pomoci wsimportu a protoze jsem se snazil o univerzalni reseni, adresa koncoveho bodu je v .properties souboru. Lokalne mam ovsem ulozeny wsdl, na ktery se odkazuju pomoci anotace @WebServiceClient ve tride klienta:

[code language=“java“]@WebServiceClient(
name = "myService",
targetNamespace = "http://www.shmoula.cz/my/service",
wsdlLocation = "META-INF/wsdl/myService.wsdl")
public class MyServiceClient extends Service{
[/code]

No a tohle byl muj problem – toto lokalni wsdl se neshodovalo s deskriptorem na druhe strane (odstranil jsem policy cast), takze mi server porad odmital pozadavky:

[code language=“plain“]javax.xml.ws.WebServiceException: Failed to access the WSDL at: https://shmoula.cz:8080/myService?wsdl. It failed with:
Connection refused.
[/code]

Stacilo zmenit wsdlLocation na adresu deskriptoru na serveru a vse uz bezi v poradku. Hadam, ze kdyby lokalni wsdl presne odpovidalo tomu na serveru, fungovalo by to taky. Ted ale to podstatnejsi – jak autentikovat uzivatele?

Nejprve mejme vygenerovany a naimportovany certifikat v trusted certs, napr. pomoci keytool:

[code language=“bash“]keytool -import -alias shmoula.cz -file certifikat.shmoula.cz.der -keystore <J2EE_HOME>/domains/domain1/config/cacerts.jks
[/code]

Potom budeme potrebovat vlastni implementaci tridy Authenticator, kterou zajistime, aby byly autentikacni informace predavany pouze pri zabezpecenem spojeni:

[code language=“java“]package cz.shmoula.klient;

import java.net.Authenticator;
import java.net.PasswordAuthentication;

public class BasicHTTPAuthenticator extends Authenticator {
private String userName;
private String password;

public BasicHTTPAuthenticator(String userName, String password){
this.userName = userName;
this.password = password;
}

@Override
protected PasswordAuthentication getPasswordAuthentication(){
if (this.getRequestingProtocol().equalsIgnoreCase("https"))
return new PasswordAuthentication(userName, password.toCharArray());
else
return null;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}
[/code]

V aplikaci je potom nutne nejprve nastavit tento autentikator a teprve pote vytvorit instanci klienta:

[code language=“java“]URL baseUrl = cz.shmoula.klient.MyServiceClient.class.getResource(".");
URL url = new URL(baseUrl, "https://shmoula.cz:8080/myService?wsdl");
QName qName = new QName("http://www.shmoula.cz/myservice", "myService");

Authenticator.setDefault(new BasicHTTPAuthenticator("jmeno", "heslo"));
MyServiceIface service = new MyServiceClient(url, qName).getMyServicePort();
[/code]

Pote je nutne jeste poupravit kontext pozadavku pomoci BindingProvidera a je mozne se pustit do volani vzdalenych metod, vse zabezpeceno:

[code language=“java“]BindingProvider bp = (BindingProvider) service;
bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "jmeno");
bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "heslo");
MyServiceResponse resp = service.makeCall(foo, bar);
[/code]

Abych pravdu rekl, prestava se mi to libit cim dal tim vic, asi se vratim k JSONu. Podstatne je, ze to mam z krku.

Validace vstupu webových služeb

Potřeboval jsem validovat vstup webové služby na základě xsd šablony – a to jak typy, tak patterny a potřeboval jsem to pokud možno obecně a jednoduše. Postupně jsem se dobral řešení, které se pokusím níže popsat. Měl jsem zadaný wsdl dokument, k němu definici typů v xsd a příkaz použít jax-ws. Takže jsem provedl wsimport … Pokračovat ve čtení „Validace vstupu webových služeb“

Potřeboval jsem validovat vstup webové služby na základě xsd šablony – a to jak typy, tak patterny a potřeboval jsem to pokud možno obecně a jednoduše. Postupně jsem se dobral řešení, které se pokusím níže popsat.

Měl jsem zadaný wsdl dokument, k němu definici typů v xsd a příkaz použít jax-ws. Takže jsem provedl wsimport a začal zkoušet. Na komplexní typy byl pomocí jaxb vytvořen binding, takže mi vznikla trochu poschoďovější struktura, která ovšem nebrala v úvahu definované simple typy a prostě je převedla na podobné typy jazyka Java. Pokud jsem tento projekt spustil na serveru, patterny těchto typů prostě zmizely a vygenerované xsd bylo úplně jiné, wsdl se jakž-takž podobalo. Stačilo ovšem přidat parametr k anotaci WebService, který specifikoval cestu k originálnímu wsdl.

[sourcecode language=“java“]@WebService(
name = &quot;myServiceSei&quot;,
targetNamespace = &quot;http://www.shmoula.cz/schema/myservice&quot;,
wsdlLocation = &quot;META-INF/wsdl/myService.wsdl&quot;
)[/sourcecode]

V tomto okamžiku jsem měl ovšem problém s bindingem, který jsem původně přiřazoval nějaké chybičce ve jmenných prostorech, a ten způsoboval, že mi služba předávala null hodnoty. Nakonec se ukázalo, že v zadaném wsdl se vyskytuje zpráva z názvem doSomeStuffRequest, který se kryl s elementem ve vlastním těle této zprávy (navíc jax-ws přidává postfix Request automaticky), takže stačilo tento název změnit a vše bylo v pořádku a já byl o krok blíže k validování.

První, co mě napadlo, bylo použití anotace SchemaValidation, tak jsem ji použil. Služba se ovšem chovala, jako by tam tato anotace vůbec nebyla a prošlo naprosto všechno. Tudíž nastoupilo řešení číslo dvě – použítí Marshalleru, který by měl při nesrovnalostech skončit s výjimkou. Končil, ovšem s výjimkou jinou, než jsem čekal.

unable to marshal type "cz.foo.bar.DoSomeStuffRequest" as an element because it is missing an @XmlRootElement annotation

Důvody jejího vzniku pěkně rozebral Kohsuke Kawaguchi ve svém blogpostu a protože jsem nechtěl do všech typů cpát XmlRootElement, řídil jsem se jí a dobral se funkčnosti – opravdu mi to validuje! Ještě jsem si s řešením trochu pohrál a především využil vygenerované ObjectFactory, abych nemusel vytvářet vlastní JAXBElement. Výsledek vypadá (zhruba) následovně a funguje na výbornou.

[sourcecode language=“java“]@WebMethod
public void doSomeStuff(DoSomeStuffRequest serviceParameters) {

ObjectFactory of = new ObjectFactory();
JAXBElement&lt;DoSomeStuffRequest&gt; element = of.createParcelImportRequest(serviceParameters);
SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);

try {
URLClassLoader cl = (URLClassLoader) getClass().getClassLoader();
URL url = cl.findResource(&quot;META-INF/wsdl/myService.xsd&quot;);

Schema schema = sf.newSchema(url);

JAXBContext context = JAXBContext.newInstance(DoSomeStuffRequest.class);

Marshaller marshaller = context.createMarshaller();
marshaller.setSchema(schema);

marshaller.marshal(element, new DefaultHandler());

} catch (SAXException e) {
e.printStackTrace();
} catch (JAXBException e) {
e.printStackTrace();
}
}
[/sourcecode]

PS. Nic to ovšem nemění na tom, že SOAP není mrtvý, ale nemrtvý (a vůbec že je to fuj)!

Android MapView a onTouch

Nemálo mě, a nejenom mě, štve absence něčeho, jako je onTouch() v mapách na Androidu, protože potřebuju vytvořit dynamické načítání overlayů. MapView sice má onTouchEvent(), ale že by bylo možné jej použít nějakým mnou zamýšleným způsobem, to zrovna ne. Zkoušel jsem pár způsobů, které tu nastíním a taky jsem zkusil jedno ne zrovna dvakrát moc … Pokračovat ve čtení „Android MapView a onTouch“

Nemálo mě, a nejenom mě, štve absence něčeho, jako je onTouch() v mapách na Androidu, protože potřebuju vytvořit dynamické načítání overlayů. MapView sice má onTouchEvent(), ale že by bylo možné jej použít nějakým mnou zamýšleným způsobem, to zrovna ne. Zkoušel jsem pár způsobů, které tu nastíním a taky jsem zkusil jedno ne zrovna dvakrát moc fér řešení. Ale zoufalí lidé se uchylují k zoufalým věcem, však to znáte… Jen to vezmu hodně hopem, protože mám moře jiných věcí na dělání, ale pár lidem jsem to slíbil a sliby se mají plnit a to nejen o Vánocích ;-).

Zatímco natahování je poměrně jasné (AsyncTask, který bude natahovat data ve čtverci, jehož směrem jsem se posunul – na základě kolize souřadnic tohoto čtverce a viewportu – aby to pořád netahalo jak blbé), taková trivialita jako je onTouch už tak jasná není.

Nejprve jsem se snažil přimět k rozumu metodu onTouchEvent() jak na MapView, tak i na Overlayi, bohužel bezúspěšně. Zajímalo by mě, jestli je tento event pozůstatek něčeho zaniklého, nebo se na něj jenom nějak zapomnělo. Tento způsob by měl fungovat nějak takto, což vypadá poměrně prakticky a použitelně – ve switchi checkovat eventy:

[sourcecode language=“java“]public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
. . .
}
return super.onTouchEvent(ev);
}[/sourcecode]

Bohužel – z nějakého důvodu tato metoda vůbec nebyla volána. Po nějakém googlení jsem narazil na blog Juriho Strumpflohnera, který řešil stejný problém a vyšpekuloval ho následovně: na mapView navěsit vlastní OnTouchListener(), čili přidat jednoduchou anonymní třídu:

[sourcecode language=“java“]mapView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent ev) {
return false;
}
});[/sourcecode]

Pokud teda dojde k eventu Touch, jsou procházeny všechny views a případné implementace listenerů v nich. V listeneru implementovaná metoda onTouch je volána nejméně jednou v závislosti na tom, zda vrátí true či false. Pokud vrací false, provede se pouze poprvé a systém je tak chytrý, že už jde příště rovnou na jistotu (aka přímo po metodě, která vrátila true), což je zároveň i kámen úrazu: je nutné zajistit, aby byla volána i metoda „níže“, protože se při true mapa nepohybuje (ale náš onTouch je volaný vždycky). Je teda nutné předat „nižšímu view“ tento event. Nejprve jsem volal dispatchTouchEvent() na view, který přišel do onTouch, ale to je blbost, protože tento view je vlastně onen MapEvent, nad kterým byl navěšen tento listener, takže došlo k zacyklení a StackOverflowError. Takže jsem třídu odanonymizoval a předávám si do ní Context, což je aktivita, uvnitř které je mapView:

[sourcecode language=“java“]public class MyTouchListener implements View.OnTouchListener {
private Activity activity;

public MyTouchListener(Activity activity) {
super();
this.activity = activity;
}

public boolean onTouch(View v, MotionEvent ev) {
activity.dispatchTouchEvent(ev);
return true;
}
}[/sourcecode]

Taky to ovšem nejede, ale oproti dispatchování do view to vydrží o chvíli déle (a pak to stejně přeteče zásobník a zdechne).

Jak už to bývá, funkční řešení bývají ta nejjednodušší, takže dneska tenhle blogpost konečně dorazím!

Ono totiž stačí rozšířit map view a přepsat v něm onTouchEvent, nebo onInterceptTouchEvent (jak je popsáno tady). V čem je zakopán pudl? V ničem, opravdu to funguje. Předchozí Class Cast Exception se dá zbavit velice jednoduše – definovat správný typ v layoutu! Pojďme tedy na to, nejprve vlastní mapView:

[sourcecode language=“java“]package cz.shmoula.pat;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;

import com.google.android.maps.MapView;

public class AreaMapView extends MapView {
private Context mContext;

public AreaMapView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
mContext = context;
}

public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_MOVE) {
Log.i("!!!!!", "Pohyb!");
}
return super.onTouchEvent(ev);
}
}[/sourcecode]

Teď následuje onen výše zmíněný kámen úrazu, který dříve hulákal Class Cast výjimkou a je to docela logické, ale nevěděl jsem, že je možné vkládat do layoutů vlastní komponenty. Teď už to vím, tak je možné psát něco zhruba takového:

[sourcecode language=“xml“]<?xml version="1.0" encoding="utf-8"?>

<cz.shmoula.pat.AreaMapView
xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/areaMapView"

android:layout_width="fill_parent"
android:layout_height="fill_parent"

android:clickable="true"
android:apiKey="api_klíč"
/>
[/sourcecode]

No a v aktivitě se tato komponenta dohledá každému známým způsobem:

[sourcecode language=“java“]AreaMapView mapView = (AreaMapView) findViewById(R.id.areaMapView);[/sourcecode]

Toť vše! Opravdu, v jednoduchosti je síla. Takže teď přidat nějaké spočítání delta a pokud bylo pohnuto viewportem více, než je výše uvedený čtverec v onu stranu, tak načíst další. Na závěr se ještě musím přiznat, že toto řešení jsem nevyplodil sám, ale sprostě se nechal inspirovat OpenCachingem od Garmina, který mě nakopl na správnou cestu směrem k výsledku. Při pídění se po řešení jsem taky narazil na projekt mapview-overlay-manager, ve kterém se nachází Lazy loading a který si nechávám k dalšímu prostudování a hádám, že nebudu sám.

Testování EJB

V poslední době jsem byl nucen se věnovat vývoji aplikace s nálepkou Enterprise a to tak, že používám EJB. Možná někdy časem budu moci prozradit, co je to za aplikaci a přidat nějaké informace o tom, jak jsem co navrhoval a realizoval, zatím však budu mlčet jako hrob. Pootevřenej – potřeboval jsem testovat a to … Pokračovat ve čtení „Testování EJB“

V poslední době jsem byl nucen se věnovat vývoji aplikace s nálepkou Enterprise a to tak, že používám EJB. Možná někdy časem budu moci prozradit, co je to za aplikaci a přidat nějaké informace o tom, jak jsem co navrhoval a realizoval, zatím však budu mlčet jako hrob. Pootevřenej – potřeboval jsem testovat a to bych to zmínit mohl, protože jsem tomu nějaký čas dal.

Pro některé beany (transformátory) bylo možné napsat jednotkové testy, které nepotřebovaly pro svůj běh EJB kontejner – prostě bylo možné vytvořit instanci dané třídy, provést transformaci (či validaci) a podívat se, jaký je výsledek. Pro další služby jsem už ovšem EJB kontejner potřeboval – takže  bylo potřeba jej buď spustit, nebo nasimulovat (pěkně to zblognul před mnoha lety finc, který odkazuje na Ejb3unit, ještě dříve krecan odkázal ve spojitosti se Springem na Pitchfork – přiznám se, vyprdl jsem se na oba).

Nejprve jsem uvažoval nad embeded glassfishem, ale zdálo se mi to úchylné, tak jsem rozhodil síť na twitteru a ozval se @dblevins s odkazy, jak je to pácháno na OpenEJB. To jsem zkoušel mimo video je to pěkně popsáno třeba zde), ale končil jsem s

[sourcecode language=“plain“]java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/ejb/embeddable/EJBContainer
[/sourcecode]

což se opakovalo, i když jsem se snažil vygooglit řešení a různě si s tím hrál. Podle všeho jsou knihovny pouze abstrakce a vlastní implementaci vkládá až zvolený kontejner, alespoň tak jsem to pochopil. Takže jsem se ve finále rozhodl jít cestou onoho embedded kontejneru.

Protože vyvíjím pro Glassfishe, padla volba na použití embedded glassfishe. Nejprve jsem se inspiroval Adamem Bienem a pokoušel se vytvořit archiv a ten následně deploynout, což však samozřejmě nebyla správná cesta. Hledal jsem dále a konečně objevil něco funkčního – vytvoření kontejneru se zkompilovanými classami a získání kontextu, nad kterým je možné provádět lookup. Teď bych sepsal kroky, jak jsem to celé zjednodušil a nacpal do ukázkového projektu.

Nejprve si vytvořme nový projekt pomocí mavenu

[sourcecode language=“plain“]mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=cz.shmoula -DartifactId=ejbTesting[/sourcecode]

následně je vhodné změnit pom.xml dle výše uvedeného zdroje – přidat závislost a parametry, případně repozitář

[sourcecode language=“plain“]. . .
<dependency>
<groupId>org.glassfish.extras</groupId>
<artifactId>glassfish-embedded-all</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
. . .
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
. . .
<repository>
<id>glassfish-repository</id>
<url>http://download.java.net/maven/glassfish</url>
</repository>
[/sourcecode]

Teď je možné přidat například lokální stateless bean a jednoduše jej otestovat, část TestCase je uvedena níže. Za povšimnutí stojí především specifikace cesty, kde se nalézají classes, vytvoření (a uzavření) kontejneru a získání kontextu a dohledání pokusného beanu.

[sourcecode language=“java“]@Override
@Before
protected void setUp() throws Exception {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(EJBContainer.MODULES, new File("target/classes"));
properties.put("org.glassfish.ejb.embedded.glassfish.installation.root", "glassfish");
properties.put(EJBContainer.APP_NAME, "pokus");

container = EJBContainer.createEJBContainer(properties);
Context ic = container.getContext();

Object o = ic.lookup("java:global/pokus/Pokus");
if(o instanceof Pokus)
this.pokus = (Pokus) o;
}

@Override
@After
protected void tearDown() throws Exception {
container.close();
}

@Test
public void testPokus(){
assertNotNull(pokus);
}

@Test
public void testScitani(){
assertEquals(9, pokus.scitani(5, 4));
}[/sourcecode]

To by mohlo být vše, teď to nějak aplikuju na WS, snad se to tak používá (chci testovat služby na straně serveru) a potom zkusím vkládat Messages na jazyk MDB :-). Nakonec to zas až tak nebolelo, i když mi připadá hodně úchylné ono spouštění embedded kontejneru. Je škoda, že v oficiální dokumentaci se o testování nic nepíše (nebo jsem to přehlédl? prosím link).

Oracle Java Developer Conference

Mám v poslední době takovej nějakej dojem, že navštívené konference mi nějak nic nedávají. Otázka je, jestli stárnu, nebo jestli za to může fakt, že jsem se den před touto konferencí nepěkně picnul a modlil se, ať už to skončí. Pravda ovšem může být úplně jinde – recykluje se. No a protože slíbené slajdy z … Pokračovat ve čtení „Oracle Java Developer Conference“

Mám v poslední době takovej nějakej dojem, že navštívené konference mi nějak nic nedávají. Otázka je, jestli stárnu, nebo jestli za to může fakt, že jsem se den před touto konferencí nepěkně picnul a modlil se, ať už to skončí. Pravda ovšem může být úplně jinde – recykluje se. No a protože slíbené slajdy z androidDevCampu pořád nejsou (a nemůžu tu komentovat co jsem chtěl), zkusím se zamyslet nad tím, co se mi děje.

Vzpomínám si, jak jsem se „zamlada“ těšil na Invex, asi tak moc, jak jsem tuto akci potom nenáviděl. Důvod se mi zdá prostý – internet a přebytek informací (Brave new world). Pokud se člověk o něco zajímá, určitě má dané téma nastudované ze všech stran a zná detaily. Proto mi svého času přišlo zbytečné chodit na výše zmíněnou výstavu. Stejný dojem bohužel začínám získávat i z různých konferencí. Pokud člověk nejede vyloženě získávat kontakty (případně se dobře najíst či flirtovat s hosteskama), bude to zabitý čas.

Oracle Java Developer Conference
Oracle Java Developer Conference

Posledních několik týdnů jsem se věnoval hlubšímu studiu Enterprise edition Javy (všechny ty servlety a podobné věci už potkávám pár let, ale injektáže a další věci mimo Spring jsem si ještě pořádně neošahal), tak jsem se těšil, že nabudu nové tipy a směrovky, na co se dále podívat… bohužel. Dopolední část programu bylo víceméně vzájemné plácání se přednášejících po ramenou, co že se povedlo, jak to bylo tenkrát, jak je to teď… zakončené povídáním Aleše Koběrského z Home Creditu, co že vlastně dělají a jak to u nich vypadá. Jasně, z velké části na akci byli studenti, kteří budou hledat job, ale stejně mi to nesedí. Navíc je otázka, jestli vůbec budou mít zájem (u oběda porovnávali nabídky různých firem, tam že dávají auto, tam jiné benefity…), jestli si nevysnili něco úplně jiného (pečené holuby zadarmo do huby).

Oracle Java Developer Conference
Oracle Java Developer Conference

Po obědě to začalo být zajímavé – Martin Marko (Web development for java web developers. Bad practices and solutions) rozjel show na téma jakýchsi vlastních dá se říci šablonovacích systému a přednášky o tom, že jako Javisti bychom neměli psát html kód a pokud ano, nepsat jej jak prasata. Chápu, souhlasím! Měl neuvěřitelný flow a těch 45 minut uteklo jak voda, dokázal bych tam sedět klidně až do večera – tohle mi něco dalo! Teď se však marně snažím najít nějaký jeho blog (blogspot mi hlásí 404), názvy které zmiňoval ani googlu nic neříkají (html5taglib, haiku), takže tu nemůžu dát linky. Ale aspoň jsem sehnal jeho mejl, tak uvidíme, jestli se s tím bude dát něco dělat, protože to bylo rozhodně nemálo zajímavé.

Další navštívenou přednáškou byla opakovaná What’s new in JavaEE 6 prezentovaná Alexis Moussine-Pouchkine, ale spíše jsem si během ní srovnával v hlavě Marcusova slova. Občas jsem ale procitl, abych zjistil, že se recyklují věci jako qualifiers (se kterými jsem shodou okolností neúspěšně zápasil minulý týden), že se ukazují onelinery oanotované asi deseti řádky a další šílenosti. Sečteno podtrženo – nula. A to jsem seděl na zemi, protože bylo plno.

Javistky nevypadají jako matfyzák
Javistky nevypadají jako matfyzák

OK, další v plánu mám „Vývoj a architektura java aplikace pro 10 mil. uživatelů“ prezentované Ladislavem Skokanem. Jednalo se o popis řešení online aplikace pro sčítání obyvatel. No opravdu se nezlobte, ale informace o tom, že to jede na web logicu, „tady jsme potom přidali ještě jeden server“, „čteme data z databáze, tak je vhodné cachovat“…k čemu tato prezentace byla? Možná k pláči. Takže se na mě, vážení pořadatelé, nezlobte, ale odcházím. Vypouštím Contexts and Dependency Injection i MDA platformy Paternoster (pokud je vůbec za tím MDA skryta Model Driven Architektura).

Na závěr ještě zamyšlení – proč jsou novinky prezentovány vývojářům, když ti v těžké většině nemohou mít na výběr použité technologie pražádný vliv? Jasně, pokud dělám vlastní projekt, rád si ozkouším mnoho věcí a novinek, ale pokud by se mělo jednat o nějaký long-term projekt – kdo by riskoval použití novinek z něčeho, co se mění dle měsíčních fází? Nehledě na to, že zadavatel si většinou vybere něco, co už je drahně let za horizontem a co dokáží jeho ajťáci spravovat? Slovy klasika: „srsly, wtf?“ Možná by byly do budoucna vhodnější nějaké detailně probrané case studies konkrétních implementací, případně workshopy, nebo reálné zkušenosti. Že by právě proto tolik frčely všechny ty hackathony a klasické konfery začínaly taky patřit do doby dinosaurů?

PS. Negativní vyznění nemá nic společného s tím, že jsem nedostal kabelku s letáky a reklamní flashdisk, ani fakt, že jsem se večer před konferou nepěkně sejmul.

Jak se dostat na zabezpečené služby státní správy?

Pod mírně bulvárním názvem tohoto blogpostu nehledejte žádný návod na hákování webů státních institucí. Pouze jsem se snažil vytvořit klienta (v Javě) pro komunikaci s webovými službami nalézajícími se na serveru, který je zajištěn certifikátem vydaným certifikační autoritou PostSignum a aby to nebylo tak jednoduché, tak uživatel je autentikován na základě osobního certifikátu. Každý slušný … Pokračovat ve čtení „Jak se dostat na zabezpečené služby státní správy?“

Pod mírně bulvárním názvem tohoto blogpostu nehledejte žádný návod na hákování webů státních institucí. Pouze jsem se snažil vytvořit klienta (v Javě) pro komunikaci s webovými službami nalézajícími se na serveru, který je zajištěn certifikátem vydaným certifikační autoritou PostSignum a aby to nebylo tak jednoduché, tak uživatel je autentikován na základě osobního certifikátu.

Každý slušný člověk začne nejprve googlením, kdy najde nejeden příklad navazování spojení pomocí https (řekněme HTTP over TLS), další googlení potom poodkryje další příklady, tentokrát jak použít klientský certifikát. Na tomto základě už je možné začít stavět, nejprve tedy metoda pro získání ssl socket factory, kterou použijeme pro kontrolu identity:

[code lang=“java“]
private SSLSocketFactory getFactory(File pKeyFile, String pKeyPassword) throws…{
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream keyInput = new FileInputStream(pKeyFile);

keyStore.load(keyInput, pKeyPassword.toCharArray());
keyInput.close();
keyManagerFactory.init(keyStore, pKeyPassword.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());

return context.getSocketFactory();
}
[/code]

Tato factory se předá do vytvářeného zabezpečeného spojení, kdy je tímto způsobem poskytnut údaj pro autentikaci uživatele na straně serveru. Tedy metoda vracející toto spojení:

[code lang=“java“]
public HttpsURLConnection getConnection() throws …{
URL url = new URL("https://server:844/");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();

con.setSSLSocketFactory(getFactory(new File("cert_sign.p12"), "heslo"));

return con;
}
[/code]

Teď je možné se pomocí zavolání connect() připojit, ale protože nejsou v úložišti důvěryhodných certifikátů vložené certifikátu serveru, snaha o připojení skončí s výjimkou:

[code]
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
[/code]

Nejprve jsem se snažil mezi důvěryhodné certifikáty importovat certifikát kořenové autority PostSignum pomocí nástroje keytool

[code lang=“shell“]
sudo keytool -import -alias gwc.cpost.cz -keystore /etc/java-6-sun/security/cacerts -file root.pem
[/code]

což však nevedlo nikam, potřeboval jsem konkrétní certifikáty konkrétního stroje a s tím mi pomohla utilitka InstallCert (zdrojový kód, takže je to důvěryhodné ;-)). Vytvořený soubor jssecacerts je vlastně původní cacerts s přidanými certifikáty požadovaného serveru, takže je možné jej nakopírovat na odpovídající místo, pomocí keytool -list se podívat, jestli je vše v pořádku a opět vyzkoušet spojení.

Spojuje se, ale to je tak celé, takže se teď zabývám následujícími odkazy:

MVC and Spring surf

One of things I missed in Spring Surf are Models and Controllers. I tried many ways to get them working, but still no useful solution. So I chose really simple way to do that – to define another dispatcher and to play with urlrewrite. In this post I’ll describe what I did and as a … Pokračovat ve čtení „MVC and Spring surf“

One of things I missed in Spring Surf are Models and Controllers. I tried many ways to get them working, but still no useful solution. So I chose really simple way to do that – to define another dispatcher and to play with urlrewrite. In this post I’ll describe what I did and as a little bonus you’ll find a breathtaking example 🙂 – YUI based Ajax whisperer.

Let’s start with empty Spring Surf skeleton:

project --topLevelPackage cz.shmoula.controllers
surf install
perform eclipse

Now add dispatcher – in web.xml we have to define new servlet with name controller, loaded as second and with url-pattern /app (default dispatcher is mapped to /service), which is filtered by urlrewrite.

<servlet>
  <servlet-name>controller</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>controller</servlet-name>
  <url-pattern>/app/*</url-pattern>
</servlet-mapping>

In next step we’ll need web application config – Spring names them as -servlet.xml prefixed with servlet name. So let’s create controller-servlet.xml in WEB-INF (in STS New/Spring bean configuration file) and add some useful stuff there: for first we want to use annotations for our controllers, so let’s add there two beans – DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter.

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

Then we need to define where are our controllers lying, so let’s define base package.

<context:component-scan base-package="cz.shmoula.controllers.controller" use-default-filters="false">
  <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" />
</context:component-scan>

Last thing is to tell, where will be our views and which suffix they use.

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/jsp/" />
  <property name="suffix" value=".jsp" />
</bean>

Okay, folks, that’s almost all! Now the interesting part: Writing the controller. Make a class in package we defined earlier. It should extend some AbstractController or another stuff, but it’s not necessary, we’ll simple it! 😉 Put a test method inside:

package cz.shmoula.controllers.controller;

@Controller
public class AutocompleteController{

  @RequestMapping(value = "/test")
  public String test(Model model){
    model.addAttribute("attribute", "Some sample string");
    return "test";
  }
}

That’s our controller. Now we need a view. Previously we defined parameters for view resolver and in controller we’re returning name of our model. Putted together result is: /WEB-INF/jsp/test.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Test page backed by controller</title>
  </head>
  <body>
    <h1>Hi, what we have there?</h1>
    <p>${attribute}</p>
  </body>
</html>

Last thing to do is to define some rules for urlrewrite. We’ll try to forward all /app/ requests to our dispatcher and anything else to Default Spring Dispatcher. That’s done by these rules (urlrewrite.xml):

<rule>
  <from>/app/(.*)</from>
  <to>/app/$1</to>
</rule>
<rule>
  <from>/</from>
  <to>/service/</to>
</rule>

Done? So let’s test it! Run it up and open browser at http://localhost:8080/controllers/app/test. Does it work? I hope so!

Test page
Test page

That was the first part – worst one, now came pure fun – some functionality. We want to implement some buzzlike thingy as Autocompletion is – whisperer. To keep it simple our model layer will be just a Collection with Strings, so let’s modify our controller with constructor:

private Collection<String> termList = new HashSet<String>();
public AutocompleteController() {
    termList.add("Prague");
    termList.add("Paris");
    termList.add("Poznan");
}

Now we need controller code – something returning some results. So at /autocomplete will be routine, which waits for „query“parameter with part of String, which tries to find in termList and return:

@RequestMapping(value = "/autocomplete")
public void autocomplete(HttpServletRequest httpRequest, Model model) {
    String query = httpRequest.getParameter("query");
    String response = "";

    if (query != null) {
        for (Iterator<String> i = termList.iterator(); i.hasNext();) {
            String term = i.next();
            if (term.startsWith(query))
                response += "n" + term;
        }
    }
    model.addAttribute("response", response);

}

Now we have to render our model through something, so add view /WEB-INF/jsp/autocomplete.jsp:

${response }

And now to add all that into widget. Let’s extend calendar widget in /WEB-INF/webscripts/calendar – first add styles and YUI scripts into calendar.get.head.ftl:

<link type="text/css" rel="stylesheet" href="http://yui.yahooapis.com/2.8.2r1/build/autocomplete/assets/skins/sam/autocomplete.css">
<script src="http://yui.yahooapis.com/2.8.2r1/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script src="http://yui.yahooapis.com/2.8.2r1/build/datasource/datasource-min.js"></script>
<script src="http://yui.yahooapis.com/2.8.2r1/build/connection/connection-min.js"></script>
<script src="http://yui.yahooapis.com/2.8.2r1/build/autocomplete/autocomplete-min.js"></script>

<style type="text/css">
    #myAutoComplete {
        width:25em;
        padding-bottom:2em;
    }
</style>

The last step is to create div and put a script into calendar.get.html.ftl:

<div>
    <label for="myInput">Autocomplete:</label>
    <div id="myAutoComplete">
        <input id="myInput" type="text">
        <div id="myContainer"></div>
    </div>
</div>
<script type="text/javascript">
  YAHOO.example.BasicRemote = function() {
    var oDS = new YAHOO.util.XHRDataSource("/controllers/app/autocomplete");
    oDS.responseType = YAHOO.util.XHRDataSource.TYPE_TEXT;
    oDS.responseSchema = {
      recordDelim: "n",
      fieldDelim: "t"
    };
    oDS.maxCacheEntries = 5;
    var oAC = new YAHOO.widget.AutoComplete("myInput", "myContainer", oDS);
    return {
      oDS: oDS,
      oAC: oAC
    };
  }();
</script>

And that should be all, now let’s test it, if it works! So open http://localhost:8080/controllers/calendar and voila…

Working autocompletion
Working autocompletion

Ok, that’s all for this post, looks like it works! So you can download backup of this code somewhere around here and enjoy it on your own devbox. Keep looking forward for next stuff, maybe using facebook login with Spring social, who knows ;-).

JSP based components in Spring Surf

In my last blogpost we got Java backed webscripts working, now let’s try something completely different: defining page snippet as a component in .JSP. Just let’s continue with our last code, which is possible to download, but it’s not necessary, it’s possible to build it all on green meadow (aka after project in roo is … Pokračovat ve čtení „JSP based components in Spring Surf“

In my last blogpost we got Java backed webscripts working, now let’s try something completely different: defining page snippet as a component in .JSP. Just let’s continue with our last code, which is possible to download, but it’s not necessary, it’s possible to build it all on green meadow (aka after project in roo is created and surf installed).

First thing to do is to add dependency for jstl into Maven’s pom.xml and then update maven dependencies and refresh our project in Eclipse.

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>com.springsource.javax.servlet.jsp.jstl</artifactId>
    <version>1.2.0</version>
</dependency>

Now you can get glue on Spring forums, or trust me and create new component type with JSP Renderer: it’s needed to create new directory – /WEB-INF/classes/surf/site/component-types and inside new component type configuration – test.xml.

<?xml version="1.0" encoding="UTF-8"?>
<component-type>
    <id>test</id>
    <title>Test Component Type</title>
    <description>Test Component Type</description>

    <processor mode="view">
        <id>jsp</id>
        <jsp-path></jsp-path>
    </processor>
</component-type>

Jsp-path is at this time undefined, because we haven’t created any page yet. So let’s do something with that. We need to create new template and new template instance:

roo> surf template create --path test
Created SRC_MAIN_WEBAPP/WEB-INF/templates/test.ftl
roo> surf template instance create --id test --path templates --template test
Created SRC_MAIN_WEBAPP/WEB-INF/templates/test.xml

At this time we have Freemarker template (test.ftl) and template instance (test.xml) inside directory /WEB-INF/templates. We need to edit those files. First let’s add following code into test.ftl. There are four regions defined – three of them inside template scope (already defined by installation of Surf addon) and one with page scope, which we’ll define and bind later.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>${page.title}</title>
  </head>

  <body>
    <div id="page">
      <div id="header">
        <@region id="header" scope="template" />
      </div>
      <div id="horznav">
        <@region id="horznav" scope="template" />
      </div>
      <div id="content">
        <@region id="content" scope="page" />
      </div>
      <div id="footer">
        <@region id="footer" scope="template" />
      </div>
    </div>
  </body>
</html>

Following code (template instance) is definition of components in template scope and is also located in templates directory: test.xml.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<template-instance>
  <title>test</title>
  <description>Instance of test</description>
  <template-type>test</template-type>
  <components>
    <component>
      <region-id>header</region-id>
      <url>/company/header</url>
    </component>
    <component>
      <region-id>horznav</region-id>
      <url>/navigation/horizontal</url>
    </component>
    <component>
      <region-id>footer</region-id>
      <url>/company/footer</url>
    </component>
  </components>
</template-instance>

Now we can create new page based on previously defined template-instance and add link to our new page to horizontal bar. For those actions we can use roo:

roo> surf page create --id test --path pagestest --templateInstance test
Created SRC_MAIN_WEBAPP/WEB-INF/pages/test
Created SRC_MAIN_WEBAPP/WEB-INF/pages/test/test.xml

roo> surf page association create --sourceId home --destId test
Managed SRC_MAIN_WEBAPP/WEB-INF/pages/home/home.xml

As written in roo output, directory test inside pages is created and test.xml within. This file is page configuration and we have to define our content for region defined in template. But not necessary, it’s good idea to check our work now. So let’s try to Run it on server… It’s ugly, but it works! 🙂

First try
First try

That’s cool, but our aim is to create working .jsp page. How to do that? What about simply create that page? 🙂 So let’s create test.jsp inside /WEB-INF/pages/test and fill it with some simple code:

<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt'%>

<%@ page import="java.util.*"  %>
<%@ page contentType="text/html;charset=UTF-8" language="java"%>

<h1>Test jsp</h1>

<%
  String someText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

  List<String> l = new ArrayList<String>();
  l.add("Maecenas iaculis odio id eros fermentum non tempus erat interdum.");
  l.add("Sed mi orci, dignissim vitae cursus hendrerit, congue sed odio. ");
  l.add("Vivamus quam diam, dapibus sit amet placerat a, tempus at magna.");

  session.setAttribute("someText", someText);
  session.setAttribute("l", l);
%>

<p>${someText }</p>

<c:forEach var="x" items="${l }" >
    <p>${x}</p>
</c:forEach>

That’s our page. Now we need to connect it with previously created component type – /WEB-INF/classes/surf/site/component-types/test.xml. In time of creation we omit jsp-path, so fill it up now:

<jsp-path>/WEB-INF/pages/test/test.jsp</jsp-path>

Last thing to do is to put our shiny new component-type into page. In template we defined region, which is filled in page scope. That’s that components section in page config – /WEB-INF/pages/test/test.xml. It’s good idea to add some title and some styling like border and background thanks to chrome element:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<page>
  <id>test</id>
  <title>test</title>
  <template-instance>test</template-instance>
  <authentication>none</authentication>
  <components>
    <component>
      <region-id>content</region-id>
      <component-type-id>test</component-type-id>
      <chrome>box</chrome>
      <title>JSP inside</title>
    </component>
  </components>
</page>

After rebuild and redeploy we have our jsp component working, as you can see at http://localhost:8080/webscripts/test. Congratulations, good work!

Final application look
Final application look

Ah, in case you got lost, there is package with working sourcecode for this whole example.

Freemarker templates and java backed webscripts

Wondering about output to freemarker template from java backed webscript in Spring Surf? You’re on the right place, it’s simple so I’ll try to describe it on a few lines. For first I suppose some prerequisites you have: you have Spring Roo and (or) Springsource Tool Suite (or Eclipse with plugin), you have Spring surf … Pokračovat ve čtení „Freemarker templates and java backed webscripts“

Wondering about output to freemarker template from java backed webscript in Spring Surf? You’re on the right place, it’s simple so I’ll try to describe it on a few lines. For first I suppose some prerequisites you have:

Ok, let’s get it done quickly! Create new directory, for example webscripts. Go into it, fire up roo, create a new project, install surf extension into it and create an Eclipse project:

project --topLevelPackage cz.shmoula.webscripts
surf install
perform eclipse

Now you should have base skeleton of our future app (you can also download it here) and you can import it into SpringSource Tool Suite.

Webscripts are located in src/main/webapp/WEB-INF/webscripts folder, so open that folder and create two files: example.get.html.ftl (template) and example.get.desc.xml (description).

<p>logged user: ${userId}</p>
<webscript>
      <shortname>Example</shortname>
      <description>Sample java backed webscript</description>
      <url>/example</url>
</webscript>

Now we have to create our java source code. It’s not bad idea to put webscripts to their own package, for example webscript. In that package create a new class, which extends org.springframework.extensions.webscripts.AbstractWebScript – Example. By doing that we have to implement an execute method, which is called, when webscript is executed:

@Override
public void execute(WebScriptRequest req, WebScriptResponse res)
    throws IOException {
}

Let’s fill that method. We need a model map, which holds values as pair (String)key – (Object)value. For our desired function we also need to get HttpServletRequest:

Map<String, Object> model = new HashMap<String, Object>();
HttpServletRequest httpRequest = ServletUtil.getRequest();

Now to fill up model (aka our function). Let’s find out if there is logged in user and if so, write out it’s userId:

if(AuthenticationUtil.isAuthenticated(httpRequest)){
      model.put("userId", AuthenticationUtil.getUserId(httpRequest));
}else{
      model.put("userId", "guest");
}

Final step is to put out our model. We need to get writer and renderTemplate, which we specified by its path (and also flush and close our writer):

Writer writer = res.getWriter();
String templatePath = "webscripts/example.get.html.ftl";
renderTemplate(templatePath, createTemplateParameters(req, res, model), writer);

writer.flush();
writer.close();

Last thing we have to do is to let Surf know about our shiny new webscript. You can add new bean directly inside applicationContext, but it’s not bad idea to keep them separately. So in src/main/webapp/WEB-INF/config create new Spring Bean Definition file – custom-webscripts-config.xml and put inside new bean definition:

<bean id="webscript.webscripts.example.get" class="cz.shmoula.webscript.Example" parent="webscript"/>

Now we have to import that new config: in the same directory is surf-config.xml file, so let’s add there new import:

<import resource="custom-webscripts-config.xml"/>

At this time we can run our project and visit http://localhost:8080/webscripts/example, which shows following page:

Image and video hosting by TinyPic

It’s possible to login (if you have set up user factory) as an Alfresco user and after that another userId is shown. I’m planning to write new blogpost about custom user factory and stuff like that, so be patient please. Finally, you can download source code for this example at this link. Structure of project is shown at following screenshot (note that red dots – those are modified files):

Image and video hosting by TinyPic

Finally, try to experiment with some examples from Alfresco wiki and look forward to next blogpost.