Commit ec60a707 authored by Peter Harrison's avatar Peter Harrison

Merge pull request #46 from cheetah100/development

Second Release
parents 6818ebd4 6df07348
......@@ -4,19 +4,54 @@
<groupId>nz.net.gravity</groupId>
<artifactId>gravity</artifactId>
<packaging>war</packaging>
<version>3.0.0</version>
<version>3.0.1-SNAPSHOT</version>
<name>Gravity Workflow Automation</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jetty.version>6.1.4</jetty.version>
<spring.version>3.1.1.RELEASE</spring.version>
<slf4j.version>1.5.10</slf4j.version>
<slf4j.version>1.7.21</slf4j.version>
<java.version>1.6</java.version>
<junit.version>4.8.2</junit.version>
<jackson.version>1.9.10</jackson.version>
</properties>
<licenses>
<license>
<name>GPL, Version 3.0</name>
<url>http://www.gnu.org/licenses/gpl-3.0.en.html</url>
<distribution>repo</distribution>
<comments></comments>
</license>
</licenses>
<organization>
<name>Devcentre Limited</name>
<url>http://devcentre.org</url>
</organization>
<developers>
<developer>
<id>cheetah100</id>
<name>Peter Harrison</name>
<email>cheetah100@gmail.com</email>
<organization>Devcentre Limited</organization>
<organizationUrl>http://devcentre.org</organizationUrl>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
<timezone>New Zealand/Auckland</timezone>
</developer>
</developers>
<scm>
<connection>scm:git:https://github.com/cheetah100/gravity.git</connection>
<tag>HEAD</tag>
<url>https://github.com/cheetah100/gravity</url>
</scm>
<dependencies>
......@@ -150,17 +185,7 @@
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<version>1.2.17</version>
<scope>runtime</scope>
</dependency>
......@@ -184,20 +209,6 @@
<artifactId>jcr</artifactId>
<version>2.0</version>
</dependency>
<!--
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr-commons</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr-commons</artifactId>
<version>2.4.1</version>
</dependency>
-->
<dependency>
<groupId>org.apache.jackrabbit</groupId>
......@@ -263,10 +274,10 @@
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
<version>1.1</version>
<scope>provided</scope>
<groupId>javax.jms</groupId>
<artifactId>javax.jms-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
......@@ -393,7 +404,6 @@
<build>
<finalName>gravity</finalName>
<plugins>
<!-- Facilitates downloading source and javadoc in Eclipse -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
......@@ -437,7 +447,7 @@
</configuration>
</plugin>
</plugins>
</plugins>
</build>
<reporting>
......
hornetq.server=localhost
hornetq.port=5445
cron.clearBoardsCache=0 0 0 * * *
cache.clearschedule=0 0 0 * * *
automation.delay=60
repository.listener.enabled=true
repository.url=localhost
testJcrHome=
bulletin.username=boo
bulletin.password=boo
bulletin.url=bpp
bulletin.from=boo
bulletin.ratecode=boo
aws.keyid=BOO
aws.secret=BAR
\ No newline at end of file
......@@ -11,6 +11,6 @@ bulletin.from=
bulletin.ratecode=
repository.url=http://localhost:8080/jackrabbit-webapp-2.6.0/rmi
testJcrHome=/home/r_kpatel/jackrabbit
testJcrHome=
automation.delay=60000
\ No newline at end of file
......@@ -833,7 +833,7 @@ public class AutomationEngine {
Collections.sort(list, new Comparator<Action>() {
@Override
public int compare(Action action1, Action action2) {
return action1.compareTo(action2);
return action1.getOrder() - action2.getOrder();
}
});
}
......
/**
* GRAVITY WORKFLOW AUTOMATION
* (C) Copyright 2015 Orcon Limited
*
* This file is part of Gravity Workflow Automation.
*
* Gravity Workflow Automation is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Gravity Workflow Automation is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gravity Workflow Automation.
* If not, see <http://www.gnu.org/licenses/>.
*/
package nz.net.orcon.kanban.automation;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import nz.net.orcon.kanban.model.Coup;
import nz.net.orcon.kanban.model.IdRequest;
import nz.net.orcon.kanban.model.IdResponse;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.scheduling.annotation.Scheduled;
/**
* The purpose of the Cluster manager is to manage all the functions that need to be
* coordinated across the Cluster.
*
* - Invalidation of Caches.
* - Phase Updates
* - Getting Identifiers.
* - Master Server Protocol
*
* @author peter
*
*/
public class ClusterManager {
private static final Logger LOG = LoggerFactory.getLogger(ClusterManager.class);
private boolean leader;
private long startTime = System.currentTimeMillis();
private String serverId = RandomStringUtils.random(10, true, true);
@Autowired
@Qualifier("idJmsTemplate")
private JmsTemplate idTemplate;
@Autowired
@Qualifier("idSyncReceiver")
private SyncReceive idSyncReceiever;
@Autowired
JcrObserver jcrObserver;
@Autowired
TimerManager timerManager;
public Long getId(String path, String field) throws Exception {
if( LOG.isDebugEnabled()){
LOG.debug("Generating ID from " + path + "." + field);
}
Message message = requestId(path,field);
if(message==null){
executeChallenge();
message = requestId(path,field);
}
ObjectMessage objectMessage = (ObjectMessage) message;
IdResponse idResponse = (IdResponse) objectMessage.getObject();
return idResponse.getId();
}
public interface ClusterManager {
public Message requestId(String path, String field){
String requestId = RandomStringUtils.random(10, true, true);
SyncMessage idSync = idSyncReceiever.register(requestId);
IdRequest request = new IdRequest();
request.setField(field);
request.setPath(path);
request.setRequestId(requestId);
idTemplate.convertAndSend(request);
return idSync.receiveMessage(10000l);
}
public Long getId(String path, String field) throws Exception;
public String getIdString(String path, String field, String prefix) throws Exception{
Long id = getId( path, field);
return prefix + id.toString();
}
/**
* Note that this method is simply a wrapper to eat the return value of executeChallenge.
* This is needed to be able to schedule the task.
*
* @throws Exception
*/
@Scheduled( fixedDelay=30000l )
public void pollLeader() throws Exception{
if(!isLeader()){
this.executeChallenge();
}
}
public synchronized boolean executeChallenge() throws Exception{
SyncMessage coupSync = idSyncReceiever.register(this.serverId);
Coup coup = new Coup();
coup.setRequestId(this.serverId);
coup.setCoupTime(this.startTime);
idTemplate.convertAndSend(coup);
if( LOG.isDebugEnabled()){
LOG.debug("Sending Heatbeat: " + this.serverId +", Time: " + coup.getCoupTime() + ", ID: " + coup.getRequestId());
}
Message coupMessage = coupSync.receiveMessage(10000l);
boolean newLeader = (coupMessage==null);
if( isLeader()!=newLeader){
if(newLeader){
LOG.warn("FAILOVER: Node promoted to MASTER.");
setLeader(true);
this.jcrObserver.start();
this.timerManager.startup();
} else {
LOG.warn("FAILOVER: Node demoted to worker.");
setLeader(false);
this.jcrObserver.stop();
this.timerManager.stopAll();
}
}
return isLeader();
}
public String getIdString(String path, String field, String prefix) throws Exception;
public synchronized void setLeader(boolean leader) {
this.leader = leader;
}
public void setLeader(boolean leader);
public synchronized boolean isLeader() {
return leader;
}
public boolean isLeader();
public long getStartTime() {
return startTime;
}
public String getServerId() {
return serverId;
}
public long getStartTime();
public String getServerId();
}
/**
* GRAVITY WORKFLOW AUTOMATION
* (C) Copyright 2015 Orcon Limited
*
* This file is part of Gravity Workflow Automation.
*
* Gravity Workflow Automation is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Gravity Workflow Automation is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Gravity Workflow Automation.
* If not, see <http://www.gnu.org/licenses/>.
*/
package nz.net.orcon.kanban.automation;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import nz.net.orcon.kanban.model.Coup;
import nz.net.orcon.kanban.model.IdRequest;
import nz.net.orcon.kanban.model.IdResponse;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.scheduling.annotation.Scheduled;
/**
* The purpose of the Cluster manager is to manage all the functions that need to be
* coordinated across the Cluster.
*
* - Invalidation of Caches.
* - Phase Updates
* - Getting Identifiers.
* - Master Server Protocol
*
* @author peter
*
*/
public class ClusterManagerImpl implements ClusterManager {
private static final Logger LOG = LoggerFactory.getLogger(ClusterManagerImpl.class);
private boolean leader;
private long startTime = System.currentTimeMillis();
private String serverId = RandomStringUtils.random(10, true, true);
@Autowired
@Qualifier("idJmsTemplate")
private JmsTemplate idTemplate;
@Autowired
@Qualifier("idSyncReceiver")
private SyncReceive idSyncReceiever;
@Autowired
JcrObserver jcrObserver;
@Autowired
TimerManager timerManager;
public Long getId(String path, String field) throws Exception {
if( LOG.isDebugEnabled()){
LOG.debug("Generating ID from " + path + "." + field);
}
Message message = requestId(path,field);
if(message==null){
executeChallenge();
message = requestId(path,field);
}
ObjectMessage objectMessage = (ObjectMessage) message;
IdResponse idResponse = (IdResponse) objectMessage.getObject();
return idResponse.getId();
}
private Message requestId(String path, String field){
String requestId = RandomStringUtils.random(10, true, true);
SyncMessage idSync = idSyncReceiever.register(requestId);
IdRequest request = new IdRequest();
request.setField(field);
request.setPath(path);
request.setRequestId(requestId);
idTemplate.convertAndSend(request);
return idSync.receiveMessage(10000l);
}
public String getIdString(String path, String field, String prefix) throws Exception{
Long id = getId( path, field);
return prefix + id.toString();
}
/**
* Note that this method is simply a wrapper to eat the return value of executeChallenge.
* This is needed to be able to schedule the task.
*
* @throws Exception
*/
@Scheduled( fixedDelay=30000l )
public void pollLeader() throws Exception{
if(!isLeader()){
this.executeChallenge();
}
}
public synchronized boolean executeChallenge() throws Exception{
SyncMessage coupSync = idSyncReceiever.register(this.serverId);
Coup coup = new Coup();
coup.setRequestId(this.serverId);
coup.setCoupTime(this.startTime);
idTemplate.convertAndSend(coup);
if( LOG.isDebugEnabled()){
LOG.debug("Sending Heatbeat: " + this.serverId +", Time: " + coup.getCoupTime() + ", ID: " + coup.getRequestId());
}
Message coupMessage = coupSync.receiveMessage(10000l);
boolean newLeader = (coupMessage==null);
if( isLeader()!=newLeader){
if(newLeader){
LOG.warn("FAILOVER: Node promoted to MASTER.");
setLeader(true);
this.jcrObserver.start();
this.timerManager.startup();
} else {
LOG.warn("FAILOVER: Node demoted to worker.");
setLeader(false);
this.jcrObserver.stop();
this.timerManager.stopAll();
}
}
return isLeader();
}
public synchronized void setLeader(boolean leader) {
this.leader = leader;
}
public synchronized boolean isLeader() {
return leader;
}
public long getStartTime() {
return startTime;
}
public String getServerId() {
return serverId;
}
}
/**
* GRAVITY WORKFLOW AUTOMATION
* (C) Copyright 2015 Orcon Limited
* (C) Copyright 2016 Peter Harrison
*
* This file is part of Gravity Workflow Automation.
*
......@@ -21,8 +22,6 @@
package nz.net.orcon.kanban.automation;
import java.net.UnknownHostException;
import javax.annotation.PreDestroy;
import nz.net.orcon.kanban.tools.OcmMapperFactory;
......@@ -33,9 +32,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.jcr.LoginException;
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.observation.ObservationManager;
public class JcrObserver {
......@@ -50,7 +46,7 @@ public class JcrObserver {
ObjectContentManager ocm;
public void start() throws UnsupportedRepositoryOperationException, LoginException, RepositoryException, ClassNotFoundException, UnknownHostException{
public void start() throws Exception{
this.ocm = ocmFactory.getOcm();
ObservationManager observationManager = ocm.getSession().getWorkspace().getObservationManager();
final String[] types = { "nt:unstructured" };
......
/**
* GRAVITY WORKFLOW AUTOMATION
* (C) Copyright 2015 Orcon Limited
* (C) Copyright Peter Harrison 2016
*
* This file is part of Gravity Workflow Automation.
*
......@@ -37,7 +38,7 @@ public class ExtractPlugin implements Plugin {
private static final Logger logger = LoggerFactory.getLogger(ExtractPlugin.class);
@Override
public Map<String,Object> process( Action action, Map<String,Object> context ){
public Map<String,Object> process( Action action, Map<String,Object> context ) throws Exception{
Object target = context.get(action.getResource());
......@@ -60,21 +61,16 @@ public class ExtractPlugin implements Plugin {
}
}
}
try {
// Call the Method.
// If there is an exception we stop processing.
Object response = method.invoke(target,parameterValueArray);
if (response != null) {
context.put(action.getResponse(), response);
logger.info("Recevied response is " + response);
}
} catch (Exception e) {
logger.error("Exception Processing :" + action.getName(), e);
// TO DO:
// add comment and change card color to red..
if(method==null){
throw new Exception("Method Not Found: " + target);
}
Object response = method.invoke(target,parameterValueArray);
if (response != null) {
context.put(action.getResponse(), response);
logger.info("Recevied response is " + response);
}
return context;
......
/**
* GRAVITY WORKFLOW AUTOMATION
* (C) Copyright 2015 Orcon Limited
* (C) Copyright 2016 Peter Harrison
*
* This file is part of Gravity Workflow Automation.
*
......@@ -81,12 +82,11 @@ public class ScriptPlugin implements Plugin{
engine.eval(script);
Bindings resultBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
for( String key : resultBindings.keySet() ){
if( key.equals("context") || key.equals("print") || key.equals("println")){
for( Entry<String, Object> entry : resultBindings.entrySet() ){
if( entry.getKey().equals("context") || entry.getKey().equals("print") || entry.getKey().equals("println")){
continue;
}
Object value = resultBindings.get(key);
context.put(key, value);
context.put(entry.getKey(), entry.getValue());
}
return context;
}
......
......@@ -73,9 +73,6 @@ public class SpawnPlugin implements Plugin {
String targetTemplateId = (String) variableInterpreter.resolve(context, action.getMethod());
Board targetBoard = boardCache.getItem(targetBoardId);
if( targetBoard==null){
logger.warn("Board Not Found - board: " + targetBoardId);
}
String targetPhase = null;
for( Phase phase : targetBoard.getPhases().values()){
......@@ -90,7 +87,7 @@ public class SpawnPlugin implements Plugin {
throw new ResourceNotFoundException();
}
String targetTemplateName