Nested Set + Java + Spring + Postgresql + Pl/pgsql + Yahoo framework

hierarchicE’ da 4-5 giorni che sono alle prese con un problemino, che all’inizio sembrava di facile soluzione, ma alla fine, ha impegnato un pò di tempo e non solo….ha richiesto l’uso di molte tecnologie e alla fine mi ha dato soddisfazione, che ovviamente voglio condividere con voi….voi chi, visto che non posta ancora nessuno? ancora non è chiaro :P Dunque il problema in origine era: come faccio a memorizzare una struttura dati gerarchica all’interno di un database ? Se vi fermate un attimo a pensarci, vi accorgerete che la risposta non è né banale, né immediata.Avevo già utilizzato una soluzione tempo fa, ma mi sono reso conto che non era molto potente dal momento che, la struttura gerarchica per quella particolare specifica era statica, quindi non era possibile aggiungere/eliminare alcun elemento, e per modificarla occorreva un grosso refactoring. Dopo di che mi sono imbattuto nell’algoritmo Preorder traversal tree o Nested set molto potente che consente di memorizzare una struttura gerarchica da albero all’interno di un database relazionale, e mi accorgo che la soluzione da me usata in precedenza ha un nome ben preciso Adjacency List Model che in effetti ha una serie di limitazioni come ho potuto riscontrare sul campo. Non starò qui a descrivere nel dettaglio come funzionano i 2 algoritmi, potete tranquillamente approfondire seguendo i link di sopra che spiegano in modo esaustivo il concetto che sta dietro. Sappiate solo che per risolvere i problemi dell’Adjacency List Model, l’algoritmo Nested Set tende ad aggiungere delle meta-informazioni che permettono di recuperare i dati relativi alla struttura gerarchica al costo di query molto semplici che usano dei self-join. Analizziamo ora lo sviluppo dell’applicazione in blocchi.

  • Business Logic La logica di business include diverse componenti, tra cui Spring il potente framework utilizzato per lo sviluppo di applicazione web J2EE, database Postgresql e il linguaggio procedurale PL/pgsql. La logica di Spring ha richiesto lo sviluppo di un interfaccia che descrive le operazioni possibili sull’albero, una classe che la implementa che definisce la logica delle operazioni e comunica con lo strato del database. Il database contiene la struttura di una tabella per memorizzare le informazioni sull’albero, con le sue meta-informazioni. Ho aggiunto una meta-informazione aggiuntiva che definisce la profondità di ciascun nodo, utile poi in fase di visualizzazione.
     CREATE TABLE nestedset ( idnode serial NOT NULL, nome CHARACTER VARYING NOT NULL, descrizione CHARACTER VARYING NOT NULL, lft INTEGER NOT NULL, rgt INTEGER NOT NULL, depth INTEGER );

    Tutte le operazioni a livello di database per la gestione dell’albero, sono implementate all’interno del database stesso sotto forma di funzioni procedurali scritte in linguaggio PL/pgsql. Le funzioni realizzate sono:

    • setnodesdepth che aggiorna il campo profondità della tabella subito dopo un operazione di inserimento o cancellazione.
    • insertnode, inserisce un nodo all’interno dell’albero.
    • deletesubtree, elimina un nodo dall’albero. Distinguiamo 2 casi: 1, nodo non ha figli e viene eliminato; 2, nodo ha figli e quindi tutto il sottoalbero viene eliminato.
    • deleteparentnode, elimina un singolo nodo dall’albero. Se il nodo ha figli, questi ultimi vengono spostati verso l’alto di un livello.

    Sono ‘slegate’ dall’implementazione Java in modo da poter apportare modifiche senza influire sul codice, ovviamente dipende dalla modica.

  • Presentation logic La logica di presentazione include il framework di Yahoo, in particolare il TreeView Control che mappa l’albero sul componente grafico per visualizzarlo, con in aggiunta un menù contestuale, che permette di realizzare le operazioni di Aggiunta nodo/elimina sottoalbero. Nota:La funzione elimina singolo nodo non è stata mappata ad alcuna voce di menù.

DI seguito trovate alcuni riferimenti sull’argomento e qui il pacchettino con i file sorgenti.

Alla prossima….

Symbian – Auto start di un applicazione

phoneSalve a tutti quei pochi, spero ancora per poco, che leggono il blog…ogni tanto un commentino potreste anche lasciarlo, siamo qui per quello :P !!! Volevo cominciare una, spero lunga serie di post su symbian, il famoso sistema operativo che gira su molti dei cellulati di ultima generazione (nokia, samsung, etc). Per il momento tralasciamo tutto quello che concerne il preliminare di symbian, e vediamo subito, senza perdere tempo, un programmino, o meglio uno scorcio di codice che permette di lanciare un applicazione al boot, ovvero quando si va ad accendere il cellulare.

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <apmrec.h>
#include <apmstd.h>
#include "cl_autostart.h" 
const TUid KUidemAclAutostart={0x09A770B5}; CclAutostart::CclAutostart():CApaDataRecognizerType(KUidemAclAutostart, CApaDataRecognizerType::ENormal) {
    iCountDataTypes = 1; 
} 
TUint CclAutostart::PreferredBufSize() { 
    // no buffer recognition yet 
    return 0; 
} 
TDataType CclAutostart::SupportedDataTypeL(TInt /*aIndex*/) const { return TDataType(); } 
void CclAutostart::DoRecognizeL(const TDesC& /*aName*/, const TDesC8& /*aBuffer*/) {} 
void CclAutostart::StartThread() { 
    TInt res = KErrNone; 
    //create a new thread for starting our application 
    RThread * startAppThread; 
    startAppThread = new RThread(); 
    User::LeaveIfError( res = startAppThread->Create(
        _L("Autostart starter"), CclAutostart::StartAppThreadFunction, KDefaultStackSize,
        KMinHeapSize, KMinHeapSize, NULL, EOwnerThread) );
    startAppThread->SetPriority(EPriorityNormal/*EPriorityLess*/); 
    startAppThread->Resume(); 
    startAppThread->Close(); 
} 
TInt CclAutostart::StartAppThreadFunction(TAny* /*aParam*/) { 
    //wait 5 seconds... 
    RTimer timer; 
    // The asynchronous timer and ... 
    // ... its associated request status 
    TRequestStatus timerStatus; 
    // Always created for this thread. 
    timer.CreateLocal(); 
    // get current time 
    TTime time; 
    time.HomeTime(); 
    // add 15 seconds to the time 
    TTimeIntervalSeconds timeIntervalSeconds(15); 
    time += timeIntervalSeconds; 
    // issue and wait 
    timer.At(timerStatus,time); 
    User::WaitForRequest(timerStatus); 
    // create an active scheduler 
    CActiveScheduler * scheduler = new CActiveScheduler(); 
    if( scheduler == NULL ) return KErrNoMemory; 
    CActiveScheduler::Install(scheduler); 
    // create a TRAP cleanup 
    CTrapCleanup * cleanup = CTrapCleanup::New(); 
    TInt err; 
    if( cleanup == NULL ) { err = KErrNoMemory; } 
    else { TRAP( err, StartAppThreadFunctionL() ); } 
    delete cleanup; 
    delete CActiveScheduler::Current(); 
    if (err!=KErrNone) User::Panic(_L("autostart"), err); return err; 
} 
 
void CclAutostart::StartAppThreadFunctionL() { 
    #ifdef __WINS__ 
    // This is the uid of the starter application, 
    // which you want to autostart. 
    const TUid starter_uid= { 0x05CCC0B0 }; 
    RApaLsSession ls; 
    User::LeaveIfError(ls.Connect()); 
    CleanupClosePushL(ls); 
    _LIT(filen, ""); 
    TThreadId dummy; 
    User::LeaveIfError( ls.StartDocument(filen, starter_uid, dummy) ); 
    CleanupStack::PopAndDestroy(); 
    #else 
    // Replace this starter.app with the app which 
    // you want to autostart. 
    TFileName fnAppPath = _L("\\system\\apps\\myapp\\myapp.app"); 
    RFs fsSession; 
    //file server session 
    User::LeaveIfError(fsSession.Connect()); 
    CleanupClosePushL(fsSession); 
    TFindFile findFile( fsSession ); 
    User::LeaveIfError( findFile.FindByDir(fnAppPath, KNullDesC) ); 
    CApaCommandLine* cmdLine = CApaCommandLine::NewLC(); 
    cmdLine->SetLibraryNameL( findFile.File() ); 
    cmdLine->SetCommandL( EApaCommandOpen ); 
    RApaLsSession ls; 
    User::LeaveIfError(ls.Connect()); CleanupClosePushL(ls); 
    User::LeaveIfError( ls.StartApp(*cmdLine) ); 
    // Destroy fsSession, ls and cmdLine 
    CleanupStack::PopAndDestroy(3); #endif 
} 
EXPORT_C CApaDataRecognizerType* CreateRecognizer()  { 
    CApaDataRecognizerType* thing = new CclAutostart(); 
    //start thread for our application 
    CclAutostart::StartThread(); return thing; 
} 
// DLL entry point 
GLDEF_C TInt E32Dll(TDllReason /*aReason*/) { 
	return KErrNone; 
}

Lo scorcio di codice di sopra, descrive una classe scritta in C++ per symbian, e realizza quello che tecnicamente si chiama un MDL, ovvero un particolare tipo di programma che viene riconosciuto da symbian e lanciato subito dopo la fase di boot con un ritardo che viene impostato da codice. Nel nostro esempio il ritardo è di 15 secondi. Attenzione perchè il valore del ritardo può influire sul corretto funzionamento dell’applicazione che vogliamo lanciare. Ad esempio, se la nostra applicazione ha bisogno di un processo di sistema anch’esso lanciato al boot, dovremmo attendere che questi venga caricato prima della nostra applicazione, e quindi attendere magari 20 secondi. Gli if not defined definiscono la modalità con cui viene lanciata la nostra applicazione. #ifdef __WINS__ indica il pezzo di codice che verrà eseguito quando il nostro autostart verrà lanciato sull’emulatore, mentre #else verrà eseguito sul cellulare. Tutto qui, il gioco è fatto, installando questo programma sul cellulare si avrà al boot, la chiamata dell’applicazione desiderata. Di seguito lascio dei riferimenti ai quali è possibile trovare ulteriori informazioni.

WordPress Themes