Groovy Script in Oracle Agile PLM Troubleshooting - groovy

I'm in the process of learning basic programming (now reading through SICP now) for the purpose of writing Groovy scripts to deploy in Oracle Agile PLM. I've gone through a couple Java tutorials online, and I'm reading through the Groovy Recipes book as well. I'm trying to deploy some basic scripts as I go, and I've run into some issues with an if else statement. I'm hoping someone can point me in the right direction. In this case 1272 and 1332 are attribute IDs. When attribute 1272 equals 'Stock' (an attribute populated by a list), then attribute 1332 (a text field) should equal 'AWESOME'. For all other values of attribute 1272, attribute 1332 should equal 'NOT AWESOME'. Here's what I have right now:
import com.agile.agileDSL.ScriptObj.IBaseScriptObj
// add other import statements here
void invokeScript(IBaseScriptObj obj) {
//script body starts here.
def session = obj.getAgileSDKSession()
def objectClassId = obj.getObjectClassId()
def objectNumber = obj.getObjectNumber()
def dataObject = session.getObject(objectClassId, objectNumber) {
if ((dataObject.getValue(1272)) == 'Stock') {
dataObject.setValue(1332, 'AWESOME')
} else {
dataObject.setValue(1332, 'NOT AWESOME') }
}
}
With this and other variations I've tried I keep getting the "groovy.lang.MissingMethodException: No signature of method" error.

Not sure on the libraries you're using but should you have the curly braces after getObject()?, maybe try...
def dataObject = session.getObject(objectClassId, objectNumber)
if ((dataObject.getValue(1272)) == 'Stock') {
dataObject.setValue(1332, 'AWESOME')
}
else {
dataObject.setValue(1332, 'NOT AWESOME')
}

Related

Compile error when using modulus operator in MarkupTemplateEngine

I have been using the Groovy template engine without issue for about a year, but just ran into a strange issue and I'm not sure if I'm crazy, or this is expected behavior.
All things being equal, using this function throws a compile error when used inside a Groovy template.
def isEven(n) { n % 2 == 0 }
General error during class generation: org.codehaus.groovy.ast.Parameter cannot be cast to org.codehaus.groovy.ast.expr.VariableExpression
But if I do it this way...
def isEven(n) { n.mod(2) == 0 }
...everything works as expected.
I didn't notice any special case in the docs, but I could have missed it. Could anyone offer some insight into the meaning behind this error, and perhaps offer some guidance to avoid pitfalls like this in the future?
Cheers, and thank you!
Groovy version 2.5
Update
Here is a full example template that throws the error.
def isEven(n) { n % 2 == 0 }
def items = ["Zero", "One", "Two"]
yieldUnescaped '<!DOCTYPE html>'
html(lang:'en') {
body {
ul {
items.eachWithIndex { item, i ->
if(isEven(i)) li(item)
}
}
}
}
And here is an example of how the template is rendered.
TemplateConfiguration config = new TemplateConfiguration();
MarkupTemplateEngine engine = new MarkupTemplateEngine(config);
Template template = engine.createTemplate(new File('test.tpl').newReader());
Map<String, Object> model = new HashMap<>();
Writable output = template.make(model);
output.writeTo(new File('test.html').newWriter());
Changing the isEven method to use Number.mod compiles just fine.

get attributes, even if they do not exist

Please don't hate me, yes I want to do something really stupid.
I want to get null on every attribute if it does not exist. I found out that I can create the propertyMissing method:
class User {
String name = "A"
}
Object.metaClass.propertyMissing() {
null
}
u = new User();
println u?.name
println u?.namee
This prints:
A
null
Now I have the "great" Hybris system in my back :D
If I add the propertyMissing part on top of my script and run this in the Hybris groovy console, I still get the MissingPropertyException.
Is there another way to avoid the MissingPropertyException exception without having to work with hundreds of try catch? (or hundreds of println u?.namee ? u.namee : null isn't working)
/Edit: 1
I have the following use case (for the Hybris system):
I want to get all necessary information in a dynamic output from some pages. Why dynamic? Some page components have the attribute headline other teaserHeadline and some other title. To avoid to create each time an try catch or if else, I created a function which loops through possible attributes and if it's null it skips that one. For that I need to return null on attributes which doesn't exist.
Here is an example which should work, but it doesn't (don't run it on your live system):
import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
import de.hybris.platform.servicelayer.search.SearchResult;
flexibleSearch = spring.getBean("flexibleSearchService")
FlexibleSearchQuery query = new FlexibleSearchQuery("select {pk} from {ContentPage}");
SearchResult searchResult = flexibleSearch.search(query);
def i = 0;
def max = 1;
searchResult.result.each { page ->
if (i < max) {
gatherCMSPageInformation(page)
}
i++;
}
def gatherCMSPageInformation(page) {
page.class.metaClass.propertyMissing() {
null
}
println page.title2
}
Weird thing is, that if I run it a few times in a small interval, it starts to work. But I can't overwrite "null" to something else like "a". Also I noticed, to overwrite the Object class isn't working at all in Hybris.
/Edit 2:
I noticed, that I'm fighting against the groovy cache. Just try the first example, change null with a and then try to change it again to b in the same context, without restarting the system.
Is there a way to clear the cache?
why don't you use the groovy elvis operator?
println u?.namee ?: null

How to traverse AST tree

I'm trying to create an static analysis for Groovy. As a POC for my superiors I'm just trying to parse simple code and detect SQL injections, which are the easiest kind to spot. I did it successfully on Python, which is my main language, but my company mostly uses Grails (on Groovy).
This is what I have so far:
import org.codehaus.groovy.ast.expr.*;
import org.codehaus.groovy.ast.stmt.*;
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.ast.CodeVisitorSupport
import org.codehaus.groovy.ast.builder.AstBuilder
public class SecurityCheck extends CodeVisitorSupport {
void visitBlockStatement(BlockStatement statement) {
println "NEW BLOCK STATEMENT:"
println statement.getText();
//keep walking...
statement.getStatements().each { ASTNode child ->
println "CHILD FOUND: "
println child.getText();
child.visit(this)
}
}
}
def code = new File('groovy_source.groovy').text // get the code from the source file
def AstBuilder astBuilder = new AstBuilder() // build an instance of the ast builder
def ast = astBuilder.buildFromString(CompilePhase.CONVERSION, code) // build from string when the compiler converts from tokens to AST
def SecurityCheck securityCheck = new SecurityCheck() // create an instance of our security check class
println ast
println ast[0]
ast[0].visit(securityCheck)
The groovy_source.groovy file is very simple, containing only a minimal file with a super easy to spot vulnerability:
def post(id) {
query = "SELECT * FROM table WHERE id = " + id;
result = sql.execute query
return result;
}
It is my understanding that, as I'm inheriting from CodeVisitorSupport, this would just visit a BlockStatement and then, for each statement inside that statement, it would visit it using the method from the supper class.
Nevertheless, when I print the text from the BlockStatement, it is an empty string, and the for each method never even gets called (which I assume must mean the AST found no children for my block statement, even when the function definitively has statements inside it.
[org.codehaus.groovy.ast.stmt.BlockStatement#363a52f[]] // println ast
org.codehaus.groovy.ast.stmt.BlockStatement#363a52f[] // println ast[0]
NEW BLOCK STATEMENT:
{ } // println statement.getText()
Any help here would be tremendously appreciated. Thanks!
I found the answer. I wasn't so hard in the end, but the horrible documentation doesn't make it easy. If you one to traverse the tree, you need to give the constructor the false boolean as a second argument, like this:
def ast = astBuilder.buildFromString(CompilePhase.CONVERSION, false, code)
Then you can use the visit* methods as you expect.

Properties in Groovy base scripts

I have a DSL where, if present, a closure called before will be called before every command.
In my setup I have 3 files: The script itself - Script, a ScriptBase, that is 'attached' to the script via a CompilerConfiguration, and a Handler.
In the script I may or may not have a closure called before.
before = {
//Do stuff.
}
Notice the lack of a type declaration, or def. If I understand Groovy correctly, this means that before is a in the binding, and accessible from outside code when evaluated with GroovyShell.evaluate().
In the ScriptBase I do the following:
class ProductSpecificationBase extends Script {
def before = null
}
This script base may or may not be overridden later on.
Then, in the Handler, I'm doing a check for whether a before closure is defined in the script:
def config = new CompilerConfiguration()
config.setScriptBaseClass(ScriptBase.class.name)
def shell = GroovyShell()
evaluatedScript = shell.evaluate(new File(thePathToScript))
if (evaluatedScript.before) {
theEvaluationOfMyScript.before()
}
The code works as expected if the script does contain a before closure, but if it doesn't it returns a MissingPropertyException. I've had a look at what this means, and it seems that my before in the ScriptBase isn't considered a property, and all the examples of using these ScriptBases I've found on the internet give examples of using methods. This is not feasible for my use case I'm afraid. How can I ensure that the closure in the ScriptBase is considered a property instead of a field(as I am assuming it is now).
To be paraphrase: I would like my code to not execute the if block if the script does not contain a before closure as well as not having been overridden in an extension of the ScriptBase. However, I would like the evaluation of evaluatedScript.before to be false as it is an empty/null Closure (i.e. it went all the way up to ScriptBase, and found the null closure)
I like to avoid a try/catch approach if possible.
in your example you would basically call the getter for the before property. To check, if there is a method with the name (and params) check with respondsTo. To see, if there is a property at all with that name use hasProperty (Thanks #dmahapatro for pointing this out)
class X {
void before() { println 'x' }
}
class Y { }
class Z {
def before = { println 'z' }
}
def x = new X()
def y = new Y()
def z = new Z()
assert x.respondsTo('before', null)
assert !y.respondsTo('before', null)
assert !z.respondsTo('before', null)
assert !x.hasProperty('before')
assert !y.hasProperty('before')
assert z.hasProperty('before')
x.before()
z.before()

Best groovy closure idiom replacing java inner classes?

As new to groovy...
I'm trying to replace the java idiom for event listeners, filters, etc.
My working code in groovy is the following:
def find() {
ODB odb = ODBFactory.open(files.nodupes); // data nucleus object database
Objects<Prospect> src = odb.getObjects(new QProspect());
src.each { println it };
odb.close();
}
class QProspect extends SimpleNativeQuery {
public boolean match(Prospect p) {
if (p.url) {
return p.url.endsWith(".biz");
}
return false;
}
}
Now, this is far from what I'm used to in java, where the implementation of the Query interface is done right inside the odb.getObjects() method. If I where to code "java" I'd probably do something like the following, yet it's not working:
Objects<Prospect> src = odb.getObjects( {
boolean match(p) {
if (p.url) {
return p.url.endsWith(".biz");
}
return false;
}
} as SimpleNativeQuery);
Or better, I'd like it to be like this:
Objects<Prospect> src = odb.getObjects(
{ it.url.endsWith(".biz") } as SimpleNativeQuery
);
However, what groovy does it to associate the "match" method with the outer script context and fail me.
I find groovy... groovy anyways so I'll stick to learning more about it. Thanks.
What I should've asked was how do we do the "anonymous" class in groovy. Here's the java idiom:
void defReadAFile() {
File[] files = new File(".").listFiles(new FileFilter() {
public boolean accept(File file) {
return file.getPath().endsWith(".biz");
}
});
}
Can groovy be as concise with no additional class declaration?
I think it would have helped you to get answers if you'd abstracted the problem so that it didn't rely on the Neodatis DB interface -- that threw me for a loop, as I've never used it. What I've written below about it is based on a very cursory analysis.
For that matter, I've never used Groovy either, though I like what I've seen of it. But seeing as no one else has answered yet, you're stuck with me :-)
I think the problem (or at least part of it) may be that you're expecting too much of the SimpleNativeQuery class from Neodatis. It doesn't look like it even tries to filter the objects before it adds them to the returned collection. I think instead you want to use org.neodatis.odb.impl.core.query.criteria.CriteriaQuery. (Note the "impl" in the package path. This has me a bit nervous, as I don't know for sure if this class is meant to be used by callers. But I don't see any other classes in Neodatis that allow for query criteria to be specified.)
But instead of using CriteriaQuery directly, I think you'd rather wrap it inside of a Groovy class so that you can use it with closures. So, I think a Groovy version of your code with closures might look something like this:
// Create a class that wraps CriteriaQuery and allows you
// to pass closures. This is wordy too, but at least it's
// reusable.
import org.neodatis.odb.impl.core.query.criteria;
class GroovyCriteriaQuery extends CriteriaQuery {
private final c;
QProspect(theClosure) {
// I prefer to check for null here, instead of in match()
if (theClosure == null) {
throw new InvalidArgumentException("theClosure can't be null!");
}
c = theClosure;
}
public boolean match(AbstractObjectInfo aoi){
//!! I'm assuming here that 'aoi' can be used as the actual
//!! object instance (or at least as proxy for it.)
//!! (You may have to extract the actual object from aoi before calling c.)
return c(aoi);
}
}
// Now use the query class in some random code.
Objects<Prospect> src = odb.getObjects(
new GroovyCriteriaQuery(
{ it.url.endsWith(".biz") }
)
)
I hope this helps!
I believe your real question is "Can I use closures instead of anonymous classes when calling Java APIs that do not use closures". And the answer is a definite "yes". This:
Objects<Prospect> src = odb.getObjects(
{ it.url.endsWith(".biz") } as SimpleNativeQuery
);
should work. You write "However, what groovy does it to associate the "match" method with the outer script context and fail me". How exactly does it fail? It seems to me like you're having a simple technical problem to get the solution that is both "the groovy way" and exactly what you desire to work.
Yep, thanks y'all, it works.
I also found out why SimpleNativeQuery does not work (per Dan Breslau).
I tried the following and it worked wonderfully. So the idiom does work as expected.
new File("c:\\temp").listFiles({ it.path.endsWith(".html") } as FileFilter);
This next one does not work because of the neodatis interface. The interface does not enforce a match() method! It only mentions it in the documentation yet it's not present in the class file:
public class SimpleNativeQuery extends AbstactQuery{
}
Objects<Prospect> src = odb.getObjects(
{ it.url.endsWith(".biz") } as SimpleNativeQuery
);
In the above, as the SimpleNativeQuery does not have a match() method, it makes it impossible for the groovy compiler to identify which method in the SimpleNativeQuery should the closure be attached to; it then defaults to the outer groovy script.
It's my third day with groovy and I'm loving it.
Both books are great:
- Groovy Recipes (Scott Davis)
- Programming Groovy (Venkat Subramaniam)

Resources