Writing a Plugin - Part 2 - Creating a domain object for the UI page

In this module you will generate the Java domain object which stores and holds the UI data. This section assumes the user is familiar with java development in eclipse using the Maven build tool.

Please ensure you have run the dependent module Part 1 before following this tutorial.

Structure of the Project.

This demonstration uses a project with a maven structure. The structure of this project should look like this:

Plugin Project Structure.

Use the UI XML Definition to Define the Java Domain Class.

Now we use a maven profile to generate the Java POJO (or Domain) class used to hold the UI data. To do this use a groovy template generator which takes in the XML file and creates a Java file from it.

To do this add this profile to you maven project:

   <profiles>
      <!-- 
         This profile is for generation of a ui domain objects:
         Usage example: mvn -Pdomain
        -->
      <profile>
         <id>domain</id>
         <build>
            <defaultGoal>generate-resources</defaultGoal>
            <plugins>
               <plugin>
                  <groupId>org.codehaus.groovy.maven</groupId>
                  <artifactId>gmaven-plugin</artifactId> 
                  <version>1.0</version>   
                  <executions>
                     <execution>
                        <phase>generate-resources</phase>
                        <goals>
                           <goal>execute</goal>
                        </goals>
                        <configuration>
                           <defaults>
                              <templateDir>${project.basedir}/generate-domain-scripts/templates</templateDir>
                           </defaults>
                           <scriptpath>
                              <element>${project.basedir}/generate-domain-scripts</element>
                           </scriptpath>
                           <source>Generator.generate(project)</source>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </profile>
   </profiles>

In the root of the maven project add the following directory: generate-domain-scripts. In the directory generate-domain-scripts: create a new file named Generator.groovy. Add this contents to this new file:

class Generator {
    
   static void generate(project){
      
      def baseDir = project.basedir
      def templateDir = project.properties['templateDir']
      new File("src/main/resources").eachDirRecurse() { dir ->
         dir.eachFileMatch(~/ui-plugin.xml/) { file ->
            if (!file.path.contains("templates")) {
               def packageName = file.getPath().replace( '\\', '/' ).substring(19).substring(0, file.getPath().replace( '\\', '/' ).substring(19).indexOf('/ui-plugin.xml')).replace( '/', '.' )
               def packageDir = packageName.replace( '.', '/' )
               def javaDir = "src/main/java/"+packageDir
               def pluginData = new XmlSlurper().parseText( file.getText())
               def className = pluginData.name.toString() + "Domain";
               def classFileName = className + ".java"
               
               TemplaterContext tc = new TemplaterContext(packageName:packageName, className:className, pluginData:pluginData);
               TemplateWriter twDomain = new TemplateWriter(baseDir,javaDir,classFileName,tc)
               twDomain.template(templateDir,"ui-plugin-domain-java.template");
               twDomain.write();
            }
         }
      }
    }
}

In the directory generate-domain-scripts: create a new file named TemplaterContext.groovy. Add this contents to this new file:

class TemplaterContext {
   def packageName;
   def className;
   def pluginData;
   def classlike(s) {s[0].toUpperCase() + (s.size()<2 ? '' : s[1..-1])}
}

In the directory generate-domain-scripts: create a new file named TemplateWriter.groovy. Add this contents to this new file:

import groovy.text.SimpleTemplateEngine;

class TemplateWriter{
   
   def templateFile,targetFile,engine,binding;
   
   TemplateWriter(baseDir, targetDirNameTemplate, targetFileNameTemplate, TemplaterContext tc){
      this.binding = ['tc' : tc]
      
      this.engine = new SimpleTemplateEngine()
      def targetDirTemplate = engine.createTemplate(targetDirNameTemplate).make(binding)
      
      File outputDir = new File( baseDir, targetDirTemplate.toString() )
      outputDir.mkdirs()
      
      def targetFileTemplate = engine.createTemplate(targetFileNameTemplate).make(binding)
      this.targetFile = new File( outputDir, targetFileTemplate.toString() );
   }
   
   TemplateWriter template(templateDir, templateFileName){
      this.templateFile = new File( templateDir, templateFileName )
      if(!this.templateFile.exists()){
         fail("TemplateWriter templateFile :"+templateFile+" doesn't exist !" )
      }
      return this;
   }
   
   void write(){
      if(this.targetFile.exists()){
         println("WARNING Target file "+this.targetFile+" already exists....about to overwrite the file");
      }
      def template = engine.createTemplate(templateFile).make(binding);
      targetFile.write(template.toString());
      println("SUCCESS Created target file :"+this.targetFile+".");
   }
}

In the directory generate-domain-scripts, add the following directory: templates. In the directory templates: create a new file named ui-plugin-domain-java.template. Add this contents to this new file:

/**
 * MidVision 2012
 *
 * This is an auto-generated class using the maven profile:
 *
 * mvn -Pdomain
 *
 * Do NOT edit this class, edit XML file named ui-plugin.xml in the same package 
 * as this file in the resources directory, then delete this file and re-run the maven profile
 * to regenerate this domain class.
 *
 */
package ${tc.packageName};

import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import com.midvision.rapiddeploy.domain.plugin.PluginFieldValidation;
import com.midvision.rapiddeploy.utilities.xml.ObjectToXMLFileWriter;

/**
 *
 * @author MidVision Development
 * Copyright (c) MidVision Limited, All rights reserved
 *
 */
 @XmlRootElement
public class ${tc.className} implements Cloneable, Serializable {

    private static final long serialVersionUID = 1L;
    
    public ${tc.className}() {
                super();
        }
    <%tc.pluginData.fields.each{f->%>
    @PluginFieldValidation(type = PluginFieldValidation.Type.<%=
        if (f.validationType == null || f.validationType.isEmpty()) { 
                'NONE'
        } else {
                f.validationType 
        }%>)
    private <%=f.classType%> <%=f.fieldKey%>;
    <%}%>
    <%tc.pluginData.fields.each{f->%>
    public <%=f.classType%> <%=if (f.classType.equals('java.lang.Boolean')) { 'is' } else { 'get' }%><%=tc.classlike(f.fieldKey.toString())%>() {
        <%=if (f.type == 'SECRET') {'return com.midvision.rapiddeploy.service.plugin.PluginServiceHelper.decryptValue("' + f.fieldKey + '", ' + f.fieldKey + ');'} else { 'return ' + f.fieldKey + ';' }%>
    }

    public void set<%=tc.classlike(f.fieldKey.toString())%>(<%=f.classType%> <%=f.fieldKey%>) {
        <%=if (f.type == 'SECRET') { 'this.' + f.fieldKey + ' = com.midvision.rapiddeploy.service.plugin.PluginServiceHelper.encryptValue("' + f.fieldKey + '", ' + f.fieldKey + ');'} else if (f.validationType == 'FILE' || f.validationType == 'DIRECTORY') { 'this.' + f.fieldKey + ' = org.apache.commons.io.FilenameUtils.separatorsToUnix(' + f.fieldKey + ');' } else { 'this.' + f.fieldKey + ' = ' + f.fieldKey + ';' }%>
    }
    <%}%>
    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }
    
    public String toXML() {
        return ObjectToXMLFileWriter.objectToXml(this, true);
    }
}

Generate the Domain Class

To create the Java domain class, use the command [mvn -Pdomain].

        
C:\Users\user\workspace-ext-rd\rapiddeploy-demo-plugin-reports>mvn -Pdomain
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building RapidDeploy Demo Custom Reports Plugin 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- gmaven-plugin:1.0:execute (default) @ rapiddeploy-demo-plugin-reports ---
SUCCESS Created target file :C:\Users\user\workspace-ext-rd\rapiddeploy-demo-plugin-reports\src\main\java\com\midvision\rapiddeploy\plugins\report\c
ustom\CustomReportsDomain.java.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.472s
[INFO] Finished at: Fri Jun 14 15:59:28 BST 2013
[INFO] Final Memory: 15M/215M
[INFO] ------------------------------------------------------------------------

This will create the following class.

/**
 * MidVision 2012
 *
 * This is an auto-generated class using the maven profile:
 *
 * mvn -Pdomain
 *
 * Do NOT edit this class, edit XML file named ui-plugin.xml in the same package 
 * as this file in the resources directory, then delete this file and re-run the maven profile
 * to regenerate this domain class.
 *
 */
package com.midvision.rapiddeploy.plugins.report.custom;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlRootElement;

import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import com.midvision.rapiddeploy.domain.plugin.PluginFieldValidation;
import com.midvision.rapiddeploy.utilities.xml.ObjectToXMLFileWriter;

/**
 *
 * @author MidVision Development
 * Copyright (c) MidVision Limited, All rights reserved
 *
 */
 @XmlRootElement
public class CustomReportsDomain implements Cloneable, Serializable {

    private static final long serialVersionUID = 1L;
    
    public CustomReportsDomain() {
                super();
        }
    
    @PluginFieldValidation(type = PluginFieldValidation.Type.NOTEMPTY)
    private java.lang.String reportTemplate;
    
    @PluginFieldValidation(type = PluginFieldValidation.Type.NOTEMPTY)
    private java.lang.String reportFormat;
    
    
    public java.lang.String getReportTemplate() {
        return reportTemplate;
    }

    public void setReportTemplate(java.lang.String reportTemplate) {
        this.reportTemplate = reportTemplate;
    }
    
    public java.lang.String getReportFormat() {
        return reportFormat;
    }

    public void setReportFormat(java.lang.String reportFormat) {
        this.reportFormat = reportFormat;
    }
    
    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }
    
    public String toXML() {
        return ObjectToXMLFileWriter.objectToXml(this, true);
    }
}

Conclusion

We have seen how we use the XML definition file to generate the domain class. In Part 3 of this tutorial we will look at how to implement the report plugin interface.

Download the example project here