musica rock | ----------------------------------------------------------------------- | | | | | | origini rock and roll garage rock surf rock hard rock heavy metal | | | ------------- | | | rockabilly folk metal grungeSi noti che, essendo le keywords organizzate in una gerarchia, il significato di una keyword non dipende solamente dal suo nome ma anche dalla posizione che occupa nella gerarchia. Ad esempio, la nostra gerarchia potrebbe comprendere anche la musica jazz:
musica | ---------------------------------------- | | musica rock musica jazz | | -------------- . . . ------------------------------------------ | | | | | | | origini . . . origini ragtime swing bebop free jazzLa keyword
orgini
appare sia nella sottogerarchia della keyword musica rock
che in quella della keyword musica jazz
, ovviamente, con significati diversi. Nel primo caso
significa le origini della musica rock e nel secondo caso significa le origini della musica jazz.
Grazie alla gerarchia alcuni nomi di keywords possono essere abbreviati. Ad esempio, siccome
sia musica rock
che musica jazz
sono nella gerarchia di musica
,
potrebbero essere denominate semplicemente rock
e jazz
. Il vantaggio principale
apportato dall'organizzazione gerarchica delle keywords sta nel fatto che se a un documento D è
associata, ad esempio, la keyword grunge
e si effettua una ricerca relativamente
a heavy metal
allora sarà recuperato automaticamente anche il documento D
(anche se il documento non ha specificatamente associata la keyword heavy metal
). In generale,
questo permette una classificazione più accurata e nel contempo una maggiore facilità e
flessibilità nell'esprimere condizioni di ricerca tramite le keywords.
KB
che si trova nella
sottogerarchia di un'altra keyword KA
è una sub-keyword di KA
e
KA
è una super-keyword di KB
. Ad esempio, grunge
è
una sub-keyword di heavy metal
e anche di rock
e musica
,
inoltre, rock
, musica
e heavy metal
sono super-keywords
di grunge
. Se KA
è una super-keyword di KB
e non ci sono
altre keywords tra KA
e KB
allora diremo che KA
è una
super-keyword diretta di KB
e che KB
è una
sub-keyword diretta di KA
. Ad esempio heavy metal
è una
super-keyword diretta di grunge
e grunge
è una sub-keyword diretta
di heavy metal
, ma rock
è una super-keyword di grunge
che non è una super-keyword diretta di grunge
.
ANYTHING
. Per semplicità assumeremo che la gerarchia sia pura, cioè,
per ogni keyword K
(diversa da ANYTHING
) c'è esattamente una e
una sola keyword che è una super-keyword diretta di K
.
In generale, per specificare una keyword non è sufficiente specificare solamente il nome è
necessario specificare anche la sua posizione nella gerarchia.
Ogni keyword può essere specificata senza ambiguità mediante
la sequenza di tutti i nomi delle sue super-keywords, tali sequenze saranno chiamate path-keywords.
Ad esempio, il path-keyword di grunge
è musica>rock>heavy metal>grunge
,
i path-keywords delle due keywords di nome orgini
sono musica>rock>origini
e
musica>jazz>origini
(nei path-keywords la keyword speciale ANYTHING
è
sempre sottointesa). Si conviene di usare il carattere '>'
per separare i nomi delle
keywords.
origini
avranno codici differenti. Tali codici saranno del tutto trasparenti
all'utente e serviranno solamente per la gestione interna delle keywords e delle loro associazioni ai
documenti. L'associazione delle keywords è gestita tramite una Classificazione: una mappa che
assegna ad ogni documento, appartenente ad un certo insieme di documenti, una lista (eventualmente
vuota) di keywords appartenenti ad una certa gerarchia. L'applicazione gestirà una
sola Classificazione alla volta, la Classificazione corrente. Parimenti, gestirà una sola
gerarchia di keywords alla volta, la gerarchia corrente che generalmente sarà la
gerarchia associata alla Classificazione corrente. Le funzionalità
che l'applicazione dovrà realizzare sono specificate nel seguente elenco.
ANYTHING
. Sarà creato un file per mantenere la gerarchia
il cui pathname è specificato dall'utente.
K
, sia K
che !K
sono EBK, più precisamente,
sono EBK atomiche;
K
(la keyword è negata) allora
è sostituita con false se e solo se o K
appartiene all'insieme S
o c'è una keyword K'
in S tale che K'
è una
sub-keyword di K
;
K
allora è sostituita con
true se e solo se o K
appartiene all'insieme S o c'è una keyword
K'
in S tale che K'
è o una super-keyword di K
o una sub-keyword di K
.
K
o con una path-keyword o
semplicemente con il nome della keyword. In quest'ultimo caso, ci possono essere più keywords che
hanno lo stesso nome allora se K
non è negata il valore booleano corrispondente sarà true se è
true rispetto ad una delle keywords che hanno quel nome, se invece K
è negata
allora il valore booleano corrispondente sarà false se è
false rispetto a una delle keywords che hanno quel nome. Consideriamo, ad esempio, le
seguenti EBK:
E = ((origini & (musica>jazz>ragtime | rock and roll)) & !heavy metal) F = ((heavy metal | !bebop) & !origini) G = (!musica>jazz>origini & heavy metal)Supponiamo che i documenti nella Classificazione abbiano le seguenti keywords:
D1 musica>jazz D2 musica>rock D3 musica>rock>rock and roll>rockabilly, musica>jazz>origini D4 musica>rock>origini, musica>rock>heavy metal>folk metal D5 musica>jazz, musica>rock>heavy metal>grungeAllora E seleziona i documenti D1, D2 e D3, l'espressione F seleziona i documenti D1, D2 e D5 e l'espressione G seleziona D2, D4 e D5.
AWT
e Swing
). Nel primo caso bisognerà realizzare
opportuni menu e sotto-menu testuali.
KeywordHierarchy
che rispetta il contratto qui di seguito specificato.
L'intera implementazione della classe deve essere contenuta nel package
metodologie.progetto.kh
. Nell'implementazione della classe non si possono aggiungere
o rimuovere membri pubblici (campi, metodi e costruttori). Si possono invece aggiungere membri
privati o con accessibilità ristretta al package.
public class KeywordHierarchy
Questa classe gestisce gerarchie di keywords mantenute su files che obbediscono ad uno specifico formato.
I nomi delle keywords sono stringhe non vuote di qualsiasi
lunghezza e composte da caratteri appartenenti all'insieme
{'a','b',...,'z','A','B',...'Z','0','1',...,'9','-','_',' '}
(cioè,
caratteri alfabetici minuscoli e maiuscoli, cifre, trattino, underscore e spazio).
I nomi delle keywords non sono sensibili alla capitalizzazione e non possono
iniziare né terminare con un carattere spazio.
Ad ogni keyword è assegnato un codice univoco di CODELENGTH
caratteri appartenenti all'insieme {'a','b',...,'z','A','B',...'Z','0','1',...,'9'}
(se CODELENGTH
= 6 ci sono più di 56 miliardi di codici possibili).
La keyword speciale ANYTHING
ha sempre il codice 00...0
.
Una gerarchia di keywords è mantenuta in un file di testo (gestito
quindi tramite accesso sequenziale) che ha la seguente struttura. Il nome del file
deve essere name.KWH
dove name
è
il nome della gerarchia.
La prima linea del file contiene l'identificatore della gerarchia di keywords che
è la stringa KEYWORD_HIERARCHY:name:N
dove name
è il nome della gerarchia e N
è il numero di nanosecondi ritornato dal metodo System.nanoTime()
nel momento in cui il file della gerarchia è creato. La seconda linea contiene
lastcode
che è l'ultimo codice di keyword usato nella gerarchia.
Dopo le prime due linee, per ogni keyword (eccetto la keyword speciale ANYTHING
)
c'è una linea con il seguente formato:
code;K;supercode
dove code
è il codice della keyword, K
è il nome della
keyword e supercode
è il codice della super-keyword diretta.
Queste informazioni sono sufficienti per ricostruire l'intera gerarchia.
Field Summary | |
---|---|
static int |
CODELENGTH
La lunghezza dei codici delle keywords. |
static char |
PATHSEP
Carattere usato come separatore nei path-keywords. |
Constructor Summary | |
---|---|
KeywordHierarchy(String dir,
String name)
Apre una gerarchia di keywords o ne crea una nuova. |
Method Summary | |
---|---|
String |
add(String supercode,
String kName)
Aggiunge una nuova keyword alla gerarchia. |
void |
close()
Chiude la gerarchia di keywords. |
String[] |
codeFromName(String kName)
Ritorna in un array i codici delle keywords che hanno nome kName . |
String |
codeFromPath(String pathK)
Ritorna il codice della keyword specificata dal path-keyword pathK . |
String |
getID()
Ritorna l'identficatore di questa gerarchia di keywords. |
boolean |
isSub(String subcode,
String code)
Ritorna true se la keyword di codice subcode
è uguale o è una sub-keyword della keyword di codice code . |
boolean |
isSuper(String supercode,
String code)
Ritorna true se la keyword di codice supercode
è uguale o è una super-keyword della keyword di codice code . |
String |
name(String code)
Ritorna il nome della keyword che ha codice code . |
String |
path(String code)
Ritorna il path-keyword della keyword che ha codice code . |
boolean |
replaceName(String code,
String kName)
Sostituisce il nome della keyword di codice code con kName e ritorna
true . |
String[] |
subK(String code)
Ritorna in un array i codici delle keywords che sono sub-keywords dirette della keyword con codice code . |
String |
superK(String code)
Ritorna il codice della super-keyword diretta della keyword di codice code . |
Methods inherited from class Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
---|
public static final int CODELENGTH
6
.
public static final char PATHSEP
'>'
.
Constructor Detail |
---|
public KeywordHierarchy(String dir, String name) throws java.io.FileNotFoundException
name
e il file si trova nella directory
di pathname dir
.
dir
- il pathname di una directoryname
- il nome di una gerarchia di keywords
FileNotFoundException
- se il file non è accessibile.
IllegalArgumentException
- se il file non è compatibile con
la struttura di un file che contiene una gerarchia di keywords.
Method Detail |
---|
public String getID()
KEYWORD_HIERARCHY:name:N
dove name
è il nome della gerarchia e N
è il numero di nanosecondi ritornato dal metodo System.nanoTime()
nel momento in cui il file della gerarchia è creato. L'identificatore è
registrato nel file della gerarchia.
public String (String pathK)
pathK
.
Se non è presente ritorna null
.
pathK
- un path-keyword.
null
.public String[] codeFromName(String kName)
kName
.
Se non ci sono keyword con quel nome ritorna un array di lunghezza 0.
kName
- un nome di keyword.
public String path(String code)
code
.
Se non ci sono keyword con quel codice ritorna null
.
code
- il codice di una keyword.
null
.public String name(String code)
code
.
Se non ci sono keywords con quel codice ritorna null
.
code
- il codice di una keyword
null
.public String superK(String code)
code
.
Se non ci sono keywords con quel codice ritorna null
.
code
- il codice di una keyword.
null
.public String[] subK(String code)
code
. Se non ci sono sub-keywords, ritorna
un array di lunghezza 0 e se non ci sono keywords con codice code
, ritorna
null
.
code
- il codice di una keyword.
null
.public boolean isSub(String subcode, String code)
true
se la keyword di codice subcode
è uguale o è una sub-keyword della keyword di codice code
.
Altrimenti ritorna false
, anche quando uno dei codici è errato.
subcode
- il codice di una keyword.code
- il codice di una keyword.
true
o false
.public boolean isSuper(String supercode, String code)
true
se la keyword di codice supercode
è uguale o è una super-keyword della keyword di codice code
.
Altrimenti ritorna false
, anche quando uno dei codici è errato.
supercode
- il codice di una keyword.code
- il codice di una keyword.
true
o false
.public String add(String supercode, String kName)
kName
ed è aggiunta come sub-keyword diretta della
keyword di codice supercode
. Ritorna il codice assegnato alla
nuova keyword. Se l'operazione non può essere effettuata (perché supercode
non esiste o kName
non è un nome ammissibile o esiste già
una sub-keyword diretta della keyword supercode
con quello stesso nome),
allora ritorna null
.
supercode
- il codice della super-keyword diretta.kName
- il nome della nuova keyword.
null
.public boolean replaceName(String code, String kName)
code
con kName
e ritorna
true
. Se l'operazione fallisce (perché o non esistono keyword con quel codice,
o il nuovo nome non è ammissibile o il nuovo nome coincide con quello di un'altra keyword che
è una sub-keyword diretta della stessa super-keyword diretta della keyword di codice code
),
allora ritorna false
,
code
- il codice di una keyword.kName
- il nuovo nome della keyword.
true
o, se fallisce, false
.public void close()
IllegalStateException
.
Classification
che rispetta il contratto qui di seguito specificato. L'intera implementazione della classe deve essere
contenuta nel package metodologie.progetto.classif
. Nell'implementazione della classe non si possono aggiungere o rimuovere membri pubblici (campi, metodi e costruttori). Si possono invece aggiungere membri privati o con accessibilità ristretta al package.
public class Classification
Questa classe gestisce Classificazioni che sono matenute in files che
obbediscono a un opportuno formato. La classe opera in congiunzione con la classe
metodologie.progetto.kh.KeywordHierarchy
. La natura degli elementi
di una Classificazione non è specificata (possono essere files, siti web, oggetti
fisici come libri o dvd, ecc.). Ogni elemento è identificato da una stringa
chiamata appunto l'identificatore dell'elemento (se gli elementi sono files
l'identificatore potrebbe essere il pathname, se sono siti web potrebbe essere
l'URL, se sono libri l'identificatore potrebbe essere la collocazione).
Siccome gli identificatori possono essere stringhe piuttosto lunghe
e in vista di possibili estensioni che permettano di gestire anche link tra elementi,
conviene assegnare ad ogni elemento un codice, ovviamente univoco.
Il codice è composto da CODELENGTH
caratteri appartenenti all'insieme
{'a','b',...,'z','A','B',...'Z','0','1',...,'9'}
.
Una Classificazione è mantenuta in due files. Il file degli elementi con nome
name.ELM
e il file delle keywords
con nome name.KYW
.
La stringa name
deve essere comune ad entrambi i files e rappresenta
il nome della Classificazione. Entrambi i files sono di tipo testo e quindi sono
gestiti tramite accesso sequenziale. La struttura del file degli elementi è la
seguente. La prima linea contiene CLASSIFICATION:name:N
, dove
name è il nome della Classificazione e
N
è il numero di nanosecondi ritornato dal metodo System.nanoTime()
nel momento in cui la Classificazione è creata. La seconda linea contiene
lastcode
che è l'ultimo codice usato per gli elementi della
Classificazione. Poi c'è una linea per ogni elemento contenente
code;ID
, dove code
è il
codice dell'elemento e ID
è l'identificatore dell'elemento.
La struttura del file delle keywords è la seguente. La prima linea contiene
CLASSIFICATION_KEYWORDS:name:N
,
dove name
è il nome della Classificazione N
è il numero di nanosecondi mantenuto nel file degli elementi. La seconda linea
contiene l'identificatore della gerarchia di keywords usata (cioè la stringa ritornata
dal metodo getID()
della classe metodologie.progetto.kh.KeywordHierarchy
).
Poi per ogni elemento che ha almeno una keyword associata c'è una linea contenente
code;K1;K2;...KN
, dove code
è il codice dell'elemento e K1
, K1
,...,
KN
sono i codici delle keywords associate all'elemento.
Field Summary | |
---|---|
static int |
CODELENGTH
La lunghezza dei codici degli elementi. |
Constructor Summary | |
---|---|
Classification(String dir,
String name,
KeywordHierarchy kh)
Apre una Classificazione o ne crea una nuova. |
Method Summary | |
---|---|
String |
add(String id)
Aggiunge alla Classificazione un nuovo elemento. |
boolean |
addKeyword(String code,
String kCode)
Associa ad un elemento una nuova keyword. |
void |
close()
Chiude la Classificazione. |
String |
code(String id)
Ritorna il codice dell'elemento con identificatore id . |
String |
id(String code)
Ritorna l'identificatore dell'elemento di codice code . |
java.util.Iterator<String> |
iterator()
Ritorna un iteratore sui codici degli elementi. |
String[] |
keywords(String code)
Ritorna in un array i codici delle keywords associate all'elemento di codice code . |
boolean |
removeKeyword(String code,
String kCode)
Rimuove la keyword di codice kCode dalle keywords associate
all'elemento di codice code . |
Methods inherited from class Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
---|
public static final int CODELENGTH
6
.
Constructor Detail |
---|
public Classification(String dir, String name, KeywordHierarchy kh) throws java.io.FileNotFoundException
name
e i files si trovano nella directory
di pathname dir
. La Classificazione usa la gerarchia di keyword kh
.
dir
- il pathname di una directory.name
- il nome di una Classificazione.kh
- una gerarchia di keyword.
FileNotFoundException
- se uno dei files coinvolti non è accessibile.
IllegalArgumentException
- se kh
è null
o
uno dei files non è compatibile con la struttura di un file di una Classificazione o
la gerarchia di keywords non è compatibile con la Classificazione (ad esempio l'identificatore
della gerarchia è differente da quello riportato nel file delle keywords).
Method Detail |
---|
public String code(String id)
id
. Se non c'è
nessun elemento con quell'identificatore ritorna null
.
id
- l'identificatore di un elemento.
null
.public String id(String code)
code
. Se non c'è
nessun elemento con quel codice ritorna null
.
code
- il codice di un elemento
null
.public java.util.Iterator<String> iterator()
Iterator<String>
ritornato permette di
scorrere i codici di tutti gli elementi della Classificazione (anche quelli
che non hanno keywords associate).
iterator
in interface Iterable<String>
public String[] keywords(String code)
code
. Se L'elemento non ha keywords associate ritorna un array di lunghezza
0. Se l'elemento non esiste ritorna null
.
code
- il codice di un elemento.
null
.public String add(String id)
id
. Ritorna il codice assegnato all'elemento.
Se c'è già un elemento con
quel identificatore, allora non aggiunge l'elemento e ritorna null
.
id
- l'identficatore di un nuovo elemento.
null
.public boolean addKeyword(String code, String kCode)
code
e il codice della keyword è kCode
.
Se l'operazione ha successo ritorna true
. Se la keyword era già
stata associata all'elemento o uno dei codici è errato ritorna false
.
code
- il codice di un elemento.kCode
- il codice di una keyword.
true
se l'operazione ha successo, false
altrimenti.public boolean removeKeyword(String code, String kCode)
kCode
dalle keywords associate
all'elemento di codice code
. Se l'operazione ha successo
ritorna true
. Se la
keyword non è presente o uno dei codici è errato, ritorna false
.
code
- il codice di un elemento.kCode
- il codice di una keyword.
true
se l'operazione ha successo, false
altrimenti.public void close()
IllegalStateException
.
StrBoolExpr
e dell'interfaccia SBEAtom
. L'intera implementazione
della classe StrBoolExpr
deve essere contenuta nel package metodologie.progetto.sbe
.
Per potenziare le possibilità di riuso ed estensione del codice la valutazione di una EBK
è stata divisa in due parti: la parte che riguarda la valutazione delle EBK atomiche
(interfaccia SBEAtom
) e la parte che riguarda la valutazione dell'espressone booleana,
dopo che le espressioni atomiche sono state valutate (classe StrBoolExpr
).
Inoltre, sia l'interfaccia che la classe sono state pensate per la valutazione di espressioni più
generali delle EBK che sono state chiamate SBE (String Boolean Expression). Le SBE sono definite nella
documentazione della classe StrBoolExpr
. La connessione tra EBK e SBE è spiegata
nei dettagli alla fine di questa sezione.
public interface SBEAtom
Interfaccia per oggetti che implementano la valutazione delle SBE atomiche.
Method Summary | |
---|---|
boolean |
check(String atom)
Ritorna true se la stringa atom contiene
una SBE atomica ammissibile. |
boolean |
eval(String atom)
Ritorna il valore booleano della SBE atomica atom . |
Method Detail |
---|
boolean check(String atom)
true
se la stringa atom
contiene
una SBE atomica ammissibile. Altrimenti ritorna true
.
atom
- una stringa.
true
se è una SBE atomica ammissibile.boolean eval(String atom)
atom
.
Se non è una SBE atomica ammissibile lancia l'eccezione
IllegalArgumentException
.
atom
- una stringa.
IllegalArgumentException
- se non è una SBE atomica ammissibile.public class StrBoolExpr
Questa classe permette di valutare String Boolean Expressions, in breve SBE.
Le SBE possono essere definite induttivamente:
'('
,
')'
, '&'
, '|'
e che non inizia né termina
con il carattere spazio è una SBE atomica;
Constructor Summary | |
---|---|
StrBoolExpr(String expr,
SBEAtom atom)
Crea un oggetto relativo alla (presunta) SBE nella stringa expr e
il valutatore di SBE atomiche atom . |
Method Summary | |
---|---|
int |
check()
Fa un controllo sintattico della espressione dell'oggetto: parentesi, operatori, espressioni atomiche. |
boolean |
eval()
Ritorna il valore della SBE. |
Methods inherited from class Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructor Detail |
---|
public StrBoolExpr(String expr, SBEAtom atom)
expr
e
il valutatore di SBE atomiche atom
.
expr
- una stringa contenente una (presunta) SBE.atom
- un valutatore di SBE atomiche.Method Detail |
---|
public int check()
public boolean eval()
IllegalStateException
- se l'SBE non è corretta.SBEAtom
è
possibile realizzare un valutatore di EBK atomiche che in congiunzione con una implementazione
della classe StrBoolExpr
permetterà di valutare una qualsiasi EBK.
Si noti che l'implementazione della classe StrBoolExpr
non dipende dal
particolare tipo di SBE (EBK, variazioni di EBK o altro). Solamente la classe che
realizza un valutatore di SBE atomiche dipende dalle specificità
di tali espressioni.
musica rock | ----------------------------------------------------------------------- | | | | | | origini rock and roll garage rock surf rock hard rock heavy metal | | | ------------- | | | rockabilly folk metal grungeL'utente potrebbe voler aggiungere una keyword
1950-60
per classificare anche
in termini cronologici i vari stili della musica rock. Allora l'applicazione deve permettere
di fare ciò, trasformando la gerarchia precedente in quella qui sotto:
musica rock | ----------------------------------------------------------------------- | | | | origini 1950-60 hard rock heavy metal | | -------------------------------- ------------- | | | | | rock and roll garage rock surf rock folk metal grungeQuindi la nuova keyword è stata inserita come sub-keyword diretta di
musica rock
e alcune sub-keywords dirette di quest'ultima sono ora diventate sub-keyword dirette della nuova
keyword.
KeywordHierarchy
:
public String insert(String supercode, String kName String...subs)
kName
, è inserita come sub-keyword diretta della
keyword di codice supercode
e le keywords i cui codici sono elencati in subs
diventano sub-keywords dirette della nuova keyword. Ritorna il codice assegnato alla
nuova keyword. Se l'operazione non può essere effettuata, ritorna null
.
Le ragioni che possono causare il fallimento dell'operazioni sono le seguenti:
supercode
non esiste;
kName
non è un nome ammissibile;
supercode
che ha
nome kName
;
subs
non sono codici di sub-keyword dirette
della keyword supercode
.
supercode
- il codice della super-keyword diretta.
kName
- il nome della nuova keyword.
subs
- l'elenco dei codici delle sub-keywords dirette.
null
.Classification
:
public static Classification merge(String dir, String name, Classification c1, Classification c2)
c1
e
c2
. Il nome della nuova Classificazione è name
e i relativi
files sono creati nella directory di pathname dir
. Ritorna il riferimento alla nuova Classificazione. Le due Classificazioni devono
usare la stessa gerarchia di keywords che sarà anche la gerarchia usata dalla nuova
Classificazione. Nella nuova Classificazione sono inseriti tutti gli elementi appartenenti
alle due Classificazioni e le relative associazioni di keywords. Se ci sono due elementi uguali
(cioè, con lo stesso identificatore) nelle due Classificazioni allora la lista delle keywords
associata all'elemento nella nuova Classificazione è l'unione delle due liste (ovviamente,
senza ripetizioni). Se l'operazione fallisce ritorna null
.
dir
- il pathname di una directory.
name
- il nome della nuova Classificazione.
c1
- una Classificazione.
c2
- un'altra Classificazione.
null
.