diff --git a/mifosng-db/migrations/core_db/V201__webhooks.sql b/mifosng-db/migrations/core_db/V201__webhooks.sql
new file mode 100644
index 000000000..0e782d7f2
--- /dev/null
+++ b/mifosng-db/migrations/core_db/V201__webhooks.sql
@@ -0,0 +1,108 @@
+-- -----------------------------------------------------
+-- Table `m_hook_templates`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `m_hook_templates` (
+ `id` SMALLINT(6) NOT NULL AUTO_INCREMENT,
+ `name` VARCHAR(45) NOT NULL,
+ PRIMARY KEY (`id`))
+ENGINE = InnoDB DEFAULT CHARSET=utf8;
+
+
+-- -----------------------------------------------------
+-- Table `m_hook`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `m_hook` (
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+ `template_id` SMALLINT(6) NOT NULL,
+ `is_active` SMALLINT(3) NOT NULL DEFAULT 1,
+ `name` VARCHAR(45) NOT NULL,
+ `createdby_id` bigint(20) DEFAULT NULL,
+ `created_date` datetime DEFAULT NULL,
+ `lastmodifiedby_id` bigint(20) DEFAULT NULL,
+ `lastmodified_date` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ INDEX `fk_template_id_idx` (`template_id` ASC),
+ CONSTRAINT `fk_template_id`
+ FOREIGN KEY (`template_id`)
+ REFERENCES `m_hook_templates` (`id`))
+ENGINE = InnoDB DEFAULT CHARSET=utf8;
+
+
+-- -----------------------------------------------------
+-- Table `m_hook_schema`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `m_hook_schema` (
+ `id` SMALLINT(6) NOT NULL AUTO_INCREMENT,
+ `hook_template_id` SMALLINT(6) NOT NULL,
+ `field_type` VARCHAR(45) NOT NULL,
+ `field_name` VARCHAR(100) NOT NULL,
+ `placeholder` VARCHAR(100) DEFAULT NULL,
+ `optional` TINYINT(3) NOT NULL DEFAULT 0,
+ PRIMARY KEY (`id`),
+ INDEX `fk_hook_template_id_idx` (`hook_template_id` ASC),
+ CONSTRAINT `fk_hook_template_id`
+ FOREIGN KEY (`hook_template_id`)
+ REFERENCES `m_hook_templates` (`id`))
+ENGINE = InnoDB DEFAULT CHARSET=utf8;
+
+
+-- -----------------------------------------------------
+-- Table `m_hook_registered_events`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `m_hook_registered_events` (
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+ `hook_id` BIGINT(20) NOT NULL,
+ `entity_name` VARCHAR(45) NOT NULL,
+ `action_name` VARCHAR(45) NOT NULL,
+ PRIMARY KEY (`id`),
+ INDEX `fk_hook_id_idx` (`hook_id` ASC),
+ CONSTRAINT `fk_hook_idc`
+ FOREIGN KEY (`hook_id`)
+ REFERENCES `m_hook` (`id`))
+ENGINE = InnoDB DEFAULT CHARSET=utf8;
+
+
+-- -----------------------------------------------------
+-- Table `m_hook_configuration`
+-- -----------------------------------------------------
+CREATE TABLE IF NOT EXISTS `m_hook_configuration` (
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+ `hook_id` BIGINT(20) NULL,
+ `field_type` VARCHAR(45) NOT NULL,
+ `field_name` VARCHAR(100) NOT NULL,
+ `field_value` VARCHAR(100) NOT NULL,
+ PRIMARY KEY (`id`),
+ INDEX `fk_hook_id_idx` (`hook_id` ASC),
+ CONSTRAINT `fk_hook_id_cfg`
+ FOREIGN KEY (`hook_id`)
+ REFERENCES `m_hook` (`id`))
+ENGINE = InnoDB DEFAULT CHARSET=utf8;
+
+insert into `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
+VALUES ('configuration', 'CREATE_HOOK', 'HOOK', 'CREATE', 0);
+insert into `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
+VALUES ('configuration', 'READ_HOOK', 'HOOK', 'READ', 0);
+insert into `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
+VALUES ('configuration', 'UPDATE_HOOK', 'HOOK', 'UPDATE', 0);
+insert into `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
+VALUES ('configuration', 'DELETE_HOOK', 'HOOK', 'DELETE', 0);
+
+insert into m_hook_templates values(1, "Web");
+insert into m_hook_templates values(2, "SMS Bridge");
+
+INSERT INTO `m_hook_schema` (`hook_template_id`, `field_type`, `field_name`, `optional`)
+VALUES (1, 'string', 'Payload URL', 0);
+INSERT INTO `m_hook_schema` (`hook_template_id`, `field_type`, `field_name`, `placeholder`, `optional`)
+VALUES (1, 'string', 'Content Type', 'json / form', 0);
+INSERT INTO `m_hook_schema` (`hook_template_id`, `field_type`, `field_name`, `optional`)
+VALUES (2, 'string', 'Payload URL', 0);
+INSERT INTO `m_hook_schema` (`hook_template_id`, `field_type`, `field_name`, `optional`)
+VALUES (2, 'string', 'SMS Provider', 0);
+INSERT INTO `m_hook_schema` (`hook_template_id`, `field_type`, `field_name`, `optional`)
+VALUES (2, 'string', 'Phone Number', 0);
+INSERT INTO `m_hook_schema` (`hook_template_id`, `field_type`, `field_name`, `optional`)
+VALUES (2, 'string', 'SMS Provider Token', 0);
+INSERT INTO `m_hook_schema` (`hook_template_id`, `field_type`, `field_name`, `optional`)
+VALUES (2, 'string', 'SMS Provider Account Id', 0);
+
+
diff --git a/mifosng-provider/build.gradle b/mifosng-provider/build.gradle
index 3095438cf..fa166f6b1 100644
--- a/mifosng-provider/build.gradle
+++ b/mifosng-provider/build.gradle
@@ -90,6 +90,11 @@ dependencies {
[group: 'com.sun.jersey.contribs', name: 'jersey-spring', version: jerseyVersion],
[group: 'com.sun.jersey.contribs', name: 'jersey-multipart', version: jerseyVersion],
+ [group: 'com.squareup.retrofit', name: 'retrofit', version: '1.6.1'],
+ [group: 'com.squareup.okhttp', name: 'okhttp', version: '2.0.0'],
+ [group: 'com.squareup.okhttp', name: 'okhttp-urlconnection', version: '2.0.0'],
+
+
[group: 'com.google.code.gson', name: 'gson', version: '2.2.4'],
[group: 'com.google.guava', name: 'guava', version: '15.0'],
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java
index c7167c3ff..dd201c989 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java
@@ -233,6 +233,10 @@ public class CommandWrapper {
return this.entityName.equalsIgnoreCase("USER");
}
+ public boolean isHookResource() {
+ return this.entityName.equalsIgnoreCase("HOOK");
+ }
+
public boolean isCurrencyResource() {
return this.entityName.equalsIgnoreCase("CURRENCY");
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java
index f2f3f3093..c63e1219c 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java
@@ -302,6 +302,30 @@ public class CommandWrapperBuilder {
return this;
}
+ public CommandWrapperBuilder createHook() {
+ this.actionName = "CREATE";
+ this.entityName = "HOOK";
+ this.entityId = null;
+ this.href = "/hooks/template";
+ return this;
+ }
+
+ public CommandWrapperBuilder updateHook(final Long hookId) {
+ this.actionName = "UPDATE";
+ this.entityName = "HOOK";
+ this.entityId = hookId;
+ this.href = "/hooks/" + hookId;
+ return this;
+ }
+
+ public CommandWrapperBuilder deleteHook(final Long hookId) {
+ this.actionName = "DELETE";
+ this.entityName = "HOOK";
+ this.entityId = hookId;
+ this.href = "/hooks/" + hookId;
+ return this;
+ }
+
public CommandWrapperBuilder createCharge() {
this.actionName = "CREATE";
this.entityName = "CHARGE";
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java
index 8dd8fe6bb..2e7e942ba 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java
@@ -19,6 +19,9 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer;
+import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
+import org.mifosplatform.infrastructure.hooks.event.HookEvent;
+import org.mifosplatform.infrastructure.hooks.event.HookEventSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
@@ -32,17 +35,21 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
private PlatformSecurityContext context;
private final ApplicationContext applicationContext;
private final ToApiJsonSerializer