2011-03-16 3 views
7

Uso il GroovyShell come "motore di valutazione espressioni" all'interno del mio programma. Accetta due input: (a) uno o più script di init (b) script definito dall'utente. Entrambi vengono quindi concatenati in fase di esecuzione come una grande porzione di script (testo) e vengono inviati alla shell.Utilizzo di GroovyShell come "motore di valutazione espressioni" (o: Come riutilizzare GroovyShell)

String initScripts = getFromDB() 
String userScript = getFromUser() 

def shell = new GroovyShell() 
output = shell.evaluate(initScripts + userScript) 

Il codice precedente verrà eseguito in un ciclo, dove il contenuto di userScript varieranno.

Finora, initScripts contengono solo definizioni di variabili (ad esempio def $yyyy = new Date().format('yyyy')) che potrebbe essere fatto riferimento nel userScript (ad esempio print "$yyyy 001").

Esiste un approccio più efficiente per questo? (Ad esempio, riutilizzando il guscio, come?) Perché adesso è molto lento.

Modifica: Groovy è un must. Si prega di non raccomandare altri motori di scripting.

Edit: Sto pensando se GroovyShell può fare questo (pseudo-codice):

def shell = new GroovyShell() 
shell.evaluate(initScripts) 

for each userScript in DB { 
    shell.put(userScript) 
    def result = shell.evaluateThat() 
    println "Result is $result" 
} 

è possibile? (L'ultima volta che ho cercato su Google non è possibile, ma spero di sbagliarmi)

risposta

7

È possibile memorizzare nella cache il GroovyShell, non è necessario creare uno nuovo sempre:

final static GroovyShell shell = new GroovyShell() 

anche se si esegue uno script molte volte si può memorizzare nella cache anche loro. È possibile creare un Script con GroovyShell.parse(String scriptText), utilizzare Script.run() per eseguire lo script.

This section della documentazione potrebbe aiutare anche, invece di script è anche possibile creare dinamici oggetti groovy.

+1

GroovyShell è stateless e thread safe? Alcune persone possono utilizzare il programma contemporaneamente con script diversi (questo è certo, poiché 'userScript' potrebbe essere diverso per utente, anche per invocazione). – wiradikusuma

+1

Sì, è sicuro per i thread e stateless (ma come vedo io non crea copie difensive se non utilizza il costruttore predefinito - non dovrebbe essere un problema nel tuo caso) http://svn.codehaus.org/groovy/ tronco/groovy/groovy-core/src/main/groovy/lang/GroovyShell.java – Adam

+0

Penso che si possa riutilizzare l'oggetto shell, ma non penso che sia possibile riutilizzare l'oggetto script. Le istanze di script usano un 'Map' per l'associazione, che non è thread-safe. – HDave

1

Immagino che potresti evitare il peso di costruire un ambiente pieno di groove ogni volta.

Java 6 dispone di un supporto API di scripting in Java, che consente di utilizzare motori di scripting leggeri.

Ad esempio, vedere this page in groovy website che spiega come avviare uno script groovy in un'applicazione Java utilizzando GroovyScriptEngineImpl.

preavviso si può perdere alcune goodnesses groove, come uva forse Groovy, ma sarete in grado di

  • riutilizzare il motore di script
  • garantire i vostri evals di script in contesto di applicazione (eventualmente beneficiano oggetti Java utilizzo)

EDIT una cosa importante da notare è che né GroovyScriptEngineImplGroovyShell può garantire alcun tipo di sicurezza dei thread, come qualsiasi script groovy è libero di generare un numero qualsiasi di thread. In effetti, l'unico modo per garantire la sicurezza del thread è rappresentato dalle operazioni vietate sul thread da installing a SecurityManager. Infatti, anche questo non garantisce la sicurezza del thread (poiché questa sicurezza del thread potrebbe essere ottenuta solo garantendo che tutta la base del codice Java sia thread-safe).

+0

Ho esaminato, ma la mia domanda è sempre la stessa, è thread-safe? Come posso riutilizzarlo? (Se devo usare GroovyScriptEngineImpl). – wiradikusuma

+0

Mi dispiace, ma non riesco a vedere chi ti chiede la sicurezza del filo. – Riduidel

+0

Oops, my bad, non l'ho detto esplicitamente: P – wiradikusuma

0

io alla fine a fare questo:

def shell = new GroovyShell() 
shell.evaluate(initScripts) 

for(i in 1..count) 
{ 
    output = shell.evaluate(userScripts); 
} 

E giusto per essere sicuri, si può mettere in shellThreadLocal o in piscina.