Tuesday, September 26, 2017

SOA is so Groovy

Recently, I have tested and debugged Web Service and to automate test & compare cases I've used good ol' Groovy script activity in the SoapUI TestCase. Coincidentally, I've worked on the PoC where SOA Suite standard features don't fit well project terms. Can't say I've dreamed it, rather napped after a lunch break: "What if I can melt SOA and Groovy? There is a lang:groovy element available in the SpringBean activity descriptor". Follow me and I show you how to deliver the modern functional language to your SOA composites.

Frankly, if you have ever opened an "Oracle Fusion Middleware Developing SOA Applications with Oracle SOA Suite" you should know about this little perk. There is a whole section about Groovy and AspectJ classes. Unfortunately, it's boundaries definitions rather than how-to explanation.
We will start with the hardball:

  1. Shutdown your SOA server/cluster. 
  2. For all your node(-s, if you have clustered environment) update your $DOMAIN_HOME/bin/setDomainEnv.sh script with the extra library in the domain CLASSPATH. There are two reasons:

    • It's recommended by Oracle 
    • Your composite deployment will fail if you don't add the Groovy library into WebLogic server classpath.  



     Groovy 2.3.7 is the maximum available library version for the SOA Server 12.2.1.xxx, but if your installation has the higher version, use them.

  3. Start up your SOA domain servers normally and make sure that your SOA environment is up and ready.
  4. With the JDeveloper SOA Studio 12c create the new application or fork mine from the Github here
  5. Create a new Web Service service and define synchronous service with the minimalistic parts: request and response as simple XML Schema string types.
  6. Drop SpringBean component to the composite canvas. 
  7. Name component and create new Spring descriptor.
  8. Connect exposed service and Spring component. You should have composite similar to mine:
  9. We almost there. Locate and open for edit your new and shiny SpringBean context descriptor. As you may see there is only service declaration with no interface implementations and bean definitions.  
  10. Update SpringBean descriptor with the new Groovy component definition as on the snipped

    <?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util"
           xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang"
           xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:sca="http://xmlns.oracle.com/weblogic/weblogic-sca" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tool
     http://www.springframework.org/schema/tool/spring-tool.xsd http://www.springframework.org/schema/util
     http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache
    http://www.springframework.org/schema/cache/spring-cache.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/task
     http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/jee 
    http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/lang 
    http://www.springframework.org/schema/lang/spring-lang.xsd http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/jdbc 
    http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/jms 
    http://www.springframework.org/schema/jms/spring-jms.xsd http://www.springframework.org/schema/oxm 
    http://www.springframework.org/schema/oxm/spring-oxm.xsd http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc.xsd 
    http://xmlns.oracle.com/weblogic/weblogic-sca META-INF/weblogic-sca.xsd">
      <!--Spring Bean definitions go here-->
      <lang:groovy id="grBean" refresh-check-delay="5" script-source="file:/oracle/scripts/hello.groovy">
       <lang:property name="logger" ref="loggerBean"/>
      </lang:groovy>
      <sca:service name="GroovyBeanService" target="grBean" type="com.mmikhail.groovy.service.Sayhello_ptt"/>
    </beans>
    
    
    Let's discuss groovy definition attributes.
    • id - Spring Bean Id, should match with the sca:service target attribute.
    • refresh-check-delay - Attribute defines a period of the script source updates. Without thus attribute, composite would read Groovy source only at composite startup.
    • script-source - Points to the script file location. Oracle recommends "classpath:" format, but file: works even better.
    • <lang:property> describes preconfigured SOA spring bean. It delivers standard Logger functionality to the Java and script beans.
      • name - bean property name. Should be implemented in the Java class or script
      • ref - Reference to the SpringBean. I use global predefined bean.
  11. Create Groovy script file and copy it to the server location:

    import com.mmikhail.groovy.service.Sayhello_ptt;
    import oracle.integration.platform.blocks.java.beans.impl.LoggerBean;
    import java.util.logging.Level;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component class grBean implements Sayhello_ptt{
     @Autowired
     def LoggerBean logger;
      String execute(String request) {
            logger.log(Level.INFO,"GROOVY REQUEST: "+request);
            return "My the groovy be with you, "+request+"!"
        }   
    }
    
    
  12. Compile and deploy composite to the SOA server
  13. Run the composite test and get the expected response.
  14. Now let's have some fun. Open hello.groovy file on the server and update greeting string definition
  15. Run another test and enjoy the result

Issues

Oracle recommends to keep scripts along with the composite code and use "classpath:" format to define script-source. Documentation points to the 3 potential locations for that matter:
  • $SOA_PROJECT/SCA-INF/classes folder
  • $SOA_PROJECT/SCA-INF/lib folder
  • $DOMAIN_HOME/lib folder 
I haven't tried global library folder, but have issues with the first two options. 
  • Composite can't find groovy files in the SCA-INF/lib folder, at run-time. 
  • SCA-INF/classes location is even worse, because you can't keep files here. Compiler wipes folder content before project build. So for that, build scripts should be modified to copy your script files to the classes folders after build. 

I haven't  implemented the interface with the Groovy closures, but It could be my fault (I'm a Groovy newbie). 

Open Questions

- Will it work for the SOA 11g instance? With the REST/JSON/JavaScript support in the SOA 12c (check my blog here) it may be not actual for the 12c, but may be very useful for the previous platforms. Groovy is the perfect tool to code REST communications and JSON - XML transformations. 
- Is it possible to keep Groovy scripts in the MDS? Personally, I doubt so, but It worth to try.
- Is it possible to implement an interface with Groovy closures or it's bounded to Java-like code?

No comments: