čtvrtek 29. prosince 2005

2006

Den se Dnem se sešel a do konce roku 2005 zbývá pár hodin. Nemá velkého významu obracet se zpět, ale přece jenom vězte, že Dagblog načal čtvrtý rok svojí existence. Je to už drahnou dobu, co jsem sedmadvacátého prosince roku dvatisícedva psal první příspěvek. Za tu dobu jsem se snažil s větším či menším úspěchem obohacovat sebe i Vás, pokud se mi to alespoň trochu povedlo jsem za to nesmírně rád.

V roce 2006 nás čeká mnoho novinek a prohloubení stávajících trendů. V oblasti Javy bych rád upozornil na dva takové milníky. V první polovině roku se začnou objevovat finální implementace specifikace J2EE 1.5 a doufejme, že v té druhé polovině roku se objeví první beta verze Javy 6.0 s kódovým označením Mustang, na kterou jsou upřeny oči všech vývojářů desktopových aplikací.

V oblasti webových/internetových aplikací nás čeká prohloubení stávajícího trendu využití AJAX konceptu a celkové přiblížení k RIA. Troufám si tvrdit, že budoucí vývoj webových aplikací bude směřovat k postupnému opouštění klasického request based a přechodu ke komponentně-událostnímu modelu. To umožní vývoj nástrojů vhodných pro Rapid Application Development, Java Server Faces a Java Studion Creator budiž toho důkazem.

I v následujícím roce se objeví testy, studie a články, ve kterých bude Java srovnávána s ostatními technologiemi. Používám schválně abstraktního slova Java, protože co je to dnes Java? Je to stabilní, ověřená a dále se vyvíjející platforma, která je s úspěchem používána v mnoha segmentech IT, mobilním telefonem počínaje a lunárním vozítkem NASA konče. Berte proto všechny kritické i oslavné informace tak nějak s rezervou, protože nic není černobílé.

Na závěr bych Vám všem popřál hodně osobních a profesních úspěchů, prostě a jednoduše buďte zdraví a ať se daří. Díky a zůstaňte naladěni na stejnou vlnovou délku...

čtvrtek 22. prosince 2005

Pro koho tu jsou personální agentury

Jedna z nesporných výhod blogu je ta, že je autor jaksi více na očích. Občas se stane, že mě někdo osloví s nabídkou práce. To nepovažuji za něco špatného, ostatně vždycky se tak děje velice korektně. Občas se stane, že na člověka zacílí personální agentura.

Pokud člověk hledá práci, pak může personální agentura představovat docela dobrého prostředníka. Pokud člověk práci výslovně nehledá, tak by očekával větší než malé množství pokory, s kterou se na něj agentura bude obracet. Ostatně to vyplývá z prostého vztahu já práci nehledám:my vám jí přesto chceme zprostředkovat.

Nevím jestli je tento fakt dostatečně známý, ale personální agentura mívá výdělek kolem trojnásobku nástupního platu klienta. Personální agentura vám zprostředkuje pohovor u firmy X. Vy na pohovoru uspějete a do firmy X nastoupíte se smluvním platem 50000,- Kč a personální agentura dostane od firmy X 150000,- Kč. To je docela dobrý business, nezdá se vám?

A právě proto bych očekával, že když práci výslovně nehledám, tak si mne bude personální agentura velebit a bude se mnou jednat taktně. Bohužel jsem zjistil, že pro některé agentury tato premisa neplatí. Ba co víc nabyl jsem neochvějného dojmu, že některé agentury mají tu utkvělou představu, že je tu člověk proto, aby se účastnil pohovorů s těmito agenturami.

Mě to přijde trochu na hlavu postavené a očekával bych, že nikoliv personální agentura, ale já osobně si nejdříve vyberu z portfolia nějakých nabídek. Následně se rozhodnu, jestli mám vůbec zájem na nějakou z těch nabídek reflektovat a pakliže ano, je možné se bavit o formě pohovoru.

Ad absurdum dovedla jednání, alespoň z mého pohledu, jedna nejmenovaná personální agentura. Fakt, že mě její head hunter spamoval přibližně každé tři měsíce jsem překousnul. Vrchol jednání těchto head hunters (toto označení používám úmyslně) nastal ve chvíli, kdy mi v pondělí odpoledne sdělili, že mám přijít na pohovor v úterý nebo ve středu a dokonce si prý mohu vybrat. Naštěstí asi nerozchodili mojí asertivní odpověď, jejíž pointa byla to byl vtip? Tak takhle holenkové rozhodně ne, to já si budu vybírat!.

Moje doporučení pro jednání s personální agenturou je takové.

Vždcky a za jakýchkoliv okolností, ať už hledáte prácí nebo jste osloveni, jednejte s personální agenturou asertivně. Nejste tu vy pro ní, ale ona pro vás. Pokud neprojeví agentura dostatek pokory a nebude se vám snažit dostatečně vyjít vstříc, dejte od ní ruce pryč. A vůbec se ničeho neboje, na ocet nezůstanete, protože stále platí slavná věta business je business...

Co možná nevíte o označení head hunters

Kromě toho, že se tak "hanlivě" nazývají personální agentury, tak si název Head Hunters, dobrovolně zvolili nechvalně známí rowdies londýnské Chelsea a nebo jednotky US Army 1. jízdní (aeromobilní) kavalerie ve Vietnamu.

pátek 9. prosince 2005

VyVoleným pro test použitelnosti

Včera jsem si poprvé vyzkoušel jednak Java Studio Creator 2 a druhak jaké je to být pokusným uživatelem při testu použitelnosti pro tento násroj.

Průběh testování

Seděl jsem v nevelké místnosti s PC, kamerou a interkomem. Všechno, co jsem dělal, se zároveň nahrávalo a přenášelo do řídící místnosti, odkud mě občas korigovali. Vlastní testování probíhalo cca. jednu hodinu a plnil jsem jednotlivé úkoly, které jsem dostal v elektronické podobě. Příklad úkolu: Právě jste nastoupil ve firmě WebApp a máte za úkol seznámit se s Java Studio Creator, věnujte deset minut prohlídce IDE.

Důležitým faktorem celého testu použitelnosti bylo to, že jsem se měl snažit přemýšlet nahlas. Což mi údajně nedělalo velký problém. Dokonce jsem to občas okořenil radostnými výkřiky, když se mi něco povedlo ...jak jsi mocný apod. Ono "myšlení nahlas" bude důležité při vyhodnocování celého testu. Vzhledem k tomu, že mi přes rameno koukala kameru a v místnosti byl mikrofon, připadal jsem si jako účastník Sun reality show.

Po hodině plnění úkolů následoval zhruba půl hodinový rozhovor, kdy jsem odpovídal na připravené otázky např. jak dlouhý vám připadal startup, chovalo se prostředí svižně apod. Samozřejmě jsme se nevyhnuli otázkám na porovnání s IDE Eclipse. Docela mě pobavilo, když mi předávali jako suvenýr tričko se slovy ...je trošku kontroverzní.

Po rozbalení na mě čekalo tričko na přední straně s nápisem Are you still working in the dark? a vyobrazením jednotlivých fází zatmění slunce. Na druhé straně bylo monster slunce s nápisem NetBeans a www adresou. Prostě je vidět, že Eclipse asi leží v žaludku Sunu hodně hluboko...

Java Studio Creator 2

Java Studio Creator 2 (volně ke stažení v Early access) je klasické RAD (Rapid Application Development) IDE pro vývoj webových aplikací založených na JSF. Musím říci, že pokud je cílem Sunu přilákat vývojáře z jiných platforem, pak je tohle správná cesta. Opravdu je to pomyslná rukavice hozená na zem. Neříkám to pro nic za nic a rozhodně to není účelová reklama.

Připadal jsem si jako, kdybych měl v ruce nástroj, který dělal Microsoft. Tím myslím především komfort pro vývojáře. V podstatě není problém, posadit před IDE vývojáře s minimální zkušeností s Javou či JSF nebo JSP a může směle začít. Co se mi asi nejvíce líbilo, byl GUI návrhář, který odpovídá klasickému návrháři pro tvorbu desktopových aplikací.

Každá stránka je standardně otevřena v design módu a jedním kliknutím je možné se přepnout do javovského kódu obslužné backing beanu či vlastní JSP stránky s JSF tagy. Vygenerovaný kód mi přišel celkem přehledný. Suma sumárum RAD nástroj, který jsem ještě v Jave neviděl. Zní jako pravá nefalšovaná reklama, ale opravdu jsem byl velice spokojený jeho používání.

Samozřejmě je otázkou jak by Java Studio Creator 2 dopadl při nějakém dlouhodobějším testu a případně při reálném nasazení. Ještě bych zmínil první verzi Java Studio Creator, která údajně nebyla úplně vychytaná. Pokud si tedy chcete Java Studio Creator otestovat rozhodně šáhněte po verzi dva.

Srovnání s Eclipse

Chtě nechtě jsem byl konfrontován, jak jsem již naznačil, s porovnáním proti Eclipse. Předesílám, že porovnání Eclipse a Java Studio Creator dopadá minimálně jednu nohu. Java Studio Creator je určen přímo pro vývoj webových aplikací se zaměřením na JSF a co největším důrazem na povahu RAD. Tomu je celé IDE uzpůsobeno. Oproti tomu Eclipse je obecná vývojová platforma s výbornou podporou pro psaní vlastního kódu, synchronizačními nástroji atd.

Porovnat Eclipse a Java Studio Creator prostě nejde. Musel by se vzít konkrétní plugin (perspektiva) s podporou JSF a pak by bylo možné porovnávat. Výhoda Java Studio Creator je právě v tom, že vývojář se nemusí starat o to jaký plugin kde sehnat, jak nakonfigurovat apod. Tohle je podle mě obrovská výhoda Java Studio Creatoru kdy dostanete IDE, které je určené na to co je předmětem vašeho vývoje.

Závěr

Mohu všem doporučit ať si Java Studio Creator 2 vyzkouší, mě osobně to obohatilo a utvrdilo v názoru, že i pro Javu se dá udělat IDE, které může konkurovat nástrojům, ve kterých měl navrch DOT.NET. Podle kuloárních informací, které se ke mě dostaly, to vypadá, že by Sun mohl nějakým způsobem v budoucnu podpořit českou vývojářskou komunitu. Tak uvidíme, budeme doufat a necháme se překvapit...

úterý 6. prosince 2005

Testy použitelnosti produktu Java Studio Creator v Praze

Pražská pobočka firmy Sun organizuje testy použitelnosti, nyní již open source nástroje, Java Studio Creator viz pozvánka. Přesto, že testy se konají již tento čtvrtek a pátek tak už mají naplněné stavy. Soudím tak podle toho, že když jsem zkoušel přihlásit sebe a dva kolegy, tak mi napsali že mají plné stavy, nicméně že se mojí maličkostí počítají...

Pokud se chcete přesto zúčastnit, tak bych osobně neházel flintu do žita neboť hledají vývojáře s různých cílových skupin.

  1. Vyvojari webovych aplikaci majici zkusenost s JSP, Javou a databazemi (dalsi pripadne zkusenosti s Java Server Faces, WEB services, Portlets jsou vitany)
  2. Vyvojari, kteri maji zkusenosti s vyvojem webovych aplikaci na platforme .NET
  3. Ostatni vyvojari, kteri vyvyjeji webove aplikace na jine platforme a maji zajem se seznamit s novym nastrojem

Samozřejmě jsou to jenom moje spekulace, ale vývojářů ze skupiny dva a tři by nemuselo být tolik. Takže pokud Vás to zajímá, můžete se zkusit přihlásit. Dle vyjádření Dušana Pavlici bude pražská pobočka Sunu pořádat tyto testy i pro jiné produkty např. Netbeans, Netbeans Mobility, Java Studio Enterprise, Sun Studio.

pátek 2. prosince 2005

Odešel ten jenž změnil myšlení mnoha vývojářů

Zpráva že po dlouhé nemoci zemřel John Vlissides nezasáhla jenom mě. Možná Vám stejně jako spoustě dalších změnil John Vlissides profesní život aniž si to vůbec uvědomujete. Pokud jste někdy studovali či používali návrhové vzory, tak je více než pravděpodobné, že jste tak činili na základě jeho práce. Snad jen dodám, že byl členem slavného uskupení GOF (Gang of Four).

pátek 25. listopadu 2005

Java včera, dnes a zítra

Dnes bych chtěl pár řádek věnovat Jave 5.0. Je to až s podivem, jak zpátečnický jsem si připadal, když jsem se na těchto stránkách skepticky rozepisoval o přechodu na Javu 5.0 viz Migrace na Javu 5.0, realita nebo utopie? (5.10.2004) a Přejít na Javu 5.0, ANO či NE? (30.5.2005). Od té doby už uběhlo hodně času a já jsem si ten přechod mohl prodělat na vlastní kůži.

Nyní už si tak zpátečnický nepřipadám a dokonce si troufám tvrdit, s odstupem času, že to byl docela racionální pohled. Tou největší změnou, kterou Java prodělala, bylo zavedení generických typů.

Ach jak povrchní byly všichni ti pisálkové, včetně mě samotného, jenž referovali o zavedení generik. Profláknutý příklad s generickou kolekcí budiž toho důkazem. Generiky rozšiřují sémantiku jazyka do takové míry, že pokud si je nenastudujete, budete si pravděpodobně připadat jako Alenka v říši divů. A věřte mi, že ne jenom při čtení zdrojového kódu.

Všechny ostatní vlastnosti, které pětková řada představila, jsou jenom kosmetickým vylepšením. Generiky změnily nebo posunuly jazyk úplně jinam. Jestliže budete chtít pochopit a používat generiky v plné síle, nebude Vám k tomu možná stačit ani fenomenální Generics FAQ (na papíře to děla 300 stránek) od Angeliky Langer.

Kromě toho, že budete muset načerpat mnoho pojmů jako raw type, wildcard, wildcard capture, type erasure, type argument inference, generická třída, generická metoda (mezi těmi je diametrální rozdíl). Také budete muset například pochopit, že je generická třída a generická třída konkrétního typu, a že mezi třídami konkrétních generických typů není dědičnost (jsou to nekompatibilní typy).

Podobných pastí a pastiček, kterými si budete muset prolézt, není zrovna málo. Možná to dojde tak daleko, že abyste pochopili a nebo realizovali použití generiky, bude se muset vžít do role kompilátoru. Apropo, když jsem u toho kompilátoru, jak si myslíte, že se zachová v následujícím případě, zkompiluje nebo nezkompiluje?


public class Foo {
    
  public static <T> T doSomething(){
   return doSomethingII();
  }
    
   
  public static <U> U doSomethingII(){
   return (U) new Object();
  } 
}

Pokud si myslíte, že zkompiluje, tak máte pravdu. Vy, co si myslíte, že to nezkompiluje, máte ovšem také pravdu! Záleží na tom, jaký kompilátor použijete. Pokud použijete kompilátor ze Sun SDK (testováno na verzi 1.5.0_04 a 1.5.0_05) tak máte smůlu. Pokud použijete Jikes kompilátor máte vyhráno (používá jej například IDE Eclipse nebo Tomcat).

Mimochodem, víte jak ten kód upravit tak, aby jej "baštil" i kompilátor ze Sun SDK? Je povelená úprava pouze na úrovni generik.

Tak taková je Java dnes. Každý nechť si položí otázku, jestli opravdu potřebuje a využije vlastnosti pětkové verze a jestli to pro něj nebude v důsledku spíše kotnraproduktivní. Když jsem nad tímhle zamyšlením dumal, inspirací mi byl pohled Eda Burnetta prezentovaný v článku Better, faster, stupider Java

Mylar is a plug-in for Eclipse and, being written from scratch, the developers decided to use all the newest features of JSE 5. One little problem, not everybody could use JSE 5. For example there is no JSE 5 support on RedHat Linux with GCJ. Oh, there probably will be someday, and maybe there are workarounds with retroweaver or something but that's not the point.

Language guys love to tweak. I know, because I'm a language guy myself. I used to work on compilers, code generators, libraries, and debuggers. We were always adding new stuff, new commands, special keywords, etc. Did our users thank us for it? Maybe the one or two that wanted the new things, but the vast majority would just groan when a new release came out. What will this break now? Will I have to upgrade? Will I have to use somebody else's code that requires this new thing before I'm ready? Has it been ported to all the machines I need to run on? Boring, I know, but very practical and important issues.

A jaká bude Java zítřejška?

středa 23. listopadu 2005

Simple protection for web forms with Jcaptcha and Spring MVC

Time to time we need web forms protection before robot submision for example spammers, DOS attack and so on. The saftest and commonly used way how distinguish between robot and human is CAPTCHA. CAPTCHA is acronym for Completely Automated Public Test to tell Computers and Humans Apart.

In context web form is CAPTCHA presented as pair which contain dynamicly generated picture (image challenge) and input box. Befeore each submit of form user has to retype text from picture to input box. This text is validated on server side and if is correct form submission continue otherwise original form is returned.

In Java world exists open source CAPTCHA solution be called Jcaptcha. Jcaptcha will be very easly integrated to any web application and has a lot of prearranged modules e.g. for Struts or Servlet filter. In this article we show how to integrated Jcaptcha with Spring MVC.

What we need?

At first, dynamicly generate CAPTCHA image and second, control user retyped text during form submission. We can use Jcaptcha Base module for this. Base module aims to provide base components to build a specialized module.

The heart of JCaptcha is CaptchaService or more precisely ImageCaptchaService and their specialized implementation. This interface defines two main method getImageChallengeForID and validateResponseForID.

  • getImageChallengeForID(String ID) - method to retrive the image challenge corresponding to the given ticket.
  • validateResponseForID(String ID, Object response) - method to validate a response to the image challenge corresponding to the given ticket.

We get session id as ticket (ID) that will identify the generated captcha. Session id is unique for client and automaticly is sending by browser with each request. We needn`t stress with generating unique number a handling new parameter.

Image genarating will be wrapped to controller from Spring MVC point of view.

public class JCaptchaController implements Controller, InitializingBean{
  private ImageCaptchaService captchaService;

  /**
   @see org.springframework.web.servlet.mvc.Controller#handleRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
   */
  public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse responsethrows Exception {
        byte[] captchaChallengeAsJpeg = null;
        // the output stream to render the captcha image as jpeg into
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        
        // get the session id that will identify the generated captcha. 
        //the same id must be used to validate the response, the session id is a good candidate!
        String captchaId = request.getSession().getId();
        
        // call the ImageCaptchaService getChallenge method
        BufferedImage challenge =
                        captchaService.getImageChallengeForID(captchaId,request.getLocale());
        
        // a jpeg encoder
        JPEGImageEncoder jpegEncoder =
                        JPEGCodec.createJPEGEncoder(jpegOutputStream);
        jpegEncoder.encode(challenge);
        

        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();

        // flush it in the response
        response.setHeader("Cache-Control""no-store");
        response.setHeader("Pragma""no-cache");
        response.setDateHeader("Expires"0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream =
        response.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
        return null;
  }

  /**
   * Set captcha service
   @param captchaService The captchaService to set.
   */
  public void setCaptchaService(ImageCaptchaService captchaService) {
        this.captchaService = captchaService;        
  }  
  
  /**
   @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
   */
  public void afterPropertiesSet() throws Exception {
        if(captchaService == null){
          throw new RuntimeException("Image captcha service wasn`t set!");
        }
  }
}
Java2html

As you can see, this is classic controller with direct writing to response. It is possible to set any type of ImageCaptchaService implementation through setCaptchaService method. Now we need integrate captcha validation. The good choice is extends SimpleFormController from Spring and override onBindAndValidate method.

This method delegates call to new method validateCaptcha. validateCaptcha is responsible for validation. If is captcha response invalid, new ObjectError is added to validation errors holder and form submission is cancelled.

public class ProtectedFormController extends SimpleFormController {
  /**
   * Default paramter name for CAPTCHA response in <code>{@link HttpServletRequest}</code>
   */
  private static final String DEFAULT_CAPTCHA_RESPONSE_PARAMETER_NAME = "j_captcha_response";
  
  protected ImageCaptchaService captchaService;
  protected String captchaResponseParameterName = DEFAULT_CAPTCHA_RESPONSE_PARAMETER_NAME;
        
  /**
   * Delegates request to CAPTCHA validation, subclasses which overrides this 
   * method must manually call <code>{@link #validateCaptcha(HttpServletRequest, BindException)}</code>
   * or explicitly call super method.
   
   @see #validateCaptcha(HttpServletRequest, BindException)
   @see org.springframework.web.servlet.mvc.BaseCommandController#onBindAndValidate(javax.servlet.http.HttpServletRequest, java.lang.Object, org.springframework.validation.BindException)
   */
  @Override
  protected void onBindAndValidate(HttpServletRequest request, Object command, BindException errorsthrows Exception {        
        validateCaptcha(request, errors);
  }
  
  /**
   * Validate CAPTCHA response, if response isn`t valid creates new error object 
   * and put him to errors holder.
   
   @param request current servlet request
   @param errors errors holder
   */
  protected void validateCaptcha(HttpServletRequest request, BindException errors){
        boolean isResponseCorrect = false;
        
        //remenber that we need an id to validate!
        String captchaId = request.getSession().getId();
        //retrieve the response
        String response = request.getParameter(captchaResponseParameterName);
        //validate response
        try {          
          if(response != null){
                isResponseCorrect =
                  captchaService.validateResponseForID(captchaId, response);
          }
        catch (CaptchaServiceException e) {
                //should not happen, may be thrown if the id is not valid          
        }
        
        if(!isResponseCorrect){
          //prepare object error, captcha response isn`t valid
                  String objectName = "Captcha";
          String[] codes = {"invalid"};
          Object[] arguments = {};
          String defaultMessage = "Wrong cotrol text!";
          ObjectError oe = new ObjectError(objectName, codes, arguments, defaultMessage);
          errors.addError(oe);
        }                 
  }

  /**
   * Set captcha service
   @param captchaService the captchaService to set.
   */
  public void setCaptchaService(ImageCaptchaService captchaService) {
        this.captchaService = captchaService;
  }

  /**
   * Set paramter name for CAPTCHA response in <code>{@link HttpServletRequest}</code>
   @param captchaResponseParameterName the captchaResponseParameterName to set.
   */
  public void setCaptchaResponseParameterName(String captchaResponseParameterName) {
        this.captchaResponseParameterName = captchaResponseParameterName;
  }
}
Java2html

Now we are ready to use Spring and Jcaptcha. I choose sending comment for usage demonstration. Comment is represent as JavaBean and form controller is subclass of ProtectedFormController that has captcha validation.

public class Comment {
  private String email;
  private String subject;
  private String body;
  
  //Getters and Setters
}
Java2html

public class NewCommentForm extends ProtectedFormController {
  
  /**
   @see org.springframework.web.servlet.mvc.SimpleFormController#doSubmitAction(java.lang.Object)
   */
   @Override
    protected void doSubmitAction(Object commandthrows Exception {
        Comment comment = (Commentcommand;
        //do something with new comment for example save to database.
    }   
}
Java2html

Both controller and other stuff are configured in *-servlet.xml.

 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> 
 <bean id="formController" class="cz.sweb.pichlik.springtutorial.captcha.NewCommentForm">     
     <property name="captchaService"><ref bean="captchaService"/></property>
     <property name="commandClass"><value>cz.sweb.pichlik.springtutorial.captcha.Comment</value></property>
     <property name="formView"><value>form</value></property>
  <property name="successView"><value>submit</value></property>
  <property name="commandName"><value>comment</value></property>
    </bean>   
    
    <!-- This controller generates CAPTCHA image -->
    <bean id="captchaController" class="cz.sweb.pichlik.springtutorial.captcha.JCaptchaController">
     <property name="captchaService"><ref bean="captchaService"/></property>
    </bean> 
       
   <bean id="simpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">    
  <property name="mappings">
   <props>    
    <prop key="/newcomment.htm">formController</prop>
    <prop key="/captcha.htm">captchaController</prop>  
   </props>
  </property>
 </bean>
  
 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property>
        <property name="prefix"><value>/WEB-INF/jsp/</value></property>
        <property name="suffix"><value>.jsp</value></property>
    </bean>
</beans>
 

Application context configuration contains only captchaService bean. This bean is configured as singleton and as concrete captcha service implementation is selected default Jcaptcha class DefaultManageableImageCaptchaService>.


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> 
 <!-- CAPTCHA SERVICE DEFINITION -->
 <bean id="captchaService" 
  class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService" 
  singleton="true"/>
</beans>

HTML code is placed in form.jsp. You can notice how is JCaptchaController called by URL in src attribute of img element. forEach loop print any errors occured during validation (including captcha invalid response text).


<%@ page session="true" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<html>
 <head>
  <title>New comment</title>
 </head>
 <body>
  <form method="post" action="newcomment.htm">
  <spring:bind path="comment">
   <ul>
    <c:forEach items="${status.errorMessages}" var="errorMessage">
     <li style="color:red"><c:out value="${errorMessage}"/></li>
    </font>   
   </c:forEach>
   </ul>
   <table> 
    <tr>
     <td><label>Email</label></td><td><input type="text" name="email" value="<c:out value="${comment.email}"/>"/></td>
    </tr> 
    <tr>
     <td><label>Subject</label></td><td><input type="text" name="subject" value="<c:out value="${comment.subject}"/>"/></td>
    </tr>
    <tr>
     <td><label>Body</label></td><td><textarea name="body" cols="15" rows="5"><c:out value="${comment.body}"/></textarea></td>
    </tr>
    <tr>
     <td><label>Control text</label></td><td><input type="text" name="j_captcha_response" /></td> 
    </tr>
    <tr>
     <td colspan="2"><img src="captcha.htm" /></td>
    </tr>
    <tr>
     <td colspan="2" align="center"><input type="submit" value="submit" /></td>
    </tr>       
   </table>
   </spring:bind>
  </form>  
 </body>
</html>

New form

Valid submission

Invalid submission

Download source code (80 KB) or source code and libraries (3,2 MB)

čtvrtek 10. listopadu 2005

Java Studio Enterprise 8 a Java Studio Creator volně ke stažení

Sun se rozhodl pro členy Sun Developer Network (zkráceně SDN) zdarma uvolnit vývojová prostředí Java Studio Creator a Java Studio Enterprise 8.

JSE8 is their newest development environment for Java Enterprise Edition, and features UML and mobility functionality. Both Java Studio Creator and Java Studio Enterprise are built off of the Netbeans codebase. Java Studio Creator is a tool to help create web applications using JSF; Java Studio Enterprise contains tools aimed at the entire Java Enterprise Edition stack, and has plugins for such APIs as the Portlet API, data collection APIs, and more.

Členství v SDN není placené, takže pokud chcete tyto dva nástroje otestovat, stačí se zaregistrovat. V této souvislosti zmíním ještě jednu zprávu, kterou jsem dnes zachytil. Také Microsoft rozjel akci "zdarma" pardon Express via Express nástroje zdarma - na jak dlouho?

pátek 4. listopadu 2005

...a kam dál kráčet

Mohl bych prosim znat Vas nazor(p. Pichliku) nebo ostatnich, co bych teto dobe a v me situaci(znalost J2SE) po nauceni jsp stranek se mel ucit dal. Je mi jasne, ze nejlepsi je umet vse a zalezi na konkretnim ukolu a zvoleni vhodne technologie, ale presto musi byt technologie "lepsi" a "horsi". Neberte to prosim nekdo jako neco k nastartovani flame, je to jen zvidavost zacatecnika v teto oblasti. Jinak jsem si stahl snad vse mozne z intervalu co se tyka J2EE, ale presto bych rad znal vas nazor.

Na škole byla jedna informace, která se mi zaryla někam hluboko do paměti. Možná se vám to bude zdát divné, ale bylo to motto Znalosti mají smysl právě a jedině současně s jejich používáním., jehož autorem je Friedrich von Hayek. Jinými slovy, nemá cenu se učit něco, co vůbec nebudete používat.

Velice se zdráhám vyslovovat příkré soudy o tom co je lepší a co horší, když neznám přesnou situaci, pro kterou se hledá technické řešení. V poslední době hraje a bude hrát prim několik technologií nebo lépe řečeno přístupů. Alespoň tak to vidím já.

1.)AJAX a RIA

AJAX a RIA obecně jako směr pro tvorbu další generace webových aplikací.

2.)j2ee lightweight kontejnery

J2EE lightweight kontejnery jako RIFE a nebo Spring (Spring Framework - představení J2EE lightweight kontejneru) hrají a budou hrát prim a vytlačí EJB na okraj. Nebo donutí EJB k radikální proměně, kde změny chystané v EJB 3.0 budou pouhým odvarkem toho co bude muset přijít.

3.)Komponentně a událostně orientované frameworky

Výrazný nástup komponentně a událostně orientovaných frameworků pro tvorbu view vrstvy. A to postavených na standardizovaném JSF a nebo proprietarních řešení jako Tapestry, Wicket či Shale.

4.)Continuations

Využití continuations k tvorbě webových aplikací

5.)Obecný posun platformy Java

Java jako platforma je zdravá, silná a stabilní. V blízké budoucnosti se budou hledat cesty jak platformu rozšířit k zefektivnění vývoje a to především s ohledem na vysokou produktivitu. Vizionářsky pohled nabízí jinší kanón než já a to Bruce A. Tate v knize Beyond Java, ke které publikoval článek Technologies to Watch: A Look at Four That May Challenge Java’s Development Dominance (diskuse TSS). Zaklínadlem se tak jisto jistě stává Ruby on Rails - What Is Ruby on Rails.

středa 2. listopadu 2005

Minitutoriál: Eclipse, Tomcat a vývoj JSP a Servletu

Hodně často v diskusních skupinách javy zaznívá otázka, jak vyvíjet JSP a Servlety v IDE Eclipse. IDE Eclipse nemá přímou vestavěnou podporu pro JSP, Servlety nebo nasazení (deploying) do prostředí servletového kontejneru. K tomuto účelu je zapotřebí použít některý z plug-inu.

Protože jsem se rozhodl napsat tento příspěvek pro začínající vývojáře, použijeme plug-in Sysdeo Eclipse Tomcat Launcher plugin. To předpokládá, že je již nainstalovaný servletový kontejner Tomcat.

Konfigurace Sysdeo Eclipse Tomcat Launcher pluginu

Po nainstalování Sysdeo Eclipse Tomcat Launcher pluginu je potřeba jej nakonfigurovat.

Window >> Preferences >> Tomcat


Plná velikost (cca. 16KB)

  • Tomcat version - vyberte verzi nainstalovaného Tomcatu
  • Tomcat home - vyberte adresář Tomcatu

Window >> Preferences >> Tomcat >> Tomcat Manager App


Plná velikost (cca. 16KB)

Tomcat Manager App je správcovská webová aplikace, která umožňuje administraci aplikací, které na Tomcatu běží. Například je pomocí ní možné reloadovat jednotlivé aplikace bez nutnosti restartu celého Tomcatu.

Pokud používáte Tocmat 5.x je ManagerApp url ve tvaru http://server:port/manager. Zvolte si ManagerApp username a ManagerApp username a klikněte na tlačítko Add user to tomcat-users.xml.

Nový projekt

Nejdříve musíme vytvořit nový projekt a k tomu použijeme projektového wizarda, který přibyl po instalaci Sysdeo Eclipse Tomcat Launcher pluginu.

File >> New Project >> Java >> Tomcat Project

Zvolíme jméno projektu, případně adresář kam chceme projekt uložit.

Context name představuje kontextové jméno aplikace v rámci kontejneru. Kontextové jméno odpovídá kontextové části URL. Příklad: pokud tam stejně jako já zapíšete hodnotu test, bude URL vždy začínat http://server:port/test/*.

Tímto máme projekt připravený. Nyní si vytvoříme jednu testovací JSP stránku index.jsp, kterou umístíme přímo v rootu projektu.

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  <meta http-equiv="Content-Type" content="text/html;  
charset=UTF-8">
  <title>Hello world</title>
 </head>
 <body>
   Hello world
 </body>
</html>

A jeden servlet, který umístíme do WEB-INF/src/test.

 
package test;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse  
res) throws ServletException, IOException {
        res.getWriter().print("<html><body><p>Hello servlet world</p></body></html>");
    }
}
 

Pro namapování servletu na konkrétní URL vytvoříme soubor web.xml, který umístíme do adresáře WEB-INF.

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web  
Application 
2.3//EN' 'http://java.sun.com/dtd/web-app_2_3.dtd'>
<web-app>
    <servlet> 
   <servlet-name>HelloServlet</servlet-name>
   <servlet-class>test.HelloServlet</servlet-class> 
   <load-on-startup>1</load-on-startup>
    </servlet> 
    <servlet-mapping>
   <servlet-name>HelloServlet</servlet-name>
   <url-pattern>/helloservlet</url-pattern>
    </servlet-mapping>
</web-app>
 

Nyní je vše připraveno, nemusíme dělat žádný deploy aplikace. Stačí pouze nastartovat Tomcat. Můžeme to udělat např. z toolbaru IDE, kde máme tři nové ikonky pro ovládání "kocoura".

Po spuštění, mělo by být doprovázeno výpisy do konzole v IDE, otestujeme funkčnost v prohlížeči zadáním URL http://localhost:8080/test/index.jsp a http://localhost:8080/test/helloservlet.

Několik užitečných funkcí nalezneme v kontextové nabídce, když klikneme pravým tlačítkem na projekt a zvolíme Tomcat project. Tou nejužitečnější bude volba reload context, kterou použijeme v případě změny v zdrojovém kódu (netýká se JSP ty jsou rekompilovány automaticky).

Sysdeo Eclipse Tomcat Launcher plugin pouští Tomcat v debug módu, což znamená, že můžete debugovat tak jak jste z Eclipse zvyklí. Funguje i hot code replace. Plugin můžeme v některých případech použít i pro projekt, který nebyl původně vytvořen jako Tomcat Project viz project properties >> Tomcat.

Download testovacího projektu

Užitečné odkazy v češtině

úterý 25. října 2005

Databázové scénáře pro integrační a jednotkové (unit) testy

Pokud máte aplikaci, která je výhradně závislá na databázi, a chcete psát jednotkové a nebo integrační testy, pak jste postaveni před dva problémy.

  • nastavení testovacích dat alias uvedení databáze do výchozího stavu
  • kontrola dat v databázi v rámci testu

Jednou z možností, jak se výše uvedených problémů zbavit, je použít techniku tzv. mockování. Technika mockování je založena na tom, že vlastní testovaný objekt nepracuje v runtime s instancemi závislých objektů, ale s jejich atrapami, které v sobě mají předpřipravená data.

Ač jsou mock objekty dobrým řešením, především pro jednotkové testy, mají svá omezení. Tím nejzásadnějším, alespoň z mého pohledu, je nemožnost simulovat chování komplexních procesů, které probíhají na pozadí. Typickým příkladem pro databáze je omezení referenční integritou. Je velice neefektivní si připravovat mock objekt, který bude věrně simulovat chování databáze. Samozřejmě to nemusí být přímo databáze, ale například aplikační mezivrstva v podobě Hibernate a pod ní teprve databáze.

Další alternativou k mock objektům, a tentokrát plnohodnotnou, představuje framework DbUnit. DbUnit umožňuje jednak provést nastavení testovacích dat a také jejich kontrolu. Práci s DbUnit ukazuje článek Andrew Glovera Effective Unit Trstiny with DbUnit.

DbUnit je velice užitečný nástroj a má API podporu pro nejrůznější operace přes porovnávání datasetu až po extrakci databázových schémat. Jenže, starého psa, novým kouskům nenaučíš.

Jde o to, že jsem:

  • nechtěl nutit vývojáře vytvářet testovací data jako XML
  • nechtěl nutit vývojáře zkoumat další API
  • chtěl umožnit jednoduché využívání/rozšiřování předpřipravených dat

Výsledkem je jednoduchý "framework", který jsem pojmenoval ScenarioTestCase, a který je založený na jUnit. Stručná charakteristika by mohla znít takto: slouží pro psaní integračních a jednotkových testů za použití standardního API Javy a klasického SQL, s cílem umožnit jednoduché znovupoužití/rozšíření existujících testovacích dat.

Diagram tříd ScenarioTestCase frameworku Plná velikost (cca. 38KB)

Srdcem celého díla je abstraktní třída ScenarioTestCase, která jednak řídí životní cyklus testů a umožňuje spouštění testovacích scénářů. Termín testovací scénář, kterému odpovídá rozhraní TestSQLScenario, představuje sadu SQL dotazů starajících se o inicializaci a úklid testovacích dat.

ScenarioTestCase zaručuje:

  • před spuštěním testu volání metody onStartUp
  • před každou testovací metodou exekuci všech zaregistrovaných scénářů
  • před každou testovací metodou volání onSetUp
  • po každé testovací metodou volání onTearDown
  • možnost vykonat libovolný SQL dotaz (insert, update, delete, select)

Za zmínku stojí ještě třída ConnectionscenarioTestCase, která je potomkem ScenarioTestCase. Ta umožňuje otevření databázového připojení na základě předaných parametrů a dále implementuje práci s JDBC. Celý princip psaní testu ukazuje následující příklad. Modelová situace, máme tabulku, ve které je uloženo přihlašovací jméno uživatele a nějaké další hodnoty. Výsledný testovací objekt se pak snaží ověřit funkčnost aplikační logiky, která by měla změnit přihlašovací jméno

Napsání scénáře

Testovací scénář obsahuje SQL příkazy pro inicializaci a úklid databáze. Každý testovací scénář musí implementovat již zmíněné rozhraní TestSQLScenario, které definuje dvě metody. Metoda getInitSQL slouží pro vrácení seznamu inicializačních SQL příkazů. Metoda getCleanUpSQL slouží pro vrácení úklidových příkazů.

 
public class ExampleScenario implements TestSQLScenario{
  
    public List getInitSQL() {
        ArrayList l = new ArrayList();
        l.add("insert into users (uname, user_id,) values ('pavel', 1)");
        return l;
    }

    public List getCleanUpSQL() {
        ArrayList l = new ArrayList();
        l.add("delete from users where user_id = 1979");
        return l;
    }
}
 

Vytvoření vlastního testu

Vlastní testovací objekt je napsán jako potomek třídy ConnectionscenarioTestCase . V metodě onStartUp se provede vytvoření testovacího scénáře a jeho registrace pomocí metody addScenario. Takto je samozřejmě možné registrovat libovolné množství scénářů. Třída ConnectionscenarioTestCase definuje abstraktní metodu getConnectionParametrs, pomoci které potomci specifikují parametry pro otevření databázového připojení.

 
public class ExampleTest extends ConnectionScenarioTestCase {
    
    protected String[] getConnectionParameters() {       
        return new String[]{
                "com.mysql.jdbc.Driver", 
                "jdbc:mysql://localhost/test", 
                "test", 
                "test"};
    }

  
    protected void onStartUp() {      
        super.onStartUp();
        addScenario(new ExampleScenario());//přidání scénáře        
    }

    
    public void testFoo(){       
        //zinstancování aplikační logiky
 AplikacniLogika al = new AplikacniLogika(); 
 //změna uživatelského jména
        bl.zmen('šavel')
        
        //Pro ověření použijeme select, kde předpokládanou změnu 
        //zahrneme v rámci where klauzule viz uname='šavel'.
        int count = 
jdbcSelect("select count(*) from users where uname='šavel' and user_id = 1");
        
        //V případě, že logika zafungovala správně, musí byt v proměnné count hodnota 1
        assertEquals("Uživatelské jméno musí být změněno", 1, count);
    }
    
    public void testHoo(){       
       //test something else
    }
}
 

Testovací objekt lze pouštět jako jakýkoliv jiný jUnit test.

Rozšiřitelnost

ScenarioTestCase je určen k tomu, aby byl rozšířen patřičným způsobem a ConnectionScenarioTestCase představuje ukázku, jak to lze udělat. Typické rozšíření může například představovat implementaci, kdy nastartujeme například databázový pool a nebo kontejner (Spring), ve kterém "žije" aplikační logika.

Objekty implementující rozhraní TestSQLScenario lze skládat a nebo rozšiřovat. Myšlenka je taková, že by mělo vzniknout několik základních scénářů, které se využívají přes většinu testů. Pokud je potřeba testovací scénář rozšířit, udělá se jeho potomek a nebo kompozice.

Tento jednoduchý "framework" není rozhodně zamýšlen jako konkurence nebo náhrada DbUnit. Je to pouze jednoduchoučká alternativa pro pohodlné psaní testů závislých na databázi. Zdrojové soubory a zkomipolované třídy je možné použít dle libovůle. Jenom připomínám, že je potřeba mít na classpat jUnit a že je to psané pro Javu 5.0.

pátek 21. října 2005

Spring Framework seriál

Když jsem kdysi slíbil, že napíšu seriál o frameworku Spring, upletl jsem si na sebe pěkný bič. Připoutejte se prosím, na serveru Interval.cz, startujeme prvním dílem - Spring Framework - představení J2EE lightweight kontejneru. Za odbornou korekturu článku bych chtěl poděkovat Janu Macháčkovi (spoluautor knihy Pro Spring).

čtvrtek 20. října 2005

Eclipse a drobné maličkosti - rychlé otevírání tříd a ostatních souborů

Když jsem tuhle vychytávku pro rychlé otevírání tříd poprvé vyzkoušel, nemohl jsem uvěřit, že jsem bez něčeho takového mohl vůbec v Eclipse fungovat. Stejně tak nevěřícně na mě koukali moji kolegové, kterým jsem to ukázal. Nevýhoda práce se soubory, které jsou organizovány v stromové struktuře, spočívá v pracnosti jejich otevírání. Sice víte, že potřebujete otevřít soubor XYZ, ale už nemusíte vědět kde přesně se naléza v adresářové struktuře projektu. Eclipse má proto magickou klávesovou zkratku Ctrl-Shift-T a Ctrl-Shift-R, pomocí které je otevření požadovaného souboru otázkou zlomku vteřiny.

Open type

Open type je dialog aktivovaný klávesovou zkratkou Ctrl-Shift-T, pomocí které lze otevírat jakékoliv Java typy, které máte v rámci otevřených projektu. To znamená, jakékoliv třídy, rozhraní z vlastního projektu a nebo z přidružených knihoven těchto projektu. Vlastní výběr konkrétního typu lze omezit na určitou skupinu a to zapsáním počáteční části jeho názvu, samozřejmě lze využít i zástupného znaku.

Open type dialog

Pokud máte například jeden projekt pod Javou 1.4 a další pod 5.0 a potřebujete se podívat na zdroják StringBufferu, tak Open Type dialog nechá na vašem výběru, který si přejete zobrazit. Informace je pěkně vidět na předchozím obrázku.

Open Resource

Open resource dialog se odlišuje od Open type v tom, že nabízí k otevření všechny soubory (open type pouze javovské), které jsou součástí otevřených projektů.

Open type dialog

Související články

Eclipse 3.1 a podpora generických typů

Některé články se objeví přesně v ten moment, kdy mi to přijde vhod. Asi před čtrnácti dny jsme se čistě ze strategických důvodů rozhodli přejít na Javu 5.0. Základní premisou pro vývoj v pětkové řadě je podpora nových jazykových konstrukcí jako jsou například generické typy. V případě IDE Eclipse, které ve firmě používáme, je plná podpora Javy 5.0 implementována ve verzi 3.1.

Než se vrhnete na používání Javy 5.0 v Eclipse, budete muset nastavit minimálně kompilátor pro 5.0 a tím pádem, aktivujete podporu 5.0 v standardních nástrojích IDE, jako Quick Assist, Quick Fix, refactoring a tak dále. Pokud už v tom budete a přecházíte na stávajícím projektu, doporučuji v nastavení kompilátoru, záložka Error/Warnings, změnit v J2SE 5.0 Unchecked generic type operation na hodnotu ignore.

Pokud máte úspěšně zkompilováno a chcete vyzkoušet nějaký ten nový konstrukt, není lepší volba než generický typ. No, a pokud jste zvědaví, jak vám v tom Eclipse pomůže, můžete zkusit prolétnout článek Neala Forda Java generics support in Eclipse V3.1

pondělí 3. října 2005

JavaForge - alternativa k SourceForge pro javovské projekty

Občas se stane, že člověk zaspí nějaké události, které by rozhodně zaspat neměl např. narozeniny bližního svého. I já jsem trochu zaspal, když jsem nezaregistroval, že se rozjel nový systém JavaForge, určený k hostování, podpoře vývoje a řízení open source java projektů. Za projektem stojí server Javalobby a firma Intland Software, viz Matthew Schmidt - Javalobby Launches Subversion-based Collaboration Platform.

JavaForge (dále JF) je možné pokládat za alternativu k systému SourceForge (dále SF) a to především pro javovské projekty. Ty mohou využít například podporu build systému CruiseControl, testovacího frameworku JUnit a nebo integraci s IDE Eclipse. Narozdíl od SF, je pro SCM (Source Control Management) standardně zvolen progresivnější SubVersion (oproti CVS). Na druhou stranu, JF se chlubí podporou pro integraci s dalšími SCM systémy jako CVS, PVCS, CM Synergy a SourceSafe. Tažným koněm JF je collaborative development platform (český ekvivalent?) CodeBeamer.

Na závěr jsem si nechal anoncované vlastnosti, kterými se systém JavaForge pýšní

  • Trackers to track and manage issues ranging from bugs to requirements
  • Dashboard, task & bug reports with trending
  • Document Management
  • Source Code Comprehension
  • SCM integrations for Subversion, CVS, PVCS, CM Synergy and SourceSafe
  • Full Managed Subversion support
  • Full Managed CVS support (COMING SOON UPON DEMAND!)
  • QA statistics and metrics with trends
  • Coding violations
  • Build and Release
  • Instant messaging (Chat)
  • Discussion Forums
  • Integrations:
    • Eclipse (WSAD)
    • Wiki
    • WebDAV

pátek 30. září 2005

Využití continuations k tvorbě webových aplikací

Interakce mezi klientem a serverem je ve webových aplikacích podřízena bezestavovosti HTTP protokolu. Uživatel vytvoří požadavek, například klikne na odkaz nebo odešle formulář, a server poskytne odpověď v podobě HTML stránky. Při dalším požadavku toho samého klienta server netuší, že nějaká komunikace mezi nimi již proběhla. Představme si, že chceme realizovat objednávku zboží pomocí několika formulářů.

 
  Klient                     Server
         ** Stranka 1 **           
   <-- tady je formulář 1
   tady jsou vyplněná data    --> 
        ** Konec stranky 1 **
      
        ** Stranka 2 ** 
kontrola dat serverem (nevalidní data) návrat na stranku 1
   <-- tady je formulář 2
   tady jsou vyplněná data    -->             
        ** Konec stranky 2 **       

        ** Stranka 3 ** 
 kontrola dat serverem (nevalidní data) návrat na stranku 2
   <-- stránka s informací o odeslání objednávky k zpracování               
        ** Konec stranky 3 **  
 

Pro realizaci tohoto scénáře použijeme určitě HTTP session a obslužnou logiku projednotlivé formuláře rozdělíme do více controllerů, anebo použijeme jeden s hromadou testů na předchozí kroky. Vykoupení z bezestavovosti HTTP protokolu za pomoci session, má tu nevýhodu, že musíme s každým klientským požadavkem restaurovat stav předchozí komunikace z hodnot, které máme na session uložené, abychom dokázali rozhodnout o dalším zpracování (pokračuj a nebo se vrať o krok zpět).

Zkusme se zamyslet, jak by zpracování každého požadavku vypadalo v případě, že by server mohl s každým zasláním dat klienta navázat na předchozí stav komunikace a pokračovat dále.

 
1:   function novaObjednavka(request){
2:      boolean success = false;
3:      do{
4:        sendPageAndWait("formular1");
5:        success = validate(request);
6:      } while (!success)
7:
8:      success = false;  
9:  
10:     do{
11:       sendPageAndWait("formular2");
12:       success = validate(request);
13:     } while (!success)
14:  
15:     zpracujObjednavku();
16:     sendPage("objednavkaPrijata");  
17: }
 
  1. Klient požádá server o založení nové objednávky, ten vyhodnotí (je úplně lhostejno jak), že ji obsluhuje funkce novaObjednavka parametr request, představuje vlastní HTTP požadavek.
  2. Vykonávání programu se zastaví na řádku 4. Funkce sendPageAndWait je nativní funkcí serveru a způsobí to, že server vrátí první formulář a předá řízení klientu. Parametrem se serveru předává informace o tom, kterou stránku má klientovi vrátit.
  3. Klient po nějaké době vyplní formulář a odešle formulář na server, tím pádem server přebírá řízení. Server ví, že naposledy skončili s klientem na řádku 4, a proto pokračují řádkem pět. Na řádku 5 proběhne validace (vrací boolean hodnotu) formuláře
    1. pokud je úspěšná - posune se vykonávání přes řádek 8 až na řádek 11. Opět vstupuje do hry známá funkce sendPageAndWait, klientovi je společně s druhým formulářem předáno řízení.
    2. pokud není úspěšná - posune se vykonávání díky splněné podmínce cyklu zpět na řádek 4 a klientovi je společně s prvním formulářem opět předáno řízení.
  4. Při dalším předání řízení server opět ví, kde skončila poslední interakce. V závislosti na tom se pokračuje buďto na řádku 5 nebo 12.
  5. Interakce , která probíhá při založení nové objednávky, je ukončena zpracováním objednávky (uložení do databáze apod.) na řádku 15 a předáním řízení klientovi na řádku 16.

Jak je vidět na první pohled, kód je velice dobře čitelný a nemusíme vynakládat veliké úsilí proto, abychom s každým požadavkem restaurovali předchozí stav a rozhodovali se, jak dále pokračovat. Problém použitého postupu je v tom, jak realizovat ono přerušení, vyvolané funkcí sendPageAndWait a především jak jej později uvolnit a pokračovat dále ve zpracování ve chvíli, kdy klient poskytne data. Tu magickou část skládanky, která nám umožní realizovat přerušení a jeho uvolnění, představuje tzv. Continuations.

Co je continuation?

Continuation je vypůjčený výraz z jazyku Scheme a označuje se pomocí něj funkce nebo objekt, který reprezentuje aktuální stav (stacktrace a hodnoty proměnných) programu během jeho vykonávání. Představte si, že pustíte program v debug módu a vykonávání programu se zastaví na breakpointu. Stacktrace a lokální proměnné, které vidíte v debuggeru, představují continuation pro aktuálně zahaltovaný program.

Když se na continuation podíváte z druhé strany, tak představuje "zbytek" toho, co se má v programu udělat. Představme si, že se právě vykonává řádek číslo pět níže uvedeného programu. Pro ilustraci následuje pod kódem screenshot se vším podstatným.

 
  1: public class Foo{
  2:  public static void main(String args[]){
  3:    int foo = 1;
  4:                    int hoo = 1;
  5:                    int bar = foo + hoo;
  6:                    System.out.println(bar);  
  7:  }
  8:  }
 

Obrázek z debuggování programu

Continuation vypovída nejen o tom, v jakém stavu se nachází vykonávání programu, ale také jak bude vykonávání dále pokračovat (v našem příkladě se provede řádek šest). Díky tomu, že continuation poskytuje informaci o aktuálním stavu a o tom jak se z něj bude pokračovat, je možné udělat přerušení (pause) běhu programu a posléze jeho budoucí spuštění (resume) od bodu přerušení. Stačí nám k tomu pouze získat Continuation objekt či funkci.

Bohužel Java nenabízí, narozdíl od jiných programovacích jazyků, žádné standardní prostředky k tomu, abychom jsme mohli s Continuation jakkoliv pracovat. Pokud je mi známo, tak ani .NET či PHP podporu pro práci s Continuation nemá. I když Java nemá žádné standardní prostředky, Continuation v ní lze použít!

Z těch známějších frameworků má podporu Continuation web application framework RIFE, ta je popsána v článku RIFE Web continuations. Autoři frameworku RIFE se minulý týden rozhodli vyseparovat jejich continuation engine do samostatného subprojektu, který bude na zbytku RIFe nezávislý, viz Announcing RIFE/Continuations, pure Java continuations for everyone.

Dalším frameworkem je Apache Cocoon, který umožňuje napsat flow script s podporou continuations jak v Jave, tak v JavaScriptu (Rhino engine). Vřele doporučuji článek Abhijita Belapurkara Use continuations to develop complex Web applications, kde najdete rozšiřující informace, které se mi do tohoto článku nevešly. Ke Cocoonu ještě přidávám zajímavý článek Rhino with Continuations.

Pokud narazíte na informaci, že servletový kontejner Jetty má podporu Continuations, tak tomu nemusí být pravda. Minimálně to, co prezentoval Greg Wilkins v článku Jetty 6.0 Continuations - AJAX Ready!, není continuations, nýbrž jakási forma request parkingu, viz diskuse na TSS.

čtvrtek 22. září 2005

Praktická ukázka sociálního inženýrství

Jakákoliv bezpečnost jde ruku v ruce s lidským faktorem. Zářným příkladem využívajícím tohoto spojení je tzv. sociální inženýrství. Na sociálním inženýrství založil kariéru Kevin Mitnick a s úspěchem jej využívají autoři virů. No a pokud se chcete podívat jak to funguje v praxi, tak doporučuji článek Jak zjistit heslo na Seznam Email. Nebudu říkat vice a tiše se budu těšít na odpoledne…

úterý 13. září 2005

Co způsobuje v IE hlášku 'Tato stránka obsahuje zabezpečené i nezabezpečené položky' a jak ji odstranit

Standardně je tato chyba způsobena tehdy, pokud na stránce, která je zabezpečena pomocí SSL dojde k volání externího objektu, který pomocí SSL nelze zabezpečit (například volání CSS, obrázku, javascriptu z jiného, protokolem SSL nezabezpečeného, serveru).

Nejčastější rada zní - projděte si zdroj a najděte výskyt 'http://' tam, kde něco stahujete, volání odstraňte a je po chybě. Jenže je tu ještě jedna věc, která danou chybu může způsobit (většinou po ni začnete pátrat v okamžiku, kdy zjistíte, že nikde ve zdroji žádné 'http://' nemáte).

Vše je jasné z následujícího úryvku získaného v konferenci u Microsoftu:

IE gives this message when the page contains objects from HTTP server instead of HTTPS server: such as css, js, img etc or when we reference about:blank as the src of an iframe.

Takže nejen obrázky, styly, a javascripty, ale i chybně definovaný atribut 'src' u iframe. V mém případě nebyl definován vůbec, což si IE přeložil jako 'about:blank'. Poté, co jsem scr definoval správně, už problém nebyl a stránka se nyní tváří jako zcela zabezpečená.

Celý článek byl převzatý z naší firemní wiki, se souhlasem Budíka, jakožto autora textu. Ještě jednou díky za svolení to publikovat, protože věřím, že to hodně lidem pomůže.

pondělí 12. září 2005

SEO spammeři z Texasu

Včera do mojí emailové schránky dorazila nabídka s vážným zájmem o reklamu na Dagblogu. Pod emailem, který se mě snaží přesvědčit o tom, jak je pro mě výhodné umístit (2400/rok) čtyři odkazy na kasina, je podepsána jistá Martina Leinová.

V podstatě jde o klasickou pyramidu, která se točí kolem zpětných odkazů, které mají pomoci nějakému kasinu vystoupat ve vyhledávačích. Výsledkem je klasická link farma, bohužel s neblahým dopadem, v podobě penalizace od vyhledávačů, na toho kdo linkuje.

Vřele doporučuji rozhovor Jan Ambrož s Robertem Němcem - Rizika prodeje zpětných odkazů z vašich stránek s podtitulem Michal Kadera se rozhodl skupovat zpětné odkazy pro online kasina v Texasu..

pátek 9. září 2005

Java – znakové kódování

Jedno z nejčastěji tázaných témat, v diskusních skupinách věnovaných Jave, se točí kolem kódování znaků. Nejčastěji se to týká kódování při čtení/zápisu servletu (JSP), databáze a souborů. Obecně to může generalizovat na operace probíhající na hranici mezi JVM a okolním světem, kde dochází převodu bytové reprezentace na znakovou reprezentaci a naopak. Mě osobně nejvíce problematiku kódování v Jave osvětlil Makub v diskusní skupině na serveru java.cz a tak se pokusím podělit.

Nemám problém protože všechno je Unicode

Výše uvedený nadpis si najdete v kdejakém pamfletu o Jave. Ano je to skutečně tak, že Java pracuje vnitřně se všemi znaky jako s Unicode. Unicode přiřazuje každému znaku jedinečné číslo a definuje tři formy, jak může být toto číslo reprezentováno v byte, word nebo double word formě (8, 16, 32).

To že Java pracuje vnitřně s Unicode (používá UTF-16), je tak omlácenou frází, že vede mnoho vývojářů k přesvědčení, že se nemusí o kódování starat. Opak je pravdou. Při jakékoliv probíhající na hranici mezi JVM a okolním světem, například čtení textového souboru nebo zápis do databáze, dochází k převodu z vnitřní unicodovské reprezentace znaku na jeho bytovou reprezentaci a naopak.

Vnější bytová reprezentace pak odpovídá zvolenému kódování. Pokud toto kódování neurčíme, použije JVM defaultní kódování, které závisí na prostředí, v němž běží. Právě při převodu znaku na bajtovou vnější reprezentace a naopak dochází k problémům. Pokud se defaultní kódování JVM liší s kódováním, které chceme na vstupu/výstupu a my toto kódování explicitně Jave neurčíme, dojde k převodu na bytovou reprezentaci či naopak, podle defaultního kódování.

Klasickým příkladem je zpracování HTTP požadavku v servletu. Pokud začneme číst parametry HTTP požadavku, před tím než zavoláme metodu setCharacterEncoding, dojde k tomu, že servletový kontejner použije defaultní kódování pro všechny parametry.

Jednoduchá rada, plynoucí z výše uvedeného, tedy zní:Explicitně určujte kódování pro všechny vstupně/výstupní operace mimo JVM. Problém této rady je v tom, že vývojáři si často neuvědomí co je mimo JVM. Takže jedná se například o práci s databází, souborovým systémem nebo zpracování HTTP požadavku.

Na závěr jsem si nechal pár praktických rad, které řeší 90% problémů.

Obecné - žádné texty ve zdrojových kódech

Vyčleňte všechny aplikační texty do resource bundle a ušetříte si s tím plno problému.

Obecné – čtení/zápis textových zdrojů

Používejte třídy java.io.InputStreamReader a java.io.OutputStreamWriter.

Obecné - nastavte kódování pro kompiler

Pokud používáte ve zdrojovém kódu aplikační texty např. pro výjimky, nezapomeňte určit kompileru kódování. Slouží pro to parametr encoding.

Obecné - zkonvertujte properties resource bundle před použitím

Pokud používáte resource bundle založený na properties souboru, prožeňte jej, v rámci build procesu, přes utilitku native2ascii. Ta je standardní součástí Java SDK.

 
Antovský task:
<target name="native2ascii"> 
    <native2ascii 
 encoding="utf-8" 
 src="${src.dir}" 
 dest="${web.dir}/WEB-INF/classes" 
 includes="**/*.properties" 
 ext=".properties"/> 
</target>
 
Server - nastavte kódování pro HTTP request/response

Před tím než přečtete první parametr a zapíšete první znak na výstup nastavte pro oba požadované kódování. V případě HTTP požadavku se k tomu dá elegantně využít servletový filtr. Filtrem zamezíte případným problémům, které mohou nastat v případě, že si na parametry "šáhne" někdo před vámi, např. validátor vstupních parametrů.

 
public class RequestEncodindFilter implements Filter{    
  public void doFilter(
  ServletRequest rq, 
  ServletResponse re, 
  FilterChain chain) 
    throws IOException, ServletException {

            rq.setCharacterEncoding("utf-8");//kodovani          
            chain.doFilter(rq,re);  
  } 
 
  public void init(FilterConfig fc) throws ServletException {}
  public void destroy() {}
}

web.xml

<filter>  
  <filter-name>RequestEncodindFilter</filter-name>
  

<filter-class>filterpackage.RequestEncodindFilter</filter-class> 
</filter>
 
<filter-mapping>
  <filter-name>RequestEncodindFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
 

Pro JSP stránky používejte direktivu page a atribut pageEncoding a contentType

 
<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
 
Databáze - nastavte kódování pro JDBC ovladač

JTDS ovladače mají parametr, kterým určíte kódování pro práci s CHAR/VARCHAR/TEXT typy.

 
Connection string MySQL JDBC ovladače:
jdbc:mysql://localhost/devdb1?useUnicode=true&characterEncoding=UTF-8
 

čtvrtek 1. září 2005

Vyšší dívčí – názvy temporary proměnných

Jestliže si myslíte, že programování resp. jeho určité činnosti nelze povýšit na umění, pak se hluboce mýlíte. Kreativita vývojářů se naplno rozbuší při vymýšlení názvů temporary proměnných. Připadám si trochu fádní se svými názvy temporary proměnných jako foo nebo hoo v porovnání s tím, na co lze narazit.

Jeden z kolegů dokonce našel inspiraci v ovoci a zelenině: pomik, kiwik, svestik, tresnik. Už jsem se setkal i s neotřelými nazvy rozhraní jako Bordel, Kybl, s názvy metod hodDoKyblu, vyndejZkyblu. Ovšem ani jeden z těchto neortodoxních názvů mě neodzbrojil jako následující kód.

Odhlášení uživatele při použití Basic Authentication

Připadá Vám logické, že pokud se někam přihlásíte, měli byste mít možnost se i odhlásit? Pokud použijete pro autentizaci tzv. Basic Authentication (viz RFC 2617), představuje odhlášení takřka nepřekonatelný problém.

Lesk a bída Basic Authentication

Basic Authentication funguje tak, že při požadavku na resource, pro který je vyžadována autentizace, vrátí server prohlížeči hlavičku 401 Authentication Required. Prohlížeč si od uživatele vyžádá jméno a heslo, které zašle na server. Pokud je autentizace úspěšná, vrátí server požadovaný resource. Protože je HTTP protokol bezestavový, probíhá stejný scénář pro každý požadavek.

Aby byl uživatel ušetřen neustálého zadávání uživatelského jména a hesla, prohlížeč si je při prvním úspěšném ověření "zapamatuje" a s každým dalším požadavkem posílá automaticky. Ono "zapamatování" je specifické podle implementace prohlížeče, ale veskrze je omezeno na tzv. browser session, která vzniká při otevření prohlížeče a zaniká při jeho zavření. Problém je v tom, že neexistuje standardizovaný způsob, jak prohlížeč donutit, aby přihlašovací data již neposílal a tím došlo de facto k odhlášení.

Nefunkční workaround pro Internet Explorer

První způsob těží z toho, že prohlížeč při neúspěšné autentizaci požádá uživatele o nové zadání přihlašovacích údajů. Dále se využívá toho, že přihlašovací údaje mohou být součástí vlastní URL, a to ve formátu protokol://jmeno:heslo@server např. http://foo:hoo@acme.com/doSomething. Trik spočívá v tom, že při odhlášení se provede přesměrování, při kterém se do URL přidají neexistující přihlašovací informace. Prohlížeč tak zůstane ve stavu, kdy je zobrazen dialog pro přihlášení. Celý postup je popsán v článku Pavla Růžičky Odhlášení z HTTP autentizace.

Tento způsob skutečně fungoval, a to do doby, kdy velký bratr, pardon Microsoft, vydal kumulativní aktualizaci zabezpečení MS04-004 alias KB 834489(mimochodem standardně v SP2), která možnost odesílání přihlašovacích informaci v rámci URL posílá do věčných lovišť. Všechno podstatné k této záplatě osvětluje microsoftí pamflet K dispozici je aktualizace zabezpečení, která mění výchozí chování aplikace Internet Explorer při zpracování informací o uživateli v adresách URL protokolu HTTP a HTTPS. Musím říci, že po všech těch důvodech, které vedly k vydání tohoto patche, jsem zamáčknul slzu v oku.

Funkční workaround pro Internet Explorer

Naštěstí by to nebylo samo sebou, kdyby neexistoval jiný způsob odhlášení pro vyvolené uživatele Internet Exploreru. Díky aktivnímu skriptování v podobě technologie ActiveX můžeme využít informací získaných z microsoftího článku How To Clear Logon Credentials to Force Reauthentication. No a pokud máme někoho, kdo může ten kód zkompilovat, udělat package a podepsat ActiveX komponentu (díky NkD), tak je na půl vyhráno. Zbývá už "jenom" přesvědčit uživatele, že povolení ActiveX nerovná se otevření Pandořiny skříňky...