That's great news Jacopo! Thank you very much for working on this.
This effort will accomplish much more than just implement an OFBiz DSL -
it also opens up other interesting possibilities. For example, a user
could drop a JSR-223 PHP script engine in OFBiz and with a little
tweaking here and there, be able to use products like Drupal and Joomla
as an OFBiz front end. Also, server-side JavaScript is gaining in
popularity - which makes sense. Why have two teams of developers - one
for client-side JavaScript, and another for server-side scripting? You
can use the same tools and skill sets on both sides of the connection.
-Adrian
On 3/14/2012 7:56 AM, Jacopo Cappellato wrote:
Adrian, all,
I am summarizing here the results of my initial tests of the Groovy service and
event executed by Adrian's Script* classes (using JSR-223).
First of all, here are the service and events updated to work with the new code
(they run with the latest enhancements I committed to framework code):
=====================================================================
import org.ofbiz.base.util.UtilDateTime
import org.ofbiz.entity.util.EntityUtil
// THIS IS A SERVICE
def setLastInventoryCount() {
inventoryItem = ofbiz.findOne('InventoryItem')
if (!inventoryItem) {
ofbiz.logWarning("The InventoryItem with
inventoryItemId=${parameters.inventoryItemId} doesn't exist.")
return ofbiz.failure("Inventory item with id ${parameters.inventoryItemId}
was not found.")
}
List productFacilities = ofbiz.findList('ProductFacility',
[productId:inventoryItem.productId, facilityId:inventoryItem.facilityId])
productFacilities.each {
countResult = ofbiz.runService('getInventoryAvailableByFacility',
[productId:it.productId, facilityId: it.facilityId])
result = ofbiz.runService('updateProductFacility',
[productId:it.productId, facilityId:it.facilityId,
lastInventoryCount:countResult.availableToPromiseTotal])
}
return ofbiz.success("Updated inventory count for product
${inventoryItem.productId}.")
}
// THIS IS AN EVENT
def updateProductCategoryMember() {
thruDate = parameters.thruDate
if (!thruDate) {
thruDate = UtilDateTime.nowTimestamp()
}
try {
productCategoryMember =
EntityUtil.getFirst(EntityUtil.filterByDate(ofbiz.findList('ProductCategoryMember',
[productCategoryId: parameters.productCategoryId, productId:
parameters.productId])))
if (productCategoryMember) {
productCategoryMember.setString('thruDate', thruDate)
productCategoryMember.store()
}
} catch(Exception e) {
return ofbiz.error("The following error occurred setting thruDate on
category ${parameters.productCategoryId} for product ${parameters.productId}:
${e.getMessage()}")
}
return ofbiz.success("Set thruDate ${thruDate} on category
${parameters.productCategoryId} for product ${parameters.productId}")
}
=====================================================================
And here are some comments, each with a face to highlight the result:
:-) good
:-/ so and so
:-( bad
* the code above is the whole content of the file I have created: as you can
see is still very clear: no need to declare classes, define accessors; you
simply have to write the business logic
** :-)
* after the switch to JSR-223 the "DSL method" are accessed thru the "ofbiz"
reference (instead of being directly available as method calls)
** :-/ (because of the small added complexity) but also :-) because now the IDE is able
to autocomplete the method calls to the "ofbiz" object (with a small tweak that
I will explain); this is actually a nice to have feature
* after the switch to JSR-223 the debugger of my IDE (Idea) is no more able to
walk the Groovy services and events; it is working like a charm when using the
Groovy specific service engine and event handler
** :-( this is really a bummer! is this only an issue with Idea? is it working
with Eclipse? Need to research on this
The summary is:
* the new mechanism works fine and still allows to implement very nice services
and events; this is really good
* the debug issue is rather big one (the lack of debugging tools for Minilang was one of
the most frequent complains) but this is an issue that can be researched/addressed and
shouldn't block the evaluation/adoption of this "new" language for
services/events; even if we will fail to find a solution we could easily run the Groovy
services/events using the custom engine/handler and this will not require any code change
to the services/events
Next step:
it would be really nice to continue this proof of concepts by converting some
interesting Java services/events and Minilang services/events to Groovy: this
will help to complete the ScriptHelper classes and greatly help to appreciate
pros and cons.
Is there any interest in this effort? I see a big potential in this approach,
but the opinion from the community will be important.
Kind regards,
Jacopo
On Mar 13, 2012, at 4:59 PM, Adrian Crum wrote:
Cool - thanks! My apologies - I had not given much thought to the object
construction sequence in that section of code.
I'm pretty sure I followed good concurrency practices overall, but there is
always a chance I missed something.
-Adrian
On 3/13/2012 3:49 PM, Jacopo Cappellato wrote:
This is now fixed in rev. 1300202
By the way: we will need to carefully review the way ScriptHelper/ContextHelper
are built (and especially how the context is passed) in order to make sure the
code is thread safe.
Jacopo
On Mar 13, 2012, at 11:42 AM, Jacopo Cappellato wrote:
Ok thanks... it doesn't work for me because the scriptType is set to UNKNOWN
instead of SERVICE... I am debugging it now.
Jacopo
On Mar 13, 2012, at 11:16 AM, Adrian Crum wrote:
org.ofbiz.service.engine.ScriptEngine.java, line 85 and below.
-Adrian
On 3/13/2012 10:11 AM, Jacopo Cappellato wrote:
Hey Adrian,
a quick question before I dig into the details.
I am using the success(..)/error(...) methods to get a result Map (for
services) or result String (for Events) and I have noticed that in the new
implementation they are saved using the ContextHelper.putResults method.
Who is supposed to call the ContextHelper.getResults() method? It would be nice
if this was done automatically by the framework (service/event handlers) rather
than the script itself... but I am testing it with a service and I can't get
the message back.
If you could show me a code snippet it would help... if not do not worry I will
figure it out.
Thanks,
Jacopo
On Mar 13, 2012, at 8:58 AM, Adrian Crum wrote:
On 3/13/2012 7:46 AM, Jacopo Cappellato wrote:
On Mar 13, 2012, at 7:59 AM, Adrian Crum wrote:
Jacopo,
Could you share with the rest of us the limitations caused by the refactoring?
Definitely: I will review, study and use the new code and I will provide
feedback about the gaps I see.
Oh. I thought you were talking about the ScriptUtil refactoring.
One thing that I am not sure I like is the fact that now some of the strings in
Groovy will be expanded using the FlexibleStringExpander rather than the Groovy
GStrings... this could be confusing when you are programming in Groovy.
I was also planning to use closures to manage nicely EntityListIterators... but
I can probably still do this in the GroovyBaseScript.
The work I committed is just a springboard - anyone can modify it/extend it in
any way they want.
Ok, this is good... and dangerous if anyone will add what they want without
first agreeing/understanding on the purpose of this class. Do we all agree that
it should stay clean and light by providing simple access for common operations
rather than providing access to all the possible operations? I mean, it should
provide a mechanism to perform tasks in the most common ways; for special (less
frequent) tasks the calling script should use the features provided natively by
the language and the standard API (delegator/dispatcher/etc...).
I agree. Let's keep the API limited to OFBiz-specific artifacts: entity engine,
service engine, logging, etc.
As I mentioned previously, the GroovyBaseScript class can simply delegate to
the helper class:
Yes, I will re-implement it following this design and let you know how it goes; but we will still
need the Groovy service engine and Groovy event handlers... in order to keep the architecture clean
should we start to think to them as extensions for the applications only? I mean that they could be
part of the future release of "OFBiz Applications" and not part of the future release
"OFBiz Framework". In this way the dependency and custom Groovy code will all be in the
Applications (if they will be reimplemented in Groovy) and the framework will stay clean and light.
I was planning on having mini-lang's MethodContext extend ScriptHelper so all
scripting languages (including mini-lang) are running on the same code base.
I'm thinking all of this will tie up rather nicely once we have a reduced
framework. Scripting can be its own component that runs on top of the new
framework. Higher-level applications can then extend the scripting component
Jacopo
abstract class GroovyBaseScript extends Script implements ScriptHelper {
...
private final ScriptHelper helper;
Map runService(String serviceName, Map inputMap) throws ScriptException {
return helper.runService(serviceName, inputMap);
}
Map makeValue(String entityName) throws ScriptException {
return helper.makeValue(entityName);
}
...
}
-Adrian
On 3/13/2012 5:49 AM, Jacopo Cappellato wrote:
Adrian, thank you for your work.
What I was writing was actually an extension to Groovy for making it OFBiz friendly; now we
have a "reusable" (? by other languages) version of it... my guess is that you did
it because you liked the ideas in it (and I appreciate it) and you thought it was useful for
other languages as well; and you may be right about this even if, as I initially mentioned,
I would have preferred to complete my work, or at least add a bit more to it, test the DSL
with more poc and Minilang-->Groovy conversions before crystallizing it into an interface
(one of the advantages in doing it in Groovy was that I could implement it without the need
to build/restart the system)... now I have an interface and an implementation of it to take
care of.
But I don't want to complain (*) and I will review your work closely and see
what I can do to use it properly in Groovy. This refactoring has introduced a
series of limitations that I am determined to resolve and it will require some
more study around Groovy and ideas to cope with them... I really want that, if
we will ever adopt Groovy as our next language for the applications, it will
look as perfect and simple and natural and integrated as possible: the natural
language for OFBiz (like Minilang is now) rather than OFBiz implemented in
Groovy.
But before I proceed: what is the next step in your plan? What should go in the
ScriptHelper interface? Am I allowed to enhance it based on my discoveries in my
poc work (Minilang-->Groovy) or should I consider it a final interface that
doesn't have to be modified? Should I ask before enhancing it? I don't want to
hijack your work. And more importantly: can I assume that this helper class will
stay light and simple? I really don't want to see it transformed into a huge class
containing a big amount of methods from different APIs... the fact that all
languages will potentially use it and may wish to extend it with util methods that
make sense to them concerns me a little bit (for example, a language with weak
support for Map handling may need utils methods to manage Maps that could be
useless for Groovy).
Kind regards and again thank you,
Jacopo
(*) even if I find a bit annoying to see my work intercepted and re-routed
while I was in the middle of it, I also appreciate the time and effort you
spent on it and I really want to accept the fact that working in a community
means that I have to blend and negotiate my own ideas and plans with the ones
from others: sometimes it means that you get great help, sometimes it means
that your own beautiful and perfect ideas are touched and rearranged to fit
other's plans and other's beautiful ideas.
I hope that the good attitude and flexibility I am trying to apply here will be
also used by you and others when it will be time for you to accept other's
proposals/changes
On Mar 13, 2012, at 12:35 AM, Adrian Crum wrote:
Jacopo,
I committed a generic, reusable version of this idea in rev 1299924.
-Adrian
On 3/8/2012 6:02 PM, Jacopo Cappellato wrote:
Hi all,
I have just completed my first pass in the implementation of a DSL (Domain
Specific Language) for OFBiz that can be used by Groovy services to act like a
modern version of Minilang.
Please review my notes here:
https://cwiki.apache.org/confluence/display/OFBIZ/Groovy+Services+and+DSL+for+OFBiz
I look forward to your comments and feedback but please consider that 1) it is
a work in progress, 2) I spent a lot of time and mental energy in the effort
(reaching simplicity is really complex task!)... so please don't be too picky
:-)
Regards,
Jacopo
PS: if you find it useful, I can commit the Groovy service mentioned in the
page in Confluence