Developing an Extension
The first class that you need to define is your ServiceProvider, this class will contain a method that will be executed by Cantara Server when it is requested.
Below, you can find an example:
Developing an Extension
package com.rinami.cantara.extension.script;
import com.rinami.cantara.core.CoreObjectFactory;
import com.rinami.cantara.core.DataUtility;
import com.rinami.cantara.core.MessageType;
import com.rinami.cantara.core.session.SessionData;
import com.rinami.cantara.extension.annotations.CantaraService;
import com.rinami.cantara.extension.annotations.Payload;
import com.rinami.cantara.schema.plan.Message;
public class ServiceProvider {
private final Logger log = LoggerFactory.getLogger(ServiceProvider.class);
@CantaraService(name = "scriptServiceRequest")
public ScriptResponse executeScriptRequest(@Payload(name = "scriptRequest") ScriptRequest scriptRequest, SessionData sd) {
Message message = CoreObjectFactory.generateMessage(MessageType.EXTENSION_ERROR, null, MessageType.EXTENSION_ERROR.getDescription(), null);
ScriptResponse scriptResponse = new ScriptResponse(scriptRequest.getName(), scriptRequest.getCantaraVersion());
log.error(String.format(Locale.US, "Failed to execute script %s", scriptRequest.getName());
return scriptResponse;
}
}
In our case, we are providing the possibility of executing any script so executeScriptRequest is an appropriate name but the method name can be anything that applies in your case. However, Cantara Server needs to know which method has to be executed therefore you must to specify which method has to be executed and which parameter is your payload.
@CantaraService is the annotation that you need to use to specify which method has to be executed, in our case, executeScriptRequest will be executed by Cantara Server when required.
@Payload is the annotation that you need to use to specify your payload, it means your needed parameters to execute your new behaviour.
In our example, we can also see 3 classes that we need to understand: SessionData, ScriptRequest and ScriptResponse.
SessionData is the class that contains the session information: user name, environment name, password, etc.
As your extension will be invoked by Cantara Server when an appropriate Extension HTTP Post is received, Cantara Server will validate that it has been sent with a valid Session.
SessionData
package com.rinami.cantara.core.session;
import com.rinami.cantara.core.environment.EnvironmentDefinition;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class SessionData implements Serializable{
private String functionSessionId;
private String username;
private String password;
private String environmentName;
private EnvironmentDefinition environmentDefinition;
private String application;
private Set<String> userRoles;
private String fcmRegistrationId;
private long addressNo;
private String branch;
private String approvalRoute;
private DateFormat dateFormat;
private DateSeparator dateSeparator;
private DecimalCharacter decimalCharacter;
private TimeZone timeZone;
private TimeFormat timeFormat;
private DaylightSavingsRule daylightRule;
public static final String SESSION_DATA_KEY = "com.rinami.cantara.server.core.sessiondata";
public SessionData() {
}
}
ScriptRequest it may be any class that you need but this class must extends ExtensionRequest which is part of the Extension Framework.
Obviously, you have to generate getters and setters but the important point is that you have to use @XmlElement annotation for your attributes in order to support xml and JSON formats.
Extension Script Request
package com.rinami.cantara.extension.script;
import com.rinami.cantara.extension.core.ExtensionRequest;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
public class ScriptRequest extends ExtensionRequest{
@XmlElement(name = "path", required = true )
private String path;
@XmlElement(name = "workingDirectory")
private String workingDirectory;
@XmlElement(name = "script", required = true )
private String script;
@XmlElement(name = "timeOut", required = true )
private Long timeOut;
@XmlElement(name="params")
private List<String> params;
}
Extension Request
package com.rinami.cantara.extension.core;
import com.rinami.cantara.core.CantaraRelease;
import com.rinami.cantara.core.DataUtility;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "ExtensionRequest")
public abstract class ExtensionRequest {
@XmlAttribute(name = "name", required = true)
protected String name;
@XmlAttribute(name = "cantaraVersion")
protected String cantaraVersion;
public ExtensionRequest(){
}
public ExtensionRequest(String name){
this.name = name;
this.cantaraVersion = CantaraRelease.FOUR_DOT_TWO.value();
}
}
ScriptResponse it may be any class that you need but this class must extends ExtensionResponse which is part of the Extension Framework.
Obviously, you have to generate getters and setters but the important point is that you have to use @XmlElement annotation for your attributes in order to support xml and JSON formats.
Extension Script Response
package com.rinami.cantara.extension.script;
import com.rinami.cantara.extension.core.ExtensionResponse;
import javax.xml.bind.annotation.XmlElement;
public class ScriptResponse extends ExtensionResponse{
@XmlElement(name = "stdOutput")
private String stdOutput;
@XmlElement(name = "stdError")
private String stdError;
@XmlElement(name = "exitValue")
private Integer exitValue;
public ScriptResponse(String name, String cantaraVersion) {
this.setName(name);
this.setCantaraVersion(cantaraVersion);
}
}
Extension Response
package com.rinami.cantara.extension.core;
import com.rinami.cantara.core.CantaraRelease;
import com.rinami.cantara.core.DataUtility;
import com.rinami.cantara.schema.plan.Message;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ExtensionResponse", propOrder = {
"message"
})
public abstract class ExtensionResponse {
@XmlElement(name = "Message", required = true)
protected Message message;
@XmlAttribute(name = "name", required = true)
protected String name;
@XmlAttribute(name = "cantaraVersion")
protected String cantaraVersion;
public ExtensionResponse(String name, Message message){
this.name = name;
this.message = message;
this.cantaraVersion = CantaraRelease.FOUR_DOT_TWO.value();
}
}
Extension Response Messages
You can easily return OK, Error or Customized Error Messages as part of your response.
Response Messages
Message message1 = CoreObjectFactory.generateMessage(MessageType.OK, null, MessageType.OK.getDescription(), null);
Message message2 = CoreObjectFactory.generateMessage(MessageType.EXTENSION_ERROR, null, MessageType.EXTENSION_ERROR.getDescription(), null);
Message message3 = CoreObjectFactory.generateMessage(MessageType.EXTENSION_ERROR, null, String.format(Locale.US, "Script exited with value %d", process.exitValue()), null);
ScriptResponse scriptResponse = new ScriptResponse(scriptRequest.getName(), scriptRequest.getCantaraVersion());
scriptResponse.setMessage(message1);
return scriptResponse;
Extension logging
It is really easy to log errors or debug operations on your Extension. You need to declare a Logger attribute and to use it.
Extension logging
private final Logger log = LoggerFactory.getLogger(ServiceProvider.class);
log.error(String.format(Locale.US, "Script %s finished by timeout - %d", scriptRequest.getName(), scriptRequest.getTimeOut()));
log.debug(String.format(Locale.US, "Finished by timeout - StdError: %s StdOutput:%s", scriptResponse.getStdError(), scriptResponse.getStdOutput()));