Jak rozchodit subreporty na JasperServeru

Každý report v napsaný v JasperReport / navržených v editoru iReport může obsahovat pouze jeden jediný zdrojový dotaz pro získání dat — definovaný v elementu <queryString>. V některých případech potřebujete získat data pomocí dvou či více dotazů. V takových případech si s jediným reportem nevystačíte — pro tento účel jsou k dispozici subreporty složící pro vložení jiných reportů do hlavní šablony. Jednoduše připojíte jiný JRXML soubor, předáte spojení, parametry, … Pokud reporty nahráváte na JasperServer, situace se trochu komplikuje o správné nastavení cesty k druhé šabloně.

Jak se pracuje s JasperServerem, jsem představil v dřívějším tutorialu (anglicky). Pro ilustraci budeme potřeboval dva reporty: hlavní, MainReport.jrxml, generující tabulku dat, a doplňkový, SubReport.jrxml, ve kterém se bude zobrazovat jeden řádek s nějakou hodnotou získanou z databáze. Reporty samozřejmě mají své parametry, nastavení a lze je spouštět v editoru samostatně. Na server je nahrajeme z iReport pomocí JS pluginu — zvolíme složku, kde je chce umístit, klikneme pravým a pomocí Add > Report Unit nahrajeme hlavní report, resp. Add > JRXML Document šablonu subreportu, protože ho nebudeme pouštět samostatně, ale vkládat do hlavního reportu.

Máme–li obě šablony nahrané na server, otevřeme JRXML soubor hlavního reportu. Pro vložení druhé šablony použijeme tlačítko Subreport z hlavní lišty a někde v report, třeba v sekci <title> nastavíme prostor pro vykreslení. Objeví se průvodce pro vytvoření. Zvolíme Just create the subreport element (Vytvořit pouze element subreport) a potvrdíme; jeho atributy nastavíme ve vlastnostech: V záložce Subreport musíme předně nastavit spojení k databázi. V roletce Connection/Data Source Expression zvolíme Use connection expression a jako výraz zadáme $P{REPORT_CONNECTION}. Tím se přenese datové spojení použité pro hlavní report. Další důležitou záložkou je Subreport (Other), kde nastavíme cestu k šabloně subreportu. Jako Subreport Expression Class (třídu výrazu) nastavíme java.lang.String a jako samotný Subreport Expression (výraz subreportu) zadáme absolutní cestu k šabloně a důležitý je i pseudo–protokol „repo“. Máme–li šablonu uloženou na JasperServeru v složkách “(Kořen) / Subreports”, pak bude výraz vypadat následovně (také uvozovky jsou důležité, protože se jedná o zápis řetězce v syntaxi jazyka Java):

"repo:/Subreports/SubReport.jrxml"

Nyní by se výsledek ze subreportu měl objevit přímo v hlavním reportu.

JasperServer Input Controls pro volbu více hodnot

Dříve či později při vývoji reportů nad JasperServer narazíte na požadavek, aby parametry a vstupní prvky dovolovaly zvolit více jak jednu hodnotu. Typicky je třeba prvek, kde se volí právě jeden prvek, jeden a nebo všechny, a nebo jeden až všechny. Samozřejmě, že vstupní prvky by měly mít hodnoty naplněné z databáze, což jsem popsal nedávno.

Dnes popíšu, jak vytvořit vstupní prvek s možností volby různého počtu hodnot. Základem je definice parametru. Stačí v iReport editoru, v panelu Struktura dokumentu (Document structure) kliknout pravým tlačítkem na Parametry (Parameters) a Add… > Parameter. Důležité je nastavit datový typ java.util.Collection.

V JasperServeru pak definujeme příslušný vstupní prvek, která musí umožňovat volbu více hodnot. Máme-li k dispozici hotový Dotaz (Query) v JasperServeru pro získání hodnot, v panelu JS-Plugin 3.0 zvolíme dialog Add > Input Control a vybereme typ Multi–Select Query a vyplníme ostatní parametry stejně jako u Single–Select Query. Vstupní prvek přiřadíme do reportu (Report Unit).

Poslední a nejdůležitější je použít parametr v reportu. Jelikož hodnot může být různý počet, v dotazu použijeme omezující podmínku WHERE table.attr IN(…). Klasické parametry s jednou hodnotou zapisujeme pomocí $P{ParameterName}. Pro parametry s více hodnotami existuje speciální zápis – $X{IN, table.attr, ParameterName}, který vygeneruje celou podmínku v dotazu. Místo IN můžete použít také NOTIN, pokud chcete vygenerovat klauzulin NOT IN(…).

Vstupní prvek se zobrazí jako selectbox s více zobrazenými hodnotami, kde můžete i více hodnot zvolit.

Lineární grafy v JasperReports / iReports

Moje práce na reportech a JasperServeru pro jejich správu pokračuje i nadále. Aktuálně jsem řešil problém, jak správně vytvořil lineární graf (Line Chart) v editoru iReports. Kde byl problém? Byly dokonce dva. První se týkal správného umístění elementu grafu v JRXML šabloně, druhý zadání zdrojových políček z dotazu. Druhý ze zdrojů uváděl, že do libovolné části šablony, která se neopakuje. Po spuštění reportu, kdy se mi vygeneroval graf na tolik stránek, kolik bylo řádků zdrojových dat, jsem pochopil, že to nepůjde do libovolného elementu. Tutoriál ke grafům v iReports dal správnou odpověď — graf umístěte do elementu <summary>. Řešení, jak nastavit zdrojová pole, jsem našel na Java Lobby. Máme-li dotaz:

SELECT
  workstatus.time AS DATE_TIME,
  workstatus.active_projects_count AS PROJECT_COUNT
FROM workstatus
WHERE workstatus.time BETWEEN $P{VALID_FROM} AND $P{VALID_TO}
ORDER BY workstatus.time ASC

Můžeme nastavit graf tímto způsobem:

  • Výraz pro sérii: název jedné linie v grafu, např. "Počet aktivních projektů"
  • Výraz pro kategorii: Osa X, $F{DATE_TIME}
  • Hodnota výrazu: Osa Y, $F{PROJECT_COUNT}

Graf se vykreslí v horizontální orientaci, kde na ose X budou data, na ose Y počty projektů a pod grafem v legendě název tohoto datového zdroje. Do grafu lze samozřejmě zadat více datových setů a mít více přímek.

Dynamické Input Controls na JasperServeru

Pokud jste někdy řešili úkol tvorby reportů, určitě jste při hledání vhodné technologie neopomenuli prohlédnout nebo dokonce použili JasperReports. Tento framework poskytuje flexibilní šablonovací nástroj založený na vlasním XML formátu, který navíc můžete navrhnout v grafickém WYSIWYG editoru iReport od stejných tvůrců. Škála výstupních formátů je širová – hlavně PDF a XLS budou zajímavé. Pokud se chcete o nástroji dozvědět více, doporučuji krátké představení nástroje a integrace se Springu od Vlasty Vávrů nebo tutorial z ČVUT.

Minulý týden jsem řešil přípravu několika reportů nad Oracle databází. Výhodou bylo, že máme nainstalovaný JasperServer – ten slouží k hostování, správě, automatizovanému spouštění reportů a správě vygenerovaných reportů. Pro editor iReport je vytvořen předinstalovaný plug–in, kterým můžete server spravovat. Stačí přidat adresu a přihlašovací údaje, do widgetu se vám načte kompletní obsah, se kterým můžete manipulovat a vlatní šablony přímo v editoru upravovat. Co nepřidalo na jednoduchosti, byl požadavek na vstupní parametry. Např. volba jedné ze stavů faktury, či omezení časového intervalu. Protože mě to stálo minimálně den pátrání, popíšu, jak vytvořit na JasperServeru znovupoužitelné vstupní komponenty, jejichž výčet hodnot se načítá z databáze.

Základem je mít v šabloně reportu vytvořené vstupní parametry. Jméno vstupní komponenty se musí se jménem parametru shodovat! Máte–li šablonu hotovou, můžete připravit vstupní komponenty. Pro naplnění komponenty daty potřebujete Query (dotaz). Nabídku Add > Query najdete po pravém kliku na některou složku v JS plug–inu. Záložka General vyžaduje vyplnit Name (ID komponenty) a Label (libovolný popisek pro orientaci na JasperServeru). Záložka Query poskytuje volby pro vlastní získání dat. Je třeba zvolit dotazovací jazyk (např. SQL, EJBQL, HQL či XPath), najít již definované spojení na datový zdroj (databázi) a zadat vlastní dotaz.

Máte–li definovaný Dotaz, můžete vytvořit vlastní vstupní komponentu. Dialog najdete pod Add > Input Control. Ze zajímavých voleb uvedu Type, který je třeba nastavit na Single Select Query, dále najít na JasperServeru námi definovaný dotaz a pak, Value Column určuje jméno sloupce s hodnotou. Naopak Visible Query Columns sloupce, které budou v roletce zobrazeny.

Když vytvoříte všechny potřebné komponenty, otevřete si strukturu vašeho reportu (Report Unit) a všechny postupně připojte přes volbu Link an Existing Input Control (pravý klik na Input Controls). V této chvíli jsou již nabízený v komponentách správné hodnoty a report je pak se zvolenými hodnotami předanými přes parametry spuštěn a vygenerován.

JSON notace pro RDF

RDF, jako klíčová technologie sémantického Webu, umožňuje zápis informací a jejich výměnu. Data jsou zapisována jako trojice (předmět, predikát a objekt) a dohromady pak tvoří graf. Výhodou pak je, že existuje mnoho notací, jak graf zapsat. Nejznámější je určitě RDF/XML nebo třeba Notation 3. Mezi ty méně známé pak jistě patří RDF/JSON vytvářený skupinou Talis. Nabízí se srovnání se dvěma jmenovanými – „výřečností“ může konkurovat XML notaci, ba ji i předčit, ale někdy se může podpora v JSONu hodit. Krátká ukázka N3 a RDF/JSON pro porovnání:

<http://example.org/about>
  <http://purl.org/dc/elements/1.1/title>
  "About page" .
{
  "http://example.org/about": 
  {
    "http://purl.org/dc/elements/1.1/title":
    [
      {
        "type": "literal",
        "value": "About page"
      }
    ]
  }
}

I tuto notaci používá dříve zmiňovaný projekt OpenVocab pro management ontologií.

Projekt OpenVocab pro sémantický Web

Na informace o projektu OpenVocab jsem narazil nedávno a už představení jeho současných i plánovaných funkcí mne zaujalo. O co jde? Sémantický Web je založen zejména na strojově čitelných datech a jejich výměně. Ty musí být kódovaný použitím nějakého schématu (RDFS) či lépe ontologie (OWL). Existuje mnoho „standardů“ jako FOAF, DOAP, Dublin Core… V některých případech ale potřebujete vytvořit vlastní koncepty (třídy) či atributy. Pak máte na výběr buď vytvořit jejich popis v některé z notací RDF (obvykle RDF/XML), přemýšlet nad tvarem URIref jednotlivých konceptů a následně vše publikovat, a nebo je zde právě OpenVocab.

Ve zkratce se jedná o kolaborativní hosting a tvorbu pojmů z ontologií, kdy data lze tvořit, sdílet a upravovat v rámci otevřeného systému. Ten pak poskytuje unifikovaný tvar adres, koncepty jsou zpřístupněny jako Linked Data a také v rozličných formátech – RDF, XHTML, JSON, Turtle. Linked Data znamená, že každá URIref (URL adresa) označující termín vrací na požadavky hlavičku HTTP 303 See Other a přesměrování na jinou prezentační verzi s informacemi o tomto konceptu. A to podle preferencí agenta (obvykle RDF pro stroje a XHTML pro prohlížeče).

Technicky, data jsou uložena v RDF úložišti Talis Platform a jsou přístupná přes SPARQL. Zdrojové kódy a dokumentaci projektu najdete na Google Code. Projekt navazuje na původní vocab.org, který pouze poskytoval prostor a neměnnou doménu pro různé ontologie, ale posunuje celou ideu dál. Zajímalo by mne, jestli autor bude ontologie publikované na vocab.org migrovat do nového systému.

Nekompletní podpora SPARQL OPTIONAL v PHP frameworcích

Během práce na komunitní stránce Knowledge Engineering Group, která je kompletně implementována nad RDF úložištěm, jsem narazil na jeden problém s nekompatibilitou se standardem SPARQL. Používali jsme framework RDF API for PHP, což je téměř zažitý standard pro PHP aplikace pracující s RDF. Nyní popíšu náš případ užití. Měli jsme v úložišti několik instancí typu foaf:Group; některé měly jeden atribut foaf:name, jehož hodnotou bylo jméno v anglickém jazyce a jiné měly dva atributy foaf:name, jeden v angličtině a druhý v češtině. Jedním dotazem jsme chtěli zvolit obě jména a zobrazit je v XHTML editoru. SPARQL dotaz vypadal následovně:

PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?group ?nameEn ?nameCs
WHERE {
  ?group rdf:type foaf:Group .
  ?group foaf:name ?nameEn .
  OPTIONAL {
    ?group foaf:name ?nameCs .
    FILTER (lang(?nameCs) = "cs") 
  }
  FILTER (lang(?nameEn) = "en")
}

Když jsem však spustil dotaz vůči databázovému úložišti RAP, dostal jsem chybný výsledek dotazu – ten obsahoval pouze zdroje, které měly obě dvě jména. Dvě hodiny jsem opravoval dotaz, než mi Aristo potvrdil, že je správně. Navíc, služba OpenLink Virtuoso hostovaná na DBpedii vrátila korektní výsledek. Protože se zdá, že RAP je zmražený projekt, rozhodli jsme se migrovat náš kód z RAPu na ARC2 s očekáváním, že tento dotaz bez chyb spustíme a získáme správný výsledek. Bohužel, přepis kódu do ARCu náš problém nevyřešil. Po znovu spuštění skriptu jsme dostali jiný, avšak opět nesprávný výsledek. Toto nás donutilo prozatím vypustit česká jména z naší implementace a hledat zdroj či vysvětlení potíží. Alespoň stručnou odpověď jsme získali z přehledového reportu implementací SPARQLu od W3C. RAP ani ARC nepodporují 100% OPTIONAL promněnné. Navíc, z nejznámějších RDF frameworků má kompletní podporu pro SPARQL pouze Jena a Sesame2. ARC budeme používat v dalším vývoji a doufat, že podpora SPARQLu bude někdy kompletní…