Skip to Content
Technical Articles

Faster Groovy Development for SAP CPI without Installing an IDE

The Need for Speed

Groovy scripting is an integral part of the CPI. It is a perfect glue script in Java environments and it has integration history.

There are a few annoyances to using it:

  • The only way to check for syntax errors is to deploy the integration.
  • The only way to check logic and functionality is to deploy the integration and ensure the message processing in the flow by triggering it via an adapter like HTTP or SFTP

It takes a lot of time to validate your script even for small changes.

I tried Eclipse and the experience was not perfect. Intellij IDEA seemed to be the way to go. I prepared myself to install another IDE to my computer on top of different versions of Eclipse that I had to maintain. I was going to learn every button and best practice to tell my consultant colleagues.

Then one night, I couldn’t sleep. Whether I turn to left or right in the bed I was seeing some Groovy script telling me to “run”. Why don’t I build a solution that will make my life and the lives of my fellow SAP integration consultants in the world easier? I had to try even that made me skip sleep a few nights more.

The Quick & Easy Solution

Just use your browser, paste your input, paste your Groovy script, and run. That is all.

You can bookmark the “CPI Test Mode” page.
https://groovyide.com/cpi

Conclusion

For the power user and complicated projects with library dependencies, IntelliJ IDEA may be a better solution now. But even for them, there comes a time to write a one-off script on a different computer and test it fast.

It is free and It will be free, so it can become a useful everyday app in your toolbelt like Postman or SoapUI for SAP CPI development.

/
54 Comments
You must be Logged on to comment or reply to a post.
  • class HelloFatih {
       static void main(String[] args) {
          println "He makes life easier...FP"
          println "thanks for your valuable sharing"
          println "Regards"
          print "Hasan"
       }
    } 

     

     

    Regards

    • Hello Hasan,

      Can you run this script as a response?

      import com.sap.gateway.ip.core.customdev.util.Message;
      import java.util.HashMap;
      import groovy.json.JsonSlurper;
      import groovy.util.XmlSlurper;
      
      def Message processData(Message message) {
          
          def myResponseToHasan = "Wow! Awesome way to write a comment!";
          
          myResponseToHasan = gulp(myResponseToHasan)
      	
          def xmlExpressYourself = '''
          <root>
              <expression><thank>Thank you</thank><sayhi>Hello There!</sayhi></expression>
          </root>
          '''
          def root = new XmlSlurper().parseText(xmlExpressYourself)
          myResponseToHasan = myResponseToHasan + "\n" + root.expression.thank
          
          def someWordsInBase64 = "dmVyeSBtdWNo"
          myResponseToHasan = myResponseToHasan + " " + new String(someWordsInBase64.decodeBase64())
          
          def jsonHasan = '{"friends":[{"name": "Hasan Basri", "surname":"Celebi" }, "others" ]}'
          def jsonSlurper = new JsonSlurper()
          def object = jsonSlurper.parseText(jsonHasan)
          def friend = object.friends[0]
          myResponseToHasan = myResponseToHasan + " " + friend.name + " " + friend.surname + "."
          
          def byte[] array = [72, 38, 108, 31, 102, 107, 96, 99, 31]
          myResponseToHasan = myResponseToHasan + "\n" + new String(overAnalyze(array))
          
          def String someString = "796f7520666f756e642069742075736566756c2e"
          myResponseToHasan = myResponseToHasan + new String(someString.decodeHex())
          
          println myResponseToHasan
          message.setBody(myResponseToHasan)
          return message;
          }
      
      def gulp(String str){
      	return str.replaceAll("Wow! ","...")
      }
      
      def overAnalyze(byte[] arr){
          arr.eachWithIndex { 
              value, idx -> arr[idx] = value +1
          }
      }
  • Love it. Glad you could not sleep. I hope you can sleep better now.

    It enables you to try out some code easy.

    One idea would be to add the option to upload a trace and parse the input and fill it in. That way it will be easier to run.

     

    Ps. If you get to install an IDE then we provide a git repository and Gradle plugins to deploy the ilfow from the IDE.

    • Hi Daniel, thanks for the feedback! Yes, I can sleep in peace now.

      Automatically filling in input can be an interesting use case. I try to keep this as simple as possible, so I will think about that.

      Also, storing code in Git is never a bad move. I will check that.

      Regards,
      Fatih

  • Hi Fatih,

    what do you think about integrate it to the cpi helper plugin?

    I was thinking for a link that sends the trace data and a general link in the editor that also sends the groovy script to your side.

    I do not think that’s too much work on both sides.

    I can do the cpi helper part.

    For you it would be:

    • Provide the possibility to send a post request to your site so that I can send you headers, properties, payload and script.
    • Add Impressum and data protection section to your side. I would not feel good to provide an integration without being sure that the data does not stay private

    What do you think?

     

    But first I should check if it is possible to send data to foreign pages from chrome plugin. Maybe there is some security mechanism that prevents this.

     

    Best regards

    Dominic

     

     

      • Hello Dominic,

        Thank you for your comment. I agree that a page clarifies data protection is a very good idea even without any integration. Right now server doesn’t persist anything, so I should state that.

        Regarding integration with CPI helper plugin. Changing CORS headers can cause everyone to send requests to the server. It can cause more security problems in the long run.

        I also want to control the user experience. So a better option can be preparing a URL in the plugin and opening the URL in a new tab.

        When I implement this feature, I will share here.

        Regards,
        Fatih

      • Hi Dominic Beckbauer ,

        I would really love to see this feature in your plugin. From my understanding Fatih’s current implementation (see here) doesn’t need CORS headers. You could just scrape the ressources together, encode them as base64, build the url and then render a regular link in your plugin with target=”_blank”. That should be sufficient to let users jump from your plugin to the Fatih’s pre-filled IDE. Or did I oversee anything?

        Best regards,
        Raffael

        • I am already working on it 🙂

          The problem is to get the current version of the script. So probably there will be a version but it will not send the script. You still have to copy and paste it.

          • Hi Dominic Beckbauer ,

            I don’t know which point exactly is holding you back from getting the script content, but maybe I can help by describing how I would do it. 🙂

            1. Access the browser’s tab location property (current url) which should be something like:
              https://{tenant-id}-tmn.hci.eu1.hana.ondemand.com/itspaces/shell/design/contentpackage/{package-id}/integrationflows/{iflow-id}​
            2. Use regex to extract the package-id:
              contentpackage\/(?<packageId>[^\/]+?)\/integrationflows\/(?<iflowId>[^\/]+?)$
            3. Call (via HTTP GET) the following url while inserting the package-id from step 2:
              https://{tenant-id}-tmn.hci.eu1.hana.ondemand.com/itspaces/odata/1.0/workspace.svc/ContentEntities.ContentPackages('{package-id}')?&$format=json​

              Then extract the field “reg_id” from the object where the field “TechnicalName” equals the {package-id} from the response and save it as variable “package-tech-id”. (We need it later.)

            4. Call (via HTTP GET) the following url while inserting the package-id from step 2:
              https://{tenant-id}-tmn.hci.eu1.hana.ondemand.com/itspaces/odata/1.0/workspace.svc/ContentEntities.ContentPackages('{package-id}')/Artifacts?&$format=json​

              Then extract the field “reg_id” from the object where the field “Name” equals the {iflow-id} from the response and save it as variable “iflow-tech-id”. (We need it later.)

            5. Get the name of the script file. You have two options. Either scrape the HTML source code of the browser tab (precondition: user has selected script step) or call the following API to get the BPMN model (which contains the script steps). Use package-tech-id and iflow-tech-id from steps 3 and 4 to call the url:
              https://{tenant-id}-tmn.hci.eu1.hana.ondemand.com/itspaces/api/1.0/workspace/{package-tech-id}/artifacts/{iflow-tech-id}/entities/{iflow-tech-id}/iflows/{iflow-id}​

              The get the scriptname (without path) from the response (e.g. “script1.groovy”) and store it in a variable like “script-name”. (We need it for the last step.)

            6. Call (via HTTP GET) the following api. It will return the scripts, wrapped in a JSON structure. Use the variables we received in the steps before:
              https://{tenant-id}-tmn.hci.eu1.hana.ondemand.com/itspaces/api/1.0/workspace/{package-tech-id}/artifacts/{iflow-tech-id}/entities/{iflow-tech-id}/iflows/{iflow-id}/script//{script-name}​

              (Attention the double slash in front of the script name is a must!)

            Let me know if I can help you any further.

          • I already hate the day when SAP changes the internal APIs 🙂

            Seems like this is a way to go. Do you know if it is always the last version of the script? So when I change sth in the iflow, press safe (or maybe do not press safe), do I get this version or the last version that was safed with a version number?

            Thanks for the hint. That saved a lot of time 🙂

          • Should be always the latest version, because it is the API which is called when you open the script in the IFlow editor. 😉

            And yes, when internal APIs change your plugin may break, but until then it makes life easier. By the way I guess this is true for the complete plugin. If anything in the HTML/CSS structure changes, I guess it would even break the plugin…

            But since you are not selling the tool, I guess nobody will blame you if it breaks. And we have to keep in mind: the tool makes life easier, but life is possible without the tool. So let’s use the tool to be more efficient as long as it is working. If it breaks one day, it’s not mission critical because it’s a helper and not an integral part of the interface’s infrastructure. 😉

          • I agree with Raffael, it is a free tool we share provided as-is. We can try our best to be stable but no commitments and no deadlines, only fun 🙂 I encourage everyone to publish free tools if they want to change the experience for good.

            In the end, SAP can also pick and implement good ideas from these tools and I want that to happen. That will be a good outcome for CPI developers. In the meantime, people can enjoy increased effectiveness with these tools. It is a win-win.

  • Hi Fatih,

    what a great tool! If I had one wish free, I would wish, that you would add a “share”-functionality, so that we could generate a shortlink for the current IDE state and share it with our colleagues. Maybe, if you plan to further develop this tool, you could add this feature on your todo list. 🙂

    Best regards and thanks for contributing this tool to the community!

     

    • Hi Raffael,

      Thank you for your support and for providing good ideas!

      Short-link is a feature I thought as well. It has some interesting use cases like:

      • Sharing an input and Groovy code in a question.
      • Preparing challenges for juniors in a company.
      • Sharing very specific solutions for a problem or tutorials.

      Storing the state in DB is a solution to this problem. However, it can complicate the infrastructure. Even for a free product, I want to provide stable service and have peace of mind. Being able to say “nothing is stored in the server” is also nice.

      Another option I’m thinking about implementing is using URL to store data. One drawback is it won’t be a short-link! It will be a long link… But it will be a practical one. 🙂

      What are your other two wishes? 😉

      Best regards,
      Fatih

    • Hello Sriprasad!

      Thank you for your kind words. It is really motivating when developers find this useful.

      Regards,
      Fatih

    • Hi Iddo,

      We always work hard to find good solutions for customers. Sometimes we can solve our own problems? 🙂

      Thanks for your feedback.

      Fatih

    • Hello Bekir!

      Thank you for your support.
      It has been a long time since we drank soda water to relieve stress after a long day’s work.

      Best regards,
      Fatih

  • /