Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Sign Up
Dashboard
Groovy
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<p>The debate is not over, scripting vs programming. In fact the definitions between these two still go blurry. In the context of Java, a program comprises of definition of a class and its structure. For example, the simplest program may have just the class definition. </p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class ClassName { } </pre></td></tr></table> <p>Obviously, this particular code doesn't do anything other than just defining the class. A bare minimum useful program may contain a couple of more lines of code in Java. Lets try to write a program that prints "hello world"</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class WorldGreeter { public static void Main(String args[]) { System.out.println ("hello world") ; } } </pre></td></tr></table> <p>The same greeter program can be re-written using a static block or even with the constructor. So, programs follow some strict guidelines in terms of structure.</p> <p>On the other hand, scripts have a mixture of free-hand statements and semi-to-fully structured method elements. We will try to write the greeter program in groovy.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> println "hello world" </pre></td></tr></table> <p>Thats it!!. No class definitions, no curly brackets, no strict syntax checks such as semicolons. Just a simple readable one line statement. All other overheads have been "encapsulated". After all encapsulation is one of the qualities of any Object Oriented Program (oops, Script), isn't it?</p> <p>Ok, lets not delve too much into the contradiction between script and program, neither it is true 'encapsulation' or not. This article is to show the power of scripting using Groovy by walking you with a business example. Enough has been said about the short-hand structure of groovy, how it shrinks coding elements into small fractions to achieve the same result as its counterpart, Java. So, we will take a business problem and try to solve using a groovy script. Think of groovy as a replacement to your perl scripting or shell scripting, in this context. Groovy is not the competitor to Java, it is just complementing it.</p> <p>Feed files are general scenario in business applications. Applications receive/fetch feed files from another application or location, to process and import into the application stream. There are many situations where we need to create a diff or delta between two successive feeds to make the feed processing perform better. For our example, lets assume a feed with an XML structure given below.</p> <table class="wysiwyg-macro" data-macro-name="code" data-macro-default-parameter="xml" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGU6eG1sfQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> <WorkRequests> <WorkRequest id='1'> <Client> <name>BigClient</name> <businessUnit>DotCom</businessUnit> </Client> <RequestType>Requested</RequestType> <RequestDate>2009-12-31</RequestDate> <ProductInfo>Create the plugin component for the upper deck</ProductInfo> </WorkRequest> </WorkRequests> </pre></td></tr></table> <p>Briefly on the structure, the external entities (customer applications) send work requests to the enterprise application, through feed files. The application processes all the work request records by navigating the tree like structure of different work request elements. Basically each request contains client information, request type, date, supporting product information and order processing information. The real functionality of the application is something out of scope for this example.</p> <p>Our script needs exactly two input data to create the delta file, viz., current feed file, last run feed file. The script has to validate and respond to the caller based on the values of the input elements. The idea is to build the script with three sections, first one to verify the input data, second to define a reusable block of code that does the actual check and find out the difference and finally, a small block that writes the output into a new file. On the way we will handle some exception cases also.</p> <p>Lets start building the script by validating the input data.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> if (this.args.size() !=2 ) { println "this script expects exactly two arguments" // You can even print the usage here. return } </pre></td></tr></table> <p>If the number of arguments is anything not equal to 2, then we will not proceed. We can print the usage and exit too.</p> <p>So, the arguments are string values of input file, file to compare and the output folder name.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def inputFile = new File(this.args[0]) def fileToCompare = new File(this.args[1]) // Some more validations. if (!inputFile.exists()) { // Nothing to process, return println "The input file doesn't exist. Process incomplete" return } if (!fileToCompare) { // invalid file for comparison println "File to compare doesn't exist. Process incomplete" return } // If we are here, then the input data is valid, we can start the main processing. </pre></td></tr></table> <p>Lets skip some of the sanity checks such as whether the input file is an XML, is it following the XSD structure etc. Lets assume the well structured, required XML files, ready for processing. We have some special parser API available in groovy for processing XML files as dotted notations. Lets load the input file using the API.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def todaysFile = new XmlSlurper().parse (inputFile) </pre></td></tr></table> <p>With this single statement we have loaded the XML file into memory and all the elements of the XML file are available as dotted notations and as XPATH query elements. All we are interested is to check whether each workrequest record in today's file is a new/modified record in comparison with the "corresponding record" of the last run feed file. Here another assumption is that the id attribute of the work request is something like a primary key and never changes.</p> <p>As we loaded todaysFile into memory we will load the fileToCompare also.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def lastRunFile = new XmlSlurper().parse(fileToCompare) </pre></td></tr></table> <p>Now we need to write a simple closure routine that fetches the WorkRequest record from the last run file by searching the workrequest id.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def getLastRunWorkRequest = { wrID -> def lastRunWorkRequest = lastRunFile.WorkRequest.find(it. @id.text() == wrID) return lastRunWorkRequest } </pre></td></tr></table> <p>The above routine searches the entire last run file, looking for a specific work request using the xpath query. If it finds a matching record, then the entire work request is returned. otherwise a null will be returned. Now we need to write another small routine that verifies whether two elements (of todays file and last run file) are changed.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def dataChanged = { todays, lastrun -> return todays.toString() != lastrun.toString() } </pre></td></tr></table> <p>Simple enough, isn't it?</p> <p>With the two helper routines ready to fire, we need to loop through the feed file to see which record is changed and which is not. The changed or the new records will have to be included in the delta file and the unchanged records will be left out.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def deltaRequests = [] todaysFile.WorkRequest.each { def todays = it def lastrun = getLastRunWorkRequest (todays.@id.text()) if ( (!lastrun) || (dataChanged (todays, lastrun) ) ) { deltaRequests.add (todays) } } </pre></td></tr></table> <p>Now we have collected all the records to be processed in the deltaRequests list. Only thing pending is to attach this list under workrequests element of the XML and write the delta file. To write the XML output there is an API by name groovy.xml.StreamingMarkupBuilder. We will use this to write the file.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> def mb = new groovy.xml.StreamingMarkupBuilder() def doc = mb.bind { WorkRequests { mkp.yield deltaRequests } } def outputWriter = new FileWriter(new File(inputFile).name + '_Delta') outputWriter << doc </pre></td></tr></table> <p>With very simple steps of processing, we have written a clean script that processes two similar structured XML file and creates the delta file. When this script is plugged in into the application that processes redundant feeds on a daily process, we can significantly reduce the processing time by just creating the delta file and making the delta file as the input to the application.</p>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced