sobota 31. ledna 2015

Uložení AST jako grafu

Popis uložení AST do grafu sestává ze seznamu vrcholů, hran a vlastností k jednotlivým vrcholům. Protože bude využit framework Frames, je nutno zapsat popis vrcholů do jednotlivých rozhraní.
V kódu bude před název každého vrcholu (uvedeného v závorkách) přiložen symbol "I" pro jednodušší oddělení ostatních tříd či rozhraní.

Vrcholy grafu:
  • Objekt (Object)
    • Třída (CLASS)
      • Rozhraní (IF)
      • Anonymní třída (C_ANONYM)
      • Vnitřní třída (C_INNER)
      • Datový typ (DATT)
      • Generický typ (GENT)
      • Typový parametr (TYPE_PAR) (pouze jeden svého druhu)
      • Pole (FIELD)
      • Výčet prvků (ENUM)
      • Anotace (ANOT)
      • Anotační typ (IF_ANOT)
    • Atribut (ATTR)
    • Metoda (METH)
      • Konstruktor (METH_CON)
    • Parametr (PAR)
    • Hodnota (VALUE)
Pro větší jednoduchost a přehlednost implementace bude využito dědění rozhraní. Dostaneme tak například možnost zacházet s třídami stejně jako s rozhraním, generickým typem, polem a dalšími. Užitečnost využití bude zejména při dotazování, kdy například při dotazu na datový typ elementu může být výsledkem třída, rozhraní, anonymní třída, datový typ, generický typ, pole nebo výčet prvků.

Popis vrcholů

Objekt

Vlastnosti:
  • name (String)
  • ObjectType (o který typ vrholu se jedná)
Vztahy:
  • have_annotation (Anotace)

Třída
Dědíme vše od vrcholu Objekt.
Obsah stejný s rozhraním, vnitřní třídou, anonymní třídou, datovým typem, generickým datovým typem, polem, výčtem, typovým parametrem, anotací a anotačním typem.

Vlastnosti:
  • static (yes/no)
  • abstract (yes/no)
  • final (yes/no)
  • anonym (yes/no)
  • inner (yes/no)
  • access (public/private/protected)
  • package (String) 
  • strictfp (yes/no)
Vztahy:
  • extends (Třída)
  • uses (Třída)
  • implements (Rozhraní)
  • have_inner (Vnitřní třída)
  • have_anonym (Anonymní třída)
  • have_method (Metoda)
  • have_attribute (Atribut)
  • have_element (Hodnota)
  • main_type (Třída)
  • generic_parameter (Třída)


Atribut
Dědí od vrcholu Objekt.

Vlasnosti:
  • static (yes/no)
  • final (yes/no)
  • access (public/private/protected)
  • transient (yes/no)
  • volatile (yes/no)
Vztahy:
  • is_type (Třída)


Metoda
Dědí od vrcholu Objekt.
Obsah stejný jako konstruktor.

Vlastnosti:
  • static (yes/no)
  • final (yes/no)
  • access (public/private/protected)
  • abstract (yes/no)
  • synchronized (yes/no) 
  • native (yes/no)
  • strictfp (yes/no)
Vztahy:
  • is_type (Třída)
  • have_parameters (Parametr)
  • call (Metoda)
  • uses (Třída)
  • throws (Třída)
  • call_throws (Metoda)
  • catch (Třída)


Parametr
Také dědí od vrcholu Objekt.

Vlastnosti:
  • final (yes/no)
  • position (int)
Vztahy:
  • is_type (Třída)

Hodnota
Dědí od vrcholu Objekt.

Vlastnosti:
  • value (String)
Vztahy:
  • is_value_of (Metoda)

Zdroje:
https://github.com/tinkerpop/frames/wiki

    neděle 28. prosince 2014

    BCEL

    Zkratka BCEL značí slovní spojení Byte Code Engeneering Library, tedy se jedná o knihovnu pro práci s bytekódem. Tato knihovna je vyvíjena společností The Apache Software Foundation a taktéž spadá pod licenci Apache 2.0

    Balík BCEL není určený pro plnou dekompilaci kódu. Jeho účel je majoritně zaměřený na modifikaci již zkompilovaného kódu (bytekódu). Při zpracování však dává k dispozici tyto informace:

    • Název třídy
    • Název souboru
    • Název balíku
    • Název rodičovské třídy
    • Příznaky třídy
    • Názvy implementovaných rozhraní
    • Seznam atributů třídy (název, datový typ)
    • Seznam metod třídy (název, datový typ návratové hodnoty, datové typy parametrů)

    Nevýhodou tohoto balíku je možnost zpracování pouze souborů .class, tedy nikoliv .jar a omezené množství poskytovaných informací. Na druhou stranu je doba zpracování velice krátká (jednotky sekund) na rozdíl od dekompilace pomocí balíku Procyon.



    Zdroje:
    http://commons.apache.org/proper/commons-bcel/
    http://greg-dip.blogspot.cz/2014/11/bcel-vypis.html

    sobota 27. prosince 2014

    Procyon

    Balík Procyon je open source projekt vyvíjený pod licencí Apache 2.0. Vývoj započal koncem roku 2012 hlavním vývojářem Mikem Strobelem. Domovské stránky s možností stažení zdrojových kódů, drobným popisem a návodem lze nalézt na adrese https://bitbucket.org/mstrobel/procyon.

    Procyon je balík nástrojů pro generování a analýzu zdrojového kódu. Hlavní části (knihovny) jsou Core framework, Reflection framework, Expression framework, Compiler toolset a Java decompiler.

    Je nutno podotknout, že dekompilace je poměrně náročná operace a vyžaduje hodně vypočetního času procesoru. Dekompilace velkého projektu může na průměrném stroji trvat několik jednotek až desítek minut.

    Použití


    Pokud je stažen již zkompilovaný procyon-decompiler.jar , lze si spuštěním tohoto programu vypsat nápovědu:

    java -jar procyon-decompiler.jar -?

    Nebo je možné se rovnou pokusit dekompilovat nejaký soubor. Pro vyzkoušení funkčnosti lze vyzkoušet dekompilovat standardní knihovny javy jako například java.lang.String. Soubor pro dekompilaci se zadává jako parametr programu.

    java -jar procyon-decompiler.jar java.lang.String

    V případě použití dekompilátoru v terminálech, které neposkytují obarvení textu (vyznačení syntaxe) bude uživatel značně ochuzen. Proto se doporučují terminály s možností zabarvování textu a pokud přesto detekce ANSI selže, je možné toto vynutit přidáním argumentu -DAnsi=true.

    java -DAnsi=true -jar procyon-decompiler.jar java.lang.String

    Balík Procyon umožňuje také dekompilaci celých .jar souborů. K tomu je potřeba přidat dekompilátoru argumet -jar, oznamující typ přícozího souboru a dále je možné si výsledek uložit do vybraného umístění.

    java -jar procyon-decompiler.jar -jar soub.jar -o out

     

    Decompiler API


    Tolik k použití již hotového řešení dekompilace. Dále se podíváme na způsob použití balíku Procyon v kódu. V kódu je totiž potřeba Decompiler API, které však obsahuje pouze dvě metody.


    public static void decompile(
        final String internalName, 
        final ITextOutput output
    );
    
    public static void decompile(
        final String internalName, 
        final ITextOutput output
        final DecompilerSettings settings
    );
    

    Prvním parametrem funkce decompile je proměnná typu String, která požaduje v textovém tvaru identifikaci souboru pro dekompilaci. Identifikace může být definována buď adresou v souborovém systému nebo adresu v Java notaci k standardní knihovně (např.: java.lang.String). Druhý parametr je výstup metody v datovém typu ITextOutput, který je definován v rámci balíku Procyon. Poslední parametr je volitelný a je jím možno nastavit některé parametry dekompilace. V následujícím příkladu lze vidět jednoduché použití této funkce s výstupem na terminál.



    final DecompilerSettings settings = DecompilerSettings.javaDefaults();
    
    try (final FileOutputStream stream = new FileOutputStream("path/to/file");
         final OutputStreamWriter writer = new OutputStreamWriter(stream)) {
    
        Decompiler.decompile(
            "java/lang/String",
            new PlainTextOutput(writer),
            settings
        );
    }
    catch (final IOException e) {
        // handle error
    }
    




    Zdroje:
    https://bitbucket.org/mstrobel/procyon
    https://bitbucket.org/mstrobel/procyon/wiki/Java%20Decompiler
    https://bitbucket.org/mstrobel/procyon/wiki/Decompiler%20API

    Titan

    Tato knihovna pro grafové databáze je implementována v jazyce Clojure. Jazyk Clojure je dialekt jazyka Lisp. Domovskou stránkou knihovny Titan je http://thinkaurelius.github.io/titan/. Titan je šířený jako open source projekt a spadá pod licenci Apache 2.0. Pro ovládání databáze vytvořené pomocí knihovny Titan není vytvořen speciální databázový jazyk, jako je tomu u Neo4J. Grafová knihovna Titan umožňuje použití několika úložných beck-endů. Lze zde využít databáze Apache Cassandra, Apache HBase nebo Oracle BerkeleyDB.

    Databázi můžeme ovládat pomocí přiložené aplikace, která využívá grafového dotazovacího jazyka Gremlin nebo pomocí Blueprints. Blueprints je uváděno jako standard API grafových databází.

    Gremlin

    Spuštěním následujícího příkazu se spustí terminál Gregmlin, ve kterém je již možné spouštět dotazy a příkazy ve stejnojmenném dotazovacím jazyce.

    ./bin/gramlin.sh
    Dále, pro připojení k databázi a případnému vytvoření databáze, je nutné zadat adresu ke konfiguračnímu souboru. Příazy jsou připojení databáze a k ukončení připojení jsou následující:

    g=TitanFactory.open('/directory/file')
    g.shutdown()
    Podrobný popis tvorby konfiguračního souboru lze nalézt ve složce conf stažené knihovny Titan, kde je to popsáno v souboru titan-cassandra-es.properties. Jednoduchým příkladem funkční konfigurace může být následující text tohoto konfiguračního souboru:

    storage.backend=berkeleyje
    storage.directory=db/berkeley
    index.search.backend=elasticsearch
    index.search.directory=db/es
    index.search.elasticsearch.client-only=false
    index.search.elasticsearch.local-mode=true
    Klíčovou informací z configuračního souboru je použití úložného back-endu, který je v tomto případě BerkleyDB (berkeleyje).

    Pro vytvoření vrcholu se použije funkce addVertex() a následně se vrcholu funkcí setProperty() nastaví požadované vlastnosti.

    prom1 = g.addVertex()
    prom1.setProperty('name','Jirka')
    K vytvoření hrany se potom použije funkce addEdge(), kde se spojí například hrana prom1 a prom2 a nastaví se typ resp. popisek. Dále je samozřejmě zase možné dát hraně další vlastnosti podobně jako vrcholu.

    g.addEdge(null,prom1,prom2,'KNOWS')

    Jednudochý dotaz může vypadat následovně, kdy se grafové databáze ptáme na vrchol, který má vlastnost name s hodnotou "Jirka"

     g.V.has('name','Jirka')

    Blueprint API

    Aplikaci Gremlin a tento standard API vyvíjí stejná skupina lidí (TinkerPop), díky tomu je použití Blueprint v Javě velice podobné příkazům v aplikaci Gremlin. Zpracování databáze je zde transakční, proto je vhodné operace nad databází uzavírat do klauzule pro odchytávání vyjímek a po ukončení bloku příkazů zakončit příkazem shutdown().

    Za zmínku už zde stojí asi jen fakt, že proměnná g, která se používala i v aplikaci Gremlin (zde má stejný význam) je datového typu TitanGraph, vrcholy vytvořené funkcí addVertex() jsou datového typu Vertex a hrany jsou typu Edge.



    1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    import com.thinkaurelius.titan.core.TitanFactory;
    import com.thinkaurelius.titan.core.TitanGraph;
    import com.tinkerpop.blueprints.*;
    
    
    public class test {
    
     public static void main(String[] args) {
      
      TitanGraph g = TitanFactory.open("/home/greg/Plocha/experiment/soub");
      
      Vertex oz = g.addVertex(null);  
      oz.setProperty("name", "Jiri Bilek");  
      oz.setProperty("age", "24");  
        
      Vertex sz = g.addVertex(null);  
      sz.setProperty("name", "Tatka Bilek");  
        
      Edge e = g.addEdge( null, sz, oz, "parent");
      
      g.commit();
      
      
      if (g.getVertices("name", (Object)"Jiri Bilek").iterator().hasNext())
       System.out.println("Jiri Bilek is "+g.getVertices("name", (Object)"Jiri Bilek").iterator().next().getProperty("age")+" years old");
      else
       System.out.println("Zadny Jiri Bilek v databazi neni");
      
      
      g.shutdown();
     }
    
    }
    


    Zdroje:
    http://www.tinkerpop.com/
    http://s3.thinkaurelius.com/docs/titan/0.5.0/
    http://titanium.clojurewerkz.org/articles/getting_started.html
    http://thinkaurelius.github.io/titan/
    http://euranova.eu/upl_docs/publications/an-empirical-comparison-of-graph-databases.pdf
    http://clojure.org/

    pátek 26. prosince 2014

    Neo4J

    Knihovna pro práci s grafovýni databázemi Neo4J je implementována v programovacím jazyce Java. Tato grafová knihovna využívá dotazovacího jazyka Cipher a její domovká stránka je na adrese http://neo4j.com/. Na těchto stránkach je taktéž k dispozici stažení knihovny určené pro komunitu a tedy zdarma pod licencí Apache 2.0. Neo4J je možné získat i v komerční verzi.

    Používat grafovou knihovnu Neo4J lze několika způsoby. Jedním ze způsobů je spuštění databázového serveru používání pomocí prohlížeče (viz Cipher). Další možností je Java API.

    Cipher


    Po stažení balíku s databází lze spustit následující příkaz, který spustí databázový server:
     ./bin/neo4j console
    Následně lze v prohlížeči navštívit stránku http://localhost:7474/, kde je k dispozici manuál, rychlý tutoriál a hlavně příkazová řádka pro příkazy (dotazy) v jazyce Cipher.

    Jazyk Cipher je deklarativního typu. Jeho syntace byla pro větší intuitivnost inspirována jazykem relačních databází databází SQL. Tímto jazykem se nezadávají příkazy způsobem "jak chci hledat", ale "co chci najít".

    Vytvoření hrany:
    CREATE (ee:Person { name: "Emil", from: "Sweden" })
    Tímto příkazem bude pomocí jazyka Cipher v databázi vytvořena hrana označená jako "Person". Tato hrana bude mít vlastnosti name s hodnotou Emil a from s hodnotou Sweden.

    Tvorba hran:

    MATCH (ee:Person) WHERE ee.name = "Emil"
    MATCH (ef:Person) WHERE ef.name = "Franta"
    CREATE (ee)-[:KNOWS {since:1989}]->(ef)
    Zde jsem si vyhledal vrchol s vlastností name, která má hodnotu "Emil" a uložil jsem si tento vrchol do proměnné ee. Podobně do proměnné ef jsem vložil vrchol s vlastností name, které má hodnotu "Franta" a následně vytvořil vztah s typem KNOWS a vlastností since s hodnotou "1989".

    Dotaz na Emila a jeho známé:

    MATCH (ee:Person)-[:KNOWS]-(friends)
    WHERE ee.name = "Franta" RETURN ee, friends
    Díky tohoto dotazu je možné vyhledat všechny uzly, které mají vztah s uzlem, který má vlastnost name s hodnotou "Franta". Dalším specifikem musí být typ vztahu KNOWS. Dále se vykreslí příp. vypíše výsledek příkazu, který je možné vidět na následujícím obrázku.




    Java API

    Pro vytvoření databáze Neo4J s využitím Java API je potřeba vytvořit instanci třídy GraphDatabaseService. Vytvoření databáze tak i spustí databázový server. Při instanciaci je potřeba zadat parametr, který značí adresu v souborovém systému k úložišti. Např:. 


    1
    private static final String DB_PATH = "/home/greg/Plocha/test-data";
    



    Vytvoření databáze a spuštění databázového serveru se potom provádí takto:


    1
    GraphDatabaseService graphDb = new GraphDatabaseFactory().newEmbeddedDatabase( DB_PATH );
    


    Následující příkaz potom náš databázový server zase ukončí.


    1
    graphDb.shutdown();
    


    Veškerá manipulace s databází probíha v transakcích a proto je potřeba po každé takovéto transakci zadat příkaz pro potvrzení transakce. Navíc je nutné tuto manipulaci s ukončovacím potvrzením kvůli možným chybám uzavřít do klauzule pro odchytávání vyjímek.


    1
    2
    3
    4
    5
    try ( Transaction tx = graphDb.beginTx() )
    {
        // Database operations go here
        tx.success();
    }
    

     
    Vytvoření vrcholu a hrany je potom vidět až na komplexnějším příkladu. Dále přikládám funkční jednoduchý příklad, který vytvoří dva vrcholy, mezi nimi jednu hranu a následně vypíše hodnotu jedné vlastnosti každého tohoto elementu.


    1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    package priklady;
    
    import org.neo4j.graphdb.*;
    import org.neo4j.graphdb.factory.GraphDatabaseFactory;
    
    public class priklady {
    
     /**
      * @param args
      */
     private static enum RelTypes implements RelationshipType
     {
         KNOWS,
         UNKNOWS;
     }
    
     private static final String DB_PATH = "/home/greg/Plocha/test-data";
     
     public static void main(String[] args) {
      
      GraphDatabaseService graphDb;
      Node firstNode;
      Node secondNode;
      Relationship relationship;
    
      graphDb = new GraphDatabaseFactory().newEmbeddedDatabase( DB_PATH );
      registerShutdownHook( graphDb );
      
      try ( Transaction tx = graphDb.beginTx() )
      {
       //create data
       firstNode = graphDb.createNode();
       firstNode.setProperty( "message", "Hello, " );
       secondNode = graphDb.createNode();
       secondNode.setProperty( "message", "World!" );
    
       relationship = firstNode.createRelationshipTo( secondNode, RelTypes.KNOWS );
       relationship.setProperty( "message", "brave Neo4j " );
       
       // select data
       System.out.print( firstNode.getProperty( "message" ) );
       System.out.print( relationship.getProperty( "message" ) );
       System.out.print( secondNode.getProperty( "message" ) );
       
       
       // let's remove the data
       firstNode.getSingleRelationship( RelTypes.KNOWS, Direction.OUTGOING ).delete();
       firstNode.delete();
       secondNode.delete();
       
       
          // Database operations go here
          tx.success();
      }
      
      graphDb.shutdown();
     }
    
     private static void registerShutdownHook(GraphDatabaseService graphDb) {
      // TODO Auto-generated method stub
      
     }
    
    }
    



    Zdroje:
    http://neo4j.com/
    http://neo4j.com/developer/cypher-query-language/
    http://neo4j.com/docs/stable/tutorials.html
    http://neo4j.com/docs/stable/tutorials-java-embedded-hello-world.html

    Grafové databáze


    Databázový konzept označovaný zkratkou NoSQL (často vysvětlován jako "no only SQL" [1]) je specifický svým alternativním přístupem k ukládání dat a dotazováním nad nimi. S daty se nepracuje jako v klasických relačních databázích (tedy v tabulkách). Možným příkladem jsou grafové databáze, kde jsou data uložena v orientovaných grafech.

    Grafové databáze využívají následujících 3 stavebních bloků
    • vrchol
    • hrana
    • vlastnost

    Vrchol grafu (node) představuje záznamy databáze. Například vrchol 1 a 2 v následujícím obrázku. Hrany (relationships) představují vztahy mezi vrcholy v databázi. Nutným parametrem hrany je směr a typ. Podle následujícího obrázku je tak zřejmé, že vrchol 1 je ve vztahu s vrcholem 2. Tento vztah je otypován jako PART_OF, tedy objekt zastoupený záznamem vrchol 1 je pravděpodobně součástí jiného objektu zastoupeného záznamem vrchol 2. Posledním stavebním blokem je vlastnost (property). Lze takto blíže specifikovat jak vrchol, tak i hranu. Dle následujícího příkladu je tak už snadno pochopitelné, že vrchol 1, tedy kolo (wheel) je součástí vrcholu 1, tedy auta (které je mimochodem červené barvy) a že tyto součásti jsou hned 4 (number=4).

    Stavební bloky grafové databáze [2]


    Výhodou grafových databází je přirozený popis dat s podobnou strukturou. Příkladem může být mapování struktury objektově orientovaných aplikací bez pevně stanoveného schématu [1]. Dalším častým využitím grafových databazí je popis vztahů mezi lidmi (facebook, google+). Z následujícího komplexnějšího příkladu lze vyčíst, že se Alice a Bob znají (obousměrný vztah) a že oba jsou členové skupiny šachových hráčů.
    Příklad grafové databáze [3]



    Zdroje:
    [1] https://otik.uk.zcu.cz/bitstream/handle/11025/7596/diplomova_prace.pdf?sequence=1
    [2] http://www.infoq.com/articles/graph-nosql-neo4j
    [3] http://en.wikipedia.org/wiki/Graph_database

    úterý 23. prosince 2014