jAbLoK

Složené, fousaté, kudrnaté?

Zasláno do Java, Miscellaneous by Pavel Kolesnikov na Červen 16th, 2008

{

}

… neboli složené závorky. S Tomuchou v MA jsme jim říkali “fousaté”, Jakub Podlesak je v osmnáctém Java podcastu nazývá “kudrnatými”

Jak jim říkáte vy?

Tagged with: ,

Skutečně umíme měřit, jak dlouho lidé setrvají na webových stránkách

Zasláno do Tech by Pavel Kolesnikov na Březen 14th, 2008

Daniel Dočekal klade řečnickou otázku, a jak to u řečnických otázkách bývá, rovnou připojuje negativní odpověď — cituji: "jediné co totiž [Navrcholu] ví, je že někdo někam přišel. A pak už nikam neodešel".

Navrcholu to možná neumí (proč?), technicky lze tuto dobu velmi dobře aproximovat za předpokladu, že při čtení stránky uživatel tu a tam zaroluje či pohne myší (schválně si to vyzkoušejte na sobě).

Třeba takto:

/**
 * a simple reading time tracking utility
 *
 * @author Pavel Kolesnikov
 */
var Tracker = function(cfg) {
	var TIMEOUT = 3000; // 3 seconds

	var config = cfg ? cfg : {};

	var mouseLogging = 1;
	var keyboardLogging = 1;

	var lastActivity;
	var total = 0;
	var saveMessage = config.saveMessage;

	function logActivity() {
		var now = new Date();
		var sinceLastActivity = now.getTime() - lastActivity.getTime();
		if (sinceLastActivity > TIMEOUT) {
			sinceLastActivity = TIMEOUT;
		}
		total += sinceLastActivity;
		lastActivity = now;
	}

	function logActivityMouse() {
		if (mouseLogging) {
			logActivity();
		}
	}

	function logActivityKeyboard() {
		if (keyboardLogging) {
			logActivity();
		}
	}

	this.stopMouseLogging = function() {
		mouseLogging = 0;
	};

	this.startMouseLogging = function() {
		mouseLogging = 1;
	};

	this.stopKeyboardLogging = function() {
		keyboardLogging = 0;
	};

	this.startKeyboardLogging = function() {
		keyboardLogging = 1;
	};

	function createXMLHttpRequest() {
		if (window.XMLHttpRequest) {
			return new XMLHttpRequest();
		} else if (window.ActiveXObject) {
			return new ActiveXObject('Microsoft.XMLHTTP' ;)
		} else {
     		return null;
		}
	}

	function postLog(params) {
		var ajax = createXMLHttpRequest();
		if (ajax) {
			ajax.onreadystatechange = function() {};
		}
		ajax.open('POST', config.o, true);
		ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		ajax.setRequestHeader("Content-length", params.length);
		ajax.setRequestHeader("Connection", "close");
		ajax.send(params);
	}

	function write() {
		var params = "u=" + config.u + "&i=" + config.i + "&t=" + total
			+ "&r=" + document.referrer;
		postLog(params);
	}
	this.write = write;

	lastActivity = new Date();
	document.onmousemove = logActivityMouse;
	document.onkeypress = logActivityKeyboard;
	window.onunload = write;
}

re: Odháčkování

Zasláno do Java by Pavel Kolesnikov na Prosinec 16th, 2007

Cituji Petr Ferschmana:

Snad každý český programátor narazil na problém odstranění diakritiky z textu (tzv. odháčkování). Pro tyto účely jsem si kdysi vytvořil jednoduchou mapovací tabulku pro znaky v kódování ISO-8859-2. Nyní jsem v Javě potřeboval něco podobného a našel jsem lepší řešení:

   String decomposed = java.text.Normalizer.normalize(string, Normalizer.Form.NFD);
   return  decomposed.replaceAll("p{InCombiningDiacriticalMarks}+", "");

Pěkný, neznal jsem. Jen si dovolím dvě doplnění:

  • java.text.Normalizer přišel až s Javou 6
  • pokud ještě šestku nemáte, nemusite spoléhat na mapovací tabulky, ale můžete použít icu4j od IBM (pod proprietární, ale nerestriktivně vypadající open-source licencí). Pak můžete pro změnu psát něco jako:
       String rule = "Any-Latin; NFD; [:Nonspacing Mark:] Remove; NFC";
       Transliterator tr = Transliterator.getInstance(rule);
       return tr.transform(src);
    
Tagged with: ,

Google Guice

Zasláno do Java by Pavel Kolesnikov na Březen 14th, 2007

Pozorováním programátorů v divočině člověk snadno zjistí, že je zjevně zábavnější vytvářet obecné frameworky nežli aplikace, které něco opravdu dělají. Takže není divu, že máme další z mnoha frameworků poskytující podporu pro organizaci aplikace podle vzoru  inversion of control .

Název naznačuje, proč zrovna tenhle kousek stojí za popzornost: než byl vypuštěn do světa jako open-source projekt, tak byl po několik měsíčů prakticky ověřován na Gůglích  "mission critical applications"  (zdroj) — nevím, které přesně, někde jsem sice v této souvislost četl o AdWords, ale už si nevybavuju, kde.

Stručná charakteristika:

  • řeší jen a pouze dependency injection + integraci s servletovým kontejnerem
  • vyžaduje Javu 5, a je silně postaven na generických typech a anotacích
  • má být svižný (čemuž bych věřil, protože letmý pohled do zdrojáků naznačuje naprostou absenci reflection)

Jak se s Guice programuje?

Máme-li třídu závislou na implementaci nějakého rozhraní, označíme příslušný setter (nebo konstruktor) anotací @Inject:

import com.google.inject.Inject;

public class Client {
     private Counter counter;

    @Inject
    public void setCounter(Counter counter) {
        this.counter = counter;
    }

    public void test() {
        counter.ping();
        counter.ping();
        System.out.println(counter.getValue());
    }
}

Co nám vlastně do proměnné counter přilítne, určí programátor tak, že vyrobí, tzv. modul, tedy implementaci rozhraní com.google.inject.Module, ve většině newebových případů pak potomka com.google.inject.AbstractModule a pro webové aplikace má k dispozici rovnou com.google.inject.servlet.ServletModule.

V modulu si pak namapuje rozhraní na konkrétní implementaci a vymezí rozsah platnosti instancí, třeba takhle:

import com.google.inject.Scopes;
import com.google.inject.servlet.ServletModule;

public class MyModule extends AbstractModule {
    protected void configure() {
        super.configure();
        bind(Counter.class).to(CounterImpl.class).in(Scopes.SINGLETON);
    }
}

Výše uvedený kód říká, že do metod označených anotací com.google.inject.Inject, které přijímají parametr typu Counter se předá vždy jedna a tatáž instance (ano, to je to in(Scopes.SINGLETON)) třídy CounterImpl.

A pokud má náš kód běžet v prostředí webového kontejneru a modul vyrobíme rozšířením třídy ServletModule, pak máme — nejspíš v souladu s očekáváním — další dvě možnosti nastavení rozsahu platnosti injektovaných tříd, a to com.google.inject.servlet.ServletScopes.REQUEST a SESSION.

Pokračování možná jindy.

Gmailoidni "ořezávací" tabulky v HTML

Zasláno do Tech by Pavel Kolesnikov na Březen 8th, 2006

Jsou různé způsoby, jak zobrazit výpis tabulkových dat obsahujících textové pole víceméně neomezené délky (typicky nějaký popis).

Pokud netrváme na tom, že je třeba toto pole i ve výpisu zobrazit za každou cenu celé, častým řešením je text oříznout, aby zalamováním na více řádků neprotahoval tabulku na výšku, jako to dělá třeba GMail.

A protože vyznat se ve zdrojovém HTML Gmailu není úplně snadné, potěší návod na http://www.blakems.com/archives/000077.html — opravdu to funguje:


table.cropping { width: 100%; table-layout:fixed; border-top: 5px solid #333; border-collapse: collapse; background: #fff; }
table.cropping td { border-bottom: 1px dashed #333; padding: 0.1em 2em 0.1em 1em; text-overflow:ellipsis; overflow:hidden; }
table.cropping td span { white-space:nowrap; }

<table class=&amp;quot;cropping&amp;quot;>
     <col> <col> <col> <col>
    <thead>
        <tr><th>name</th><th>description</th><th>status</th><th>created</th></tr>
    </thead>
    <tbody>
    <tr> <td class=&amp;quot;name&amp;quot;><span>Name 1</span></td> <td><span>Description comes here, may be quite short</span></td> <td class=&amp;quot;status&amp;quot;><span>OK</span></td> <td><span>1.1.2006 17:30</span></td> </tr>
    <tr> <td class=&amp;quot;name&amp;quot;><span>Name 2</span></td> <td><span>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus.</span></td> <td class=&amp;quot;status&amp;quot;><span>OK</span></td> <td><span>2.1.2006 11:30</span></td> </tr>
    <tr> <td class=&amp;quot;name&amp;quot;><span>A sample very, very, very long name containing some pseudo-latin words like lorem ipsum dolor sit</span></td> <td><span>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</span></td> <td class=&amp;quot;status&amp;quot;><span>Failed</span></td> <td><span>1.1.2006 17:30</span></td>
    </tr> <tr> <td class=&amp;quot;name&amp;quot;><span>Blah</span></td> <td><span></span></td> <td class=&amp;quot;status&amp;quot;><span>OK</span></td> <td><span>1.1.2006 17:30</span></td> </tr>
    </tbody>
</table>

Pokud vám to přijde jako notorická samozřejmost, a vůbec máte dojem, že se toho s různými HTML/CSS/JS fígly příliš nadělá, tak pro vás závěr nedávné náborové povídání platí, i když zrovna nepěstujete Javu (jinými slovy, můj zaměstnavatel uvítá schopného webdevelopera, o pracovních podmínkách více v zmiňovaném starším příspěvku na Jabloku, případné životopisy prosím na pavel.kolesnikov zavináč gmail.com).

A pokud je to pro vás potěšující novinka, taky dobře.

Tagged with: ,

Dalších par ukázek z Javy 5

Zasláno do Java by Pavel Kolesnikov na Duben 21st, 2005

Co třeba takovýto (svou jednoduchostí už na úrovni skriptovacích jazyků) kód vypisující řádky textového souboru:

TextFile textfile = new TextFile(new File(f), "UTF-8");
int lineNumber = 0;
for(String line : textfile) {
   System.out.printf("%6d: %s%n", ++lineNumber, line)
}

Tento příklad a povídání o dalších vybraných novinkách “Tygří” javy najdete v článku Davida Flanagan na OnJava.com nazvaném Five Favorite Features from 5.0

.

Tagged with: , , ,

JBoss + Xdoclet + Unknown primary key + CMR relation = ?

Zasláno do Java by Pavel Kolesnikov na Duben 6th, 2005

Za otazníkem v nadpisu se skrývá nejspíše něco jako “spousta zábavy”. Věc se má následovně:

EJB specifikace nám umožňuje ponechat na kontejneru vytváření primárních klíčů, a říká tomu “Unknown primary key” (bod 10.8.3). Co když se rozhodneme něco takového zkusit v praxi (s aplikačním serverem JBoss 4.0.1)?

Nejprve se popereme s implementací “neznámého” primárního klíče.

Člověk by řekl, že postačí v souladu se specifikací definovat návratový typ příslušé findByPrimaryKey metody jako java.lang.Object, stejný typ dát příslušnému CMP poli a navíc třídu i pole patřičně otagovat Xdocletem (u třídy @jboss.unknown-pk a @ejb.pk class = "java.lang.Object" generate = "false", u get metody pak @ejb:persistent-field, @ejb:pk-field a @ejb:interface-method view-type="local").

A houbeles — JBossův CMP plugin nerozpozná, že deklarovaný “unknown primary key” je totožný s deklarovaným CMP primárním klíčem, a tedy generuje dotazy jako insert into tabulka (pk field, pkfield, ...). Zkrátka vidí dva sloupce, od čehož se odvíjejí rozličná chybová hlášení, od pochopitelné stížnosti relační databáze na zdvojené jméno sloupce v insert dotazu, až po mysteriózní zamyšlení aplikačního serveru na téma nevhodnosti složených primárních klíčů ve scénáři “unknown primary key”.

Co s tím? Zlenivěn Xdocletem přeskakuji studium JBoss-specific deployment descriptoru (možná chyba ;)) a rovnou sahám po manuálu k Xdocletu. Nabízí pouze uvést JBoss specific tagem název databázového sloupce sloužícího jako PK, to pochopitelně dělám, ale JBoss si z toho (vcelku pochopitelně) souvislost neznámého klíče a specifikovaného CMP fieldu odvodit nedokáže. Navíc při generování SQL příkazu INSERT se snaží vkládat primární klíč coby null namísto toho, aby se o něm vůbec nezmiňoval.

Napadá mě CMP field pro primární klíč vypustit, a vida, najednou vše funguje. Primární klíč se stává opravdu doslova neznámým — v důsledku to znamená, že hodnotu klíče musím lovit přes ruku z EntityContextu získaného callback metodou, ale tím se trápit nebudeme.

Nicméně nyní nás čeká úkol číslo 2 — definovat mezi takovýmito entitami relaci.

Napohled nic těžkého, dokud si neuvědomíme, že v descriptoru aplikačního serveru musíme definovat propojovací sloupce — a nyní na nás dopadá důsledek předminulého odstavce: co je vlastně primárním klíčem, když jsme jeho CMP pole zavrhli?

Po marném Googlování a několika naivního pokusech cosi nastřelit nezbývá než využít dostupnosti zdrojových kódů JBosse a ladících možností Eclipse. Po pár breakpointech je situace jasná:

Vytvoříme-li “unknown primary key” výše popsaným způsobem, JBoss si interně zavede pole s názvem JménoBeany_upk.
Toto po chvíli úspěšně ověřuju na stránce JBossích odštěpenců z Core Developers Network

Uf.

Stále si říkám, že by nebylo od věci tam pole pro primání klíč zavést. Neustále se ale opakují problémy se zdvojenými poli v dotazu či nadbytečným uvádění primárního klíče v INSERT dotazu.

Takže výsledný kód je:

/**
* @ejb.bean name=&quot;Something&quot; type=&quot;CMP&quot; cmp-version=&quot;2.x&quot; view-type=&quot;local&quot;
* @jboss.entity-command name=&quot;postgresql-fetch-seq&quot;
*     class=&quot;org.jboss.ejb.plugins.cmp.jdbc.keygen.JDBCPostgreSQLCreateCommand&quot;
* @jboss.unknown-pk auto-increment = &quot;true&quot; column-name=&quot;somethingId&quot;
*     jdbc-type=&quot;INTEGER&quot; sql-type=&quot;INTEGER&quot;
*     class=&quot;java.lang.Integer&quot;
* @ejb.pk class = &quot;java.lang.Object&quot; generate = &quot;false&quot;
*/
public abstract class SomethingEJB implements EntityBean {

/**
* @ejb.interface-method view-type=&quot;local&quot;
* @ejb.relation name=&quot;Something_SomethingElse&quot;
*     role-name=&quot;something-has-somethingelse&quot;
*     target-ejb=&quot;SomethingElse&quot;
*     target-role-name=&quot;somethingelse-has-something &quot;
* @jboss.relation related-pk-field=&quot;SomethingElse<strong>_upk</strong>&quot;
*     fk-column=&quot;assignedSomethingElse&quot;
*/
public abstract LocalSomethingElse getSomethingElse ();

// other stuff comes here

}

(Jde o dvě entity beans — Something a SomethingElse, obě mají databází generovaný (a z pohledu EJB specifikace “unknown”) primární klíč. Pro jednoduchost jsem uvedl zdrojový kód pouze jedné z nich, která obsahuje jednosměrnou relaci getSomethingElse().)

Tagged with: , ,

Mozkom*d aneb Rozšiřme si obzory

Zasláno do Tech by Pavel Kolesnikov na Březen 21st, 2005
++++++++[>+++++++++<-]>.<+++++[>++++++<-]>-.+++++++..+++.<
++++++++[>>++++<<-]>>.<<++++[>------<-]>.<++++[>++++++<-]>
.+++.——.——–.>+.

Tak toto byl zdrojový kód programu Hello World v programovacím jazyce Brainfuck.

Na výše uvedené adrese najdete kompilátor (171 bajtů) a archív ukázek.

Půvabné.

(via komentář k dnešní glose Františka Fuky na Lupě)

Aktualizace

K dispozici je i multithreadová variace Brainfork, která zavádí operátor Y, a pokud vám to nestačí, jistě si vyberete v přehledu esoterických programovacích jazyků na Wikipedii.

Aktualizace č. 2

Whitespace taky stojí za pozornost ;)

Tagged with: ,

Anotace? Ano, ale s mírou

Zasláno do Java by Pavel Kolesnikov na Březen 20th, 2005

Na stránkách java.sun.com se objevil článek Anderse Holmgrena o tom, jak pomocí anotací deklarovat validační kritéria u Java Beans.

Přesněji řečeno, článek je cvičením z nových vlastností, které přináší Java 5, a tyto vlastnosti jsou demonstrovány na design patternu, kterým by používání anotací k ověřování hodnot mohlo být.

Pointu článku nejsnáze shrnu názornou ukázkou kódu:

public class Vehicle {
    private int speed;

    public int getSpeed () {
        return speed;
    }

    @MinValue(0)
    @MaxValue(29979245 8)
    public void setSpeed (int speed) {
        this.speed = speed;
    }
}

(tedy máme třídu vozítek a do kontrolní anotace údaje o maximální rychlosti uvedeme informaci, že nikdy nebude vyšší než je rychlost světla ve vakuu — a pro pořádek ani nižší než nula).

Toto se na pohled může zdát velmi elegantní — pryč s trapnými kontrolami platnosti, nechme kód dělat to podstatné, a otravnou omáčku nechme strojům… pardon, anotacím.

Elegantní?

Výhodou tohoto přístupu je bezesporu jistá "elegance" a úspora kódu. Nicméně domnívam se, že vždy, kdy jedinou výhodou nějakého řešení je úspora objemu kódu, je třeba zbystřit. V praxi se totiž ukazuje, že takováto elegance může vyjít velmi draho z důvodu snížené srozumitelnosti kódu, někdy dokonce i před autorem samotným — typickým přikladem je rozšiřováním funkcionalit prvků typu String či tříd z Collection frameworku děděním namísto dekorováním (viz jedna z 57 rad Joshuy Blocha) .

Z tohoto důvodu mi tento přístup přijde vhodný pro velmi jednoduché situace, jako je validace formulářů. Jeho použítí na úrovni doménového modelu může ale být cestou do pekel — případů užití je tam nepoměrně více a tedy je i nepoměrně více způsobů, kterak kreativnější člen týmu může tento nástroj nevhodně použít či přinejmenším zamlžit srozumitelnost jeho použítí.

Mimochodem na podobné téma se vzápětí objevil i článek Validating Objects Through Metadata, který už autor zcela jednoznačně cílí právě na validaci Struts formulářů.

Diskuse

Na zmíněný Holmgrenův článek jsem se dostal tradičně přes avízo na TSS, u nějž tradičně najdeme zajímavější diskusi než u vlastního odkazovaného článku (zde nemohu nezmínit odbočku na TSS parodii ze svérázných zápisků Haniho Suleimana).

Vlastní diskusi komentovat nebudu, za pozornost ale stojí skeptická zmínka ze světa, kde anotace už nějaký pátek fungují:

I have lived with annotations in .NET for several years and find it suprisingly hard to communicate its usage to team members and library users.

Pro zajímavost, dotyčný diskutující pokračoval následující poněkud technooptimistickou douškou:

I think annotations can be very useful, but the world is not ready, it seems.

Nemohu si pomoct, ale na dobré myšlenky, do nichž lidstvo ještě neuzrálo, tak nějak nevěřím. Většinou stačí nevidět v každé novince zlaté kladívko.

Offtopic — inzerát

Velmi kvalitní sníh (via ILblog).

Tagged with: ,

EJB 3.0 poprvé odhaleno

Zasláno do Java by Pavel Kolesnikov na Květen 10th, 2004

Na TheServerSide Symposiu bylo koncem minulého týdne s velkou slávou představeno, co pěkného nám přinese chystaná specifikace EJB 3.0.

Čas od času si neodpustím povzdech nad komplexností EJB, které programátory zahrnuje kvanty rozhraní, výjimek a kontraktů. Protože v tomto nejsem jediný, vzniká spousta "odlehčených" frameworků (Spring, Hibernate), které se snaží dělat věci lépe a radostněji. Jak jsem už avizoval ve zmínce o pražském Sun Tech Day, EJB 3.0 přináší značné odlehčení a přístup založený spíše na používání POJO než implementování či rozšiřování všemožných rozhraní.

Shrnuto jednou větou: EJB 3.0 se soustřeďuje především na usnadnění vývoje. Hodně změn se týká entity bean, rozšíří se možnosti EJB-QL.

EJB 3.0 už samozřejmě počítá s možnostmi Javy 1.5, zejména metadat. Díky bude zdrojový kód jednoduché session beany vypadat následovně:

@Session public class CalculatorBean {
    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }
}

A šmitec. Rozhraní Calculator vznikne samo od sebe, a deployment descriptoru netřeba (přinejmenším, pokud byste v něm nepotřebovali sdělit nic extra zajímavého).

A uživatele Spring frameworku jistě nepřekvapí "setterová" Dependency Injection, která nahrazuje vyhledávání zdrojů pomocí JNDI. A je-li vám termín "Dependency Injection" cizí, zkuste obsáhlý článek Martina Fowlera.

Vše nasvědčuje tomu, že EJB 3.0 potvrdí vizionářství JBossího týmu a zejména neúnavného a nekompromisního agitátora Marca Fleuryho.

Zdroje a doporučená četba:

Aktualizace:

K zajímavým zdrojům přidám ještě pár kontroverznějších komentářů od Hani Suleimana — aneb TSSS extrémně kritickým okem:

Tagged with: ,