I create a groovy engine with the GroovyShell class.
Then I run a bunch of statements with the "evaluate" method.
Is there a way to catch the output of the engine so I can get "println" calls output?
Currently it goes to stdout although it is a swing application.
You can just assign your custom Writer (eg. StringWriter) to out property in the binding and pass it to the GroovyShell.
def binding = new Binding();
binding.setProperty("out", new YourWriter())
new GroovyShell(binding);
You can set a scriptBaseClass with a println method and you are free to operate on top of the value. Remember the user still can do System.out.println, but you can blacklist it, if needed.
import org.codehaus.groovy.control.CompilerConfiguration
def script = """
a = 10
println a
println "echo"
"""
abstract class Printer extends Script {
void println(obj) {
this.binding.printed << obj
}
}
def config = new CompilerConfiguration(scriptBaseClass: Printer.class.name)
def binding = new Binding([printed: []])
new GroovyShell(this.class.classLoader, binding, config).evaluate script
assert binding.variables.printed.contains( 10 )
assert binding.variables.printed.contains( "echo" )
Related
I am playing with Graal for running javascript as a guest language, and would like to know if there is a way to use javascript Array.map functionality on a host (Java) object or proxy. Demo Kotlin code follows, but should be close enough to Java code.
fun main() {
val context = Context.newBuilder().build()
val javaOutputList = mutableListOf<Integer>()
val javaList = listOf(2, 2, 3, 4, 5)
val proxyJavaList = ProxyArray.fromList(javaList)
context.polyglotBindings.apply {
putMember("javaOutputList", javaOutputList)
putMember("javaList", javaList)
putMember("proxyJavaList", proxyJavaList)
}
val script = """
var javaOutputList = Polyglot.import('javaOutputList');
var javaList = Polyglot.import('javaList');
var proxyJavaList = Polyglot.import('proxyJavaList');
var abc = [1, 2, 3];
abc.forEach(x => javaOutputList.add(x)); // WORKS
//abc.map(x => x + 1) // WORKS
//javaList.map(x => x + 1) // DOES NOT WORK (map not a method on list)
proxyJavaList.map(x => x + 1) // DOES NOT WORK (message not supported: INVOKE)
""".trimIndent()
val result = context.eval("js", script)
val resultList = result.`as`(List::class.java)
println("result: $resultList")
println("javaOutputList: $javaOutputList")
}
Using ProxyArray looked the most promising to me, but I still couldn't get it to work. Is this functionality expected to be supported?
EDIT: with the accepted answer the code works, here is the change for the interested:
val context = Context.newBuilder()
//.allowExperimentalOptions(true) // doesn't seem to be needed
.option("js.experimental-foreign-object-prototype", "true")
.build()
The root of the problem is that array-like non-JavaScript objects do not have Array.prototype on their prototype chain by default. So, Array.prototype.map is not accessible using javaList.map/proxyJavaList.map syntax.
You can either invoke Array.prototype.map directly like Array.prototype.map.call(javaList, x => x+1) or you can use an experimental option js.experimental-foreign-object-prototype=true (that we added recently) that adds Array.prototype on the prototype chain of all array-like objects. javaList.map/proxyJavaList.map will be available then.
I'm trying to build a naive bayes classifier for classifying text between two classes. Everything works great in the GUI explorer, but when I try to recreate it in code, I get the same output no matter what input I try to classify.
Within the code, I get the same evaluation metrics I get within the GUI (81% accuracy), but whenever I try to create a new instance and classify that, I get the same distributions for both classes no matter what input I use.
Below is my code - its in scala, but is pretty straightforward:
//Building the classifier:
val instances = new Instances(new DataSource("/my/dataset.arff").getDataSet)
instances.setClassIndex(3)
val filter = new StringToWordVector
filter.setAttributeIndicesArray( (0 to 2).toArray )
val classifier = new FilteredClassifier
classifier.setFilter(new StringToWordVector(1000000))
classifier.setClassifier(new NaiveBayesMultinomial)
classifier.buildClassifier(trainingSet)
//Evaluation (this prints about 80% accuracy)
val eval = new Evaluation(trainingSet)
eval.evaluateModel(classifier, trainingSet)
println(eval.toSummaryString)
//Attempting to use the classifier:
val atts = new util.ArrayList[Attribute]
atts.add(new Attribute("sentence", true))
atts.add(new Attribute("parts_of_speech", true))
atts.add(new Attribute("dependency_graph", true))
atts.add(new Attribute("the_shizzle_clazz", SentenceType.values().map(_.name()).toSeq.asJava ))
val unlabeledInstances = new Instances("unlabeled", atts, 1)
unlabeledInstances.setClassIndex( 3 )
val instance = new DenseInstance(4)
unlabeledInstances.add(instance)
instance.setDataset(unlabeledInstances)
instance.setValue(0, parsed.sentence)
instance.setValue(1, parsed.posTagsStr)
instance.setValue(2, parsed.depsGraphStr)
val distrib = classifier.distributionForInstance(unlabeledInstance.firstInstance())
distrib.foreach(println)
No matter what input I give, the output of distrib is always:
0.44556173367704455
0.5544382663229555
Any ideas what I'm doing wrong? Would greatly appreciate any help.
It looks like the magic line was:
instance.setClassMissing()
Adding that made it work. :)
Should a script run by jjs.exe be able to locate services with ServiceLoader just as any Java program could?
I have reduced my case to the following script:
function dump (stream)
{
(new BufferedReader(new InputStreamReader(stream))).lines().forEach(function (x) { print(x); });
}
var BufferedReader = Java.type("java.io.BufferedReader");
var InputStreamReader = Java.type("java.io.InputStreamReader");
var ServiceLoader = Java.type("java.util.ServiceLoader");
var Sts = Java.type("prodist.sts.Sts");
print(Sts);
// A
var stsConfigStream = Sts.class.getResourceAsStream("/META-INF/services/prodist.sts.Sts");
dump(stsConfigStream);
// B
var StsImpl = Java.type("prodist.sts.internal.StsImpl");
print(new StsImpl());
// C
var stsLoader = ServiceLoader.load(Sts.class);
var stsIterator = stsLoader.iterator();
stsIterator.next();
// D
I call jjs.exe setting up the Class-Path on the command line. My script correctly finds and prints the interface name in point A. It locates the service description resource; when I dump the content of the resource, I see the expected content in point B. I make sure the expected implementation class is available in point C.
In point D, the program throws a NoSuchElementException, which I interpret as ServiceLoader not finding any service description resource for the interface.
Is this supposed to work?
Am I missing something?
You need to set the thread context class loader. Refer to any class from your jjs classpath, get it's Class object and then get it's class loader. You then set that loader as thread context class loader. This should be done before you use service loader API:
var StsClass = Java.type("prodist.sts.Sts").class;
java.lang.Thread.currentThread().contextClassLoader = StsClass.classLoader;
I'm using Groovy's StreamingMarkupBuilder to generate XML dynamically based on the results of a few SQL queries. I'd like to call a method from inside of the closure but the markup builder tries to create an XML node using the method name.
Here's an example of what I'm trying to do:
Map generateMapFromRow(GroovyRowResult row) {
def map = [:]
def meta = row.getMetaData()
// Dynamically generate the keys and values
(1..meta.getColumnCount()).each { column -> map[meta.getColumnName(column)] = row[column-1] }
return map
}
def sql = Sql.newInstance(db.url, db.user, db.password, db.driver)
def builder = new StreamingMarkupBuilder()
def studentsImport = {
students {
sql.eachRow('select first_name, middle_name, last_name from students') { row ->
def map = generateMapFromRow(row) // Here is the problem line
student(map)
}
}
}
println builder.bind(studentsImport).toString()
This will generate XML similar to the following:
<students>
<generateMapFromRow>
[first_name:Ima, middle_name:Good, last_name:Student]
</generateMapFromRow>
<student/>
<generateMapFromRow>
[first_name:Ima, middle_name:Bad, last_name:Student]
</generateMapFromRow>
<student/>
</students>
I've tried moving the method out to a class and calling to statically on the class, which doesn't work also.
Due to the nature of how StreamingMarkupBuilder works, I'm afraid that it isn't actually possible to do this, but I'm hoping that it is.
I may loose smth during example simplification, but such code will work.
In your example students is a closure call, so it may mess smth inside.
def builder = new groovy.xml.StreamingMarkupBuilder()
def generateMapFromRow = { ["$it": it] }
builder.bind {
10.times {
def map = generateMapFromRow(it) // Now closure is escaped, there is local variable with such name.
student(map)
}
}
As said here: http://groovy.codehaus.org/Using+MarkupBuilder+for+Agile+XML+creation
Things to be careful about when using markup builders is not to overlap variables you currently have in scope. The following is a good example
import groovy.xml.MarkupBuilder
def book = "MyBook"
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.shelf() {
book(name:"Fight Club") { // Will produce error.
}
}
println writer.toString()
Builder's work similar to MethodMissing captors, ans if there is local variable in scope, no node will be produced.
New to the JVM, working with Scala and Play 2.0
I'm converting a legacy application over to Play, one that requires payment processing via Authorize.net. Looking through java.net.URL source, there are numerous potential points of failure. Given the interface I've written below, where would you implement try/catch blocks? I'll need to adapt method signatures accordingly, probably returning an Either[Error, Success] to calling client code
import java.net.{URL, URLEncoder}
import java.io.{BufferedReader, DataOutputStream, InputStreamReader}
import javax.net.ssl._
trait Authnet {
private val prodUrl = "https://secure.authorize.net/gateway/transact.dll"
private val testUrl = "https://test.authorize.net/gateway/transact.dll"
protected def authNetProcess(params: Map[String,String]) = {
val(conn, urlParams) = connect(params)
val request = new DataOutputStream( conn.getOutputStream )
request.write(urlParams.getBytes)
request.flush()
request.close()
val response = new BufferedReader(new InputStreamReader(conn.getInputStream))
val results = response.readLine().split("\\|")
response.close()
results.toList
}
private def connect(params: Map[String,String]) = {
val urlParams = (config ++ params) map { case(k,v) =>
URLEncoder.encode(k, "UTF-8") + "=" + URLEncoder.encode(v, "UTF-8")
} mkString("&")
lazy val url = if (isDev) new URL(testUrl) else new URL(prodUrl)
val conn = url.openConnection
conn.setDoOutput(true)
conn.setUseCaches(false)
(conn, urlParams)
}
private val config = Map(
'x_login -> "...",
'x_tran_key -> "...",
...
)
}
Stick to the thumb rule:
Only catch an exception if you must handle it.
There is no sharp definition for "must handle" but it means you should resist the urge to catch an exception because you can just to throw a different exception.
The "must handle" is mainly defined by how your application should work or other dependencies.
If the application requires to display an error to the user instead of aborting with an exception, then it's a must.
In that case catching the excpetion adds also some meaningful processing.
If an API requires to throw a different exception, then it's a must, but the APIs definition is possibly not sound.
I am always questioning the added value of replacing an exception with just another exception.
Applying this to your example:
Would it add some value to catch an exception from connect() in authNetProcess()?
No! There is no way to handle that exception inside of connect(). So its ok to leave that exception to the caller of authNetProcess. There you could provide different handling based on the kind of the exception.
EDIT
Well, if any part of the connection/stream process fails, the transaction is hosed, so silly to only capture error on opening of the connection. I'm just wrapping the whole transaction in a catching (operation) option block, and leaving it at that; I'm not too concerned re: the exact cause of the error (whatever it is gets logged) as it is transient, so catch it, have the user try again; if error persists, contact us...
ORIGINAL
OK, well, given the up votes and lack of commentary to-date, the only conclusion I can draw is...nobody around here knows what they're doing! heh, heh, joking ;-)
Although I'm new to the JVM, try/catch/finally bloat is getting old fast; via the wonders of Scala type inference, I have abstracted away general error handling into concise implementations:
catching ( operation ) option
catching ( operation ) either
Unless I receive feedback otherwise, for now I'm copping out by just catching connection creation (I believe, in this case, the most likely error condition). Here's the new implementation:
protected def authNetProcess(params: Map[String,String]) = {
connect() match {
case Some(conn) =>
val request = new DataOutputStream(conn.getOutputStream)
request.write(getUrlParams(params).getBytes)
request.flush()
request.close()
val response = new BufferedReader(new InputStreamReader(conn.getInputStream))
val results = response.readLine().split("\\|")
response.close()
results.toList
case None => List[String]()
}
}
private def connect() = {
lazy val url = if (isDev) new URL(testUrl) else new URL(prodUrl)
catching ( url.openConnection ) option match {
case Some(conn) =>
conn.setDoOutput(true)
conn.setUseCaches(false)
//conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
Some(conn)
case None => None // connection failed
}
}
I suppose a more rigorous approach would be to extract all potential error conditions into maybeWorked Option operations, and then wrap them all up in a for comprehension. That's probably the proper/responsible approach...but only so many hours in a day, will revisit this later
feedback appreciated!