Obiettivo: fornire una definizione di un macro-linguaggio e il parsing di esso in un oggetto.
Questo pattern è particolarmente indicato quando si vuole costruire un parser di stringhe personalizzato, tradurre una specifica espressione o gestire un'informazione strutturata ad albero.
Nel nostro esempio useremo il design pattern Interpreter per definire un parser di una stringa che definisce codice pseudo-sql. Nel listato, per focalizzare l'attenzione sul pattern in esame e quindi definire un codice snello, faremo uso anche dei pattern Visit e Iterator.
Questo pattern è particolarmente indicato quando si vuole costruire un parser di stringhe personalizzato, tradurre una specifica espressione o gestire un'informazione strutturata ad albero.
Nel nostro esempio useremo il design pattern Interpreter per definire un parser di una stringa che definisce codice pseudo-sql. Nel listato, per focalizzare l'attenzione sul pattern in esame e quindi definire un codice snello, faremo uso anche dei pattern Visit e Iterator.
package designPatterns.interpreter.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
String source = "attributes='id',table='users',"+
"conditions='username\"root\" and password=\"mypwd\"'";
String delimiter = "=,'";
Parser parser = new Parser(source, delimiter);
parser.myParser();
parser.interpret();
String result = parser.getInterpretedResult();
System.out.println(result);
}
}
class Parser{
private String expression;
private String delimitator;
private List result;
private String interpreted;
public Parser(String e, String t) {
expression = e;
delimitator = t;
}
public void myParser() {
StringTokenizer holder = new StringTokenizer(expression, delimitator);
String[] toBeMatched = new String[holder.countTokens()];
int idx = 0;
while(holder.hasMoreTokens()) {
String item = holder.nextToken();
int start = item.indexOf(",");
if(start==0) {
item = item.substring(2);
}
toBeMatched[idx] = item;
idx ++;
}
result = Arrays.asList(toBeMatched);
}
public List getParseResult() {
return result;
}
public void interpret() {
StringBuffer buffer = new StringBuffer();
ListIterator list = result.listIterator();
while (list.hasNext()){
String token = (String)list.next();
if (token.equals("attributes")){
token = "SELECT";
}else if(token.equals("table")) {
token = "FROM";
}else if(token.equals("conditions")) {
token = "WHERE";
}
buffer.append(" " + token);
}
interpreted = buffer.toString();
}
public String getInterpretedResult() {
return interpreted;
}
}
Un esempio molto più concreto di applicazione del pattern Interpreter è dato dal parsing di una query scritta in linguaggio EJB-QL nell'ambito dello sviluppo JEE. Come noto una query di ricerca scritta in tale linguaggio non è altro che una stringa ma il risultato della sua esecuzione, mediante l'utilizzo delle API che gestiscono la persistenza con un database, è un vero e proprio oggetto o una collezione di tali oggetti omogenei. Nel seguente listato viene illustrata una semplificazione del parser che, data una query ejb-ql, restituisce una collezione di oggetti (che saranno poi gli Entity Bean deputati a gestire la persistenza delle informazioni elaborate in un'applicazione enterprise con un database).
package designPatterns.interpreter;
import java.util.*;
public class Main {
public static void main(String[] args)
throws NotWellFormedSimpleQuery {
//String to parse
String queryString = "FROM interpreter.MyEntity";
SimpleEJBQueryParser queryParser =
new SimpleEJBQueryParser(queryString);
//interpret String and cast result
List<MyEntity> resultList =
(List<MyEntity>) queryParser.getResultList();
Iterator it = resultList.iterator();
while(it.hasNext()){
MyEntity tmp = (MyEntity)it.next();
System.out.println(tmp.getId()+"-"+tmp.getValue());
}
}
}
class MyEntity{
private Integer id;
private String value;
public MyEntity(){}
public MyEntity(Integer id, String value) {
this.id = id;
this.value = value;
}
public void setId(Integer id) {
this.id = id;
}
public void setValue(String value) {
this.value = value;
}
public Integer getId() {
return id;
}
public String getValue() {
return value;
}
}
class SimpleEJBQueryParser{
private Class entityClass;
private String tableName;
private List resultList;
public SimpleEJBQueryParser(String query)
throws NotWellFormedSimpleQuery{
StringTokenizer st = new StringTokenizer(query);
if(!st.nextToken(" ").trim().equals("FROM"))
throw new NotWellFormedSimpleQuery();
tableName = st.nextToken(" ");
try {
entityClass = Class.forName(tableName);
} catch (ClassNotFoundException ex) {
throw new NotWellFormedSimpleQuery(ex.toString());
}
}
public List getResultList(){
buildResultList();
return resultList;
}
private void buildResultList(){
resultList = new ArrayList();
Object obj = null;
try {
obj = entityClass.newInstance();
} catch (Exception ex) {
System.out.println(ex.toString());
}
if(obj instanceof MyEntity){
MyEntity tmp = (MyEntity)obj;
/*populate MyEntity directly or setting values
/*from database table MyEntity for examle:*/
tmp.setId(1);
tmp.setValue("ciao");
}
resultList.add(obj);
}
}
class NotWellFormedSimpleQuery extends Exception {
public NotWellFormedSimpleQuery(){
super("The simple query is not well formed");
}
public NotWellFormedSimpleQuery(String msg){
super(msg);
}
}
Nessun commento:
Posta un commento