diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/extensions.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/extensions.xml
index 358d6c5b80..3fb0ce7ea0 100644
--- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/extensions.xml
+++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/extensions.xml
@@ -10,6 +10,7 @@
the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. -->
+
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.script b/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.script
index fa4718a037..44bbe2d31f 100644
--- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.script
+++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/data/hsql/restcomm.script
@@ -21,6 +21,7 @@ CREATE MEMORY TABLE "restcomm_gateways"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"
CREATE MEMORY TABLE "restcomm_media_servers" ( "ms_id" INT GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL, "local_ip" VARCHAR(34) NOT NULL, "local_port" INT NOT NULL, "remote_ip" VARCHAR(34) NOT NULL UNIQUE, "remote_port" INT NOT NULL, "compatibility" VARCHAR(34) DEFAULT 'rms', "response_timeout" VARCHAR(34), "external_address" VARCHAR(34))
CREATE MEMORY TABLE "restcomm_media_resource_broker_entity" ("conference_sid" VARCHAR(34) NOT NULL, "slave_ms_id" VARCHAR(34) NOT NULL, "slave_ms_bridge_ep_id" VARCHAR(34),"slave_ms_cnf_ep_id" VARCHAR(34),"is_bridged_together" BOOLEAN DEFAULT FALSE,PRIMARY KEY ("conference_sid" , "slave_ms_id"))
CREATE MEMORY TABLE PUBLIC."restcomm_extensions_configuration"("sid" VARCHAR(34) NOT NULL PRIMARY KEY,"extension" VARCHAR(255) NOT NULL,"configuration_data" VARCHAR(16777216),"configuration_type" VARCHAR(255) NOT NULL,"date_created" TIMESTAMP NOT NULL,"date_updated" TIMESTAMP, "enabled" BOOLEAN DEFAULT TRUE NOT NULL)
+CREATE MEMORY TABLE PUBLIC."restcomm_accounts_extensions" ("account_sid" VARCHAR(34) NOT NULL, "extension_sid" VARCHAR(34) NOT NULL, PRIMARY KEY("account_sid", "extension_sid"), "configuration_data" VARCHAR(16777216))
CREATE MEMORY TABLE "restcomm_geolocation"("sid" VARCHAR(34) NOT NULL PRIMARY KEY, "date_created" DATETIME NOT NULL, "date_updated" DATETIME NOT NULL, "date_executed" DATETIME NOT NULL, "account_sid" VARCHAR(34) NOT NULL, "source" VARCHAR(30), "device_identifier" VARCHAR(30) NOT NULL, "geolocation_type" VARCHAR(15) NOT NULL, "response_status" VARCHAR(30), "cell_id" VARCHAR(10), "location_area_code" VARCHAR(10), "mobile_country_code" INTEGER, "mobile_network_code" VARCHAR(3), "network_entity_address" BIGINT, "age_of_location_info" INTEGER, "device_latitude" VARCHAR(15), "device_longitude" VARCHAR(15), "accuracy" BIGINT, "physical_address" VARCHAR(50), "internet_address" VARCHAR(50), "formatted_address" VARCHAR(200), "location_timestamp" DATETIME, "event_geofence_latitude" VARCHAR(15), "event_geofence_longitude" VARCHAR(15), "radius" BIGINT, "geolocation_positioning_type" VARCHAR(15), "last_geolocation_response" VARCHAR(10), "cause" VARCHAR(150), "api_version" VARCHAR(10) NOT NULL, "uri" LONGVARCHAR NOT NULL)
CREATE USER SA PASSWORD ""
GRANT DBA TO SA
diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/init.sql b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/init.sql
index c3cd1c4ce2..1edcae09a4 100644
--- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/init.sql
+++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/init.sql
@@ -381,6 +381,13 @@ date_updated DATETIME,
enabled BOOLEAN NOT NULL DEFAULT TRUE
);
+CREATE TABLE restcomm_accounts_extensions (
+account_sid VARCHAR(34) NOT NULL,
+extension_sid VARCHAR(34) NOT NULL,
+configuration_data LONGTEXT NOT NULL,
+PRIMARY KEY (account_sid, extension_sid)
+);
+
INSERT INTO restcomm_accounts VALUES (
"ACae6e420f425248d6a26948c17a9e2acf",
Date("2012-04-24"),
diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/extensions-configuration.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/extensions-configuration.xml
index cf1ed3a48f..261c3e385b 100644
--- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/extensions-configuration.xml
+++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/scripts/mariadb/sql/extensions-configuration.xml
@@ -61,4 +61,24 @@
+
+
+
+
+ INSERT INTO restcomm_accounts_extensions (account_sid, extension_sid, configuration_data)
+ VALUES (#{account_sid}, #{extension_sid}, #{configuration_data});
+
+
+
+ UPDATE restcomm_accounts_extensions SET configuration_data=#{configuration_data}
+ WHERE account_sid=#{account_sid} AND extension_sid=#{extension_sid};
+
+
+
+ DELETE FROM restcomm_accounts_extensions
+ WHERE account_sid=#{account_sid} AND extension_sid=#{extension_sid};
+
diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/extensions-configuration.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/extensions-configuration.xml
index 552915e6db..b20ac5233b 100644
--- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/extensions-configuration.xml
+++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/sql/extensions-configuration.xml
@@ -67,4 +67,24 @@
-
\ No newline at end of file
+
+
+
+
+ INSERT INTO "restcomm_accounts_extensions" ("account_sid", "extension_sid", "configuration_data")
+ VALUES (#{account_sid}, #{extension_sid}, #{configuration_data});
+
+
+
+ UPDATE "restcomm_accounts_extensions" SET "configuration_data"=#{configuration_data}
+ WHERE "account_sid"=#{account_sid} AND "extension_sid"=#{extension_sid};
+
+
+
+ DELETE FROM "restcomm_accounts_extensions"
+ WHERE "account_sid"=#{account_sid} AND "extension_sid"=#{extension_sid};
+
+
diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ExtensionsConfigurationDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ExtensionsConfigurationDao.java
index 4c5ea677bb..a66a4484dc 100644
--- a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ExtensionsConfigurationDao.java
+++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/ExtensionsConfigurationDao.java
@@ -97,4 +97,33 @@ public interface ExtensionsConfigurationDao {
* @return
*/
boolean validate(ExtensionConfiguration extensionConfiguration);
+
+ /**
+ * Get account specific ExtensionConfiguration
+ * @param accountSid
+ * @param extensionSid
+ * @return ExtensionConfiguration
+ */
+ ExtensionConfiguration getAccountExtensionConfiguration(String accountSid, String extensionSid);
+
+ /**
+ * Add a new account specific ExtensionConfiguration
+ * @param extensionConfiguration
+ * @param accountSid
+ */
+ void addAccountExtensionConfiguration(ExtensionConfiguration extensionConfiguration, Sid accountSid) throws ConfigurationException;
+
+ /**
+ * Update an existing account specific ExtensionConfiguration
+ * @param extensionConfiguration
+ * @param accountSid
+ */
+ void updateAccountExtensionConfiguration(ExtensionConfiguration extensionConfiguration, Sid accountSid) throws ConfigurationException;
+
+ /**
+ * Delete account specific ExtensionConfiguration
+ * @param accountSid
+ * @param extensionSid
+ */
+ void deleteAccountExtensionConfiguration(String accountSid, String extensionSid);
}
diff --git a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisExtensionsConfigurationDao.java b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisExtensionsConfigurationDao.java
index 4e3a58918d..e5dfb2f6ee 100644
--- a/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisExtensionsConfigurationDao.java
+++ b/restcomm/restcomm.dao/src/main/java/org/restcomm/connect/dao/mybatis/MybatisExtensionsConfigurationDao.java
@@ -259,6 +259,13 @@ private ExtensionConfiguration toExtensionConfiguration(final Map map) {
+ final Sid sid = new Sid((String)map.get("extension"));
+ final String extension = (String) map.get("extension");
+ final Object confData = map.get("configuration_data");
+ return new ExtensionConfiguration(sid, extension, true, confData, null, null, null);
+ }
+
private Map toMap(final ExtensionConfiguration extensionConfiguration) {
final Map map = new HashMap();
map.put("sid", DaoUtils.writeSid(extensionConfiguration.getSid()));
@@ -276,4 +283,86 @@ private Map toMap(final ExtensionConfiguration extensionConfigur
map.put("enabled", extensionConfiguration.isEnabled());
return map;
}
+
+ @Override
+ public ExtensionConfiguration getAccountExtensionConfiguration(String accountSid, String extensionSid) {
+ final SqlSession session = sessions.openSession();
+ ExtensionConfiguration extensionConfiguration = null;
+ try {
+ Map params = new HashMap();
+ params.put("account_sid", accountSid.toString());
+ params.put("extension_sid", extensionSid.toString());
+ final Map result = session.selectOne(namespace + "getAccountExtensionConfiguration", params);
+ if (result != null) {
+ extensionConfiguration = toAccountsExtensionConfiguration(result);
+ }
+ return extensionConfiguration;
+ } finally {
+ session.close();
+ }
+ }
+
+ @Override
+ public void addAccountExtensionConfiguration(ExtensionConfiguration extensionConfiguration, Sid accountSid) throws ConfigurationException {
+ final SqlSession session = sessions.openSession();
+ try {
+ if (extensionConfiguration != null && extensionConfiguration.getConfigurationData() != null) {
+ if (validate(extensionConfiguration)) {
+ final Map map = new HashMap();
+ map.put("account_sid", DaoUtils.writeSid(accountSid));
+ map.put("extension_sid", DaoUtils.writeSid(extensionConfiguration.getSid()));
+
+ if (extensionConfiguration.getConfigurationData() != null)
+ map.put("configuration_data", extensionConfiguration.getConfigurationData());
+
+ session.insert(namespace + "addAccountExtensionConfiguration", map);
+ session.commit();
+ } else {
+ throw new ConfigurationException("Exception trying to add new configuration, validation failed. configuration type: "
+ + extensionConfiguration.getConfigurationType());
+ }
+ }
+ } finally {
+ session.close();
+ }
+ }
+
+ @Override
+ public void updateAccountExtensionConfiguration(ExtensionConfiguration extensionConfiguration, Sid accountSid)
+ throws ConfigurationException {
+ final SqlSession session = sessions.openSession();
+ try {
+ if (extensionConfiguration != null && extensionConfiguration.getConfigurationData() != null) {
+ if (validate(extensionConfiguration)) {
+ final Map map = new HashMap();
+ map.put("account_sid", DaoUtils.writeSid(accountSid));
+ map.put("extension_sid", DaoUtils.writeSid(extensionConfiguration.getSid()));
+
+ if (extensionConfiguration.getConfigurationData() != null)
+ map.put("configuration_data", extensionConfiguration.getConfigurationData());
+ session.update(namespace + "updateAccountExtensionConfiguration", map);
+ } else {
+ throw new ConfigurationException("Exception trying to update configuration, validation failed. configuration type: "
+ + extensionConfiguration.getConfigurationType());
+ }
+ }
+ session.commit();
+ } finally {
+ session.close();
+ }
+ }
+
+ @Override
+ public void deleteAccountExtensionConfiguration(String accountSid, String extensionSid) {
+ final SqlSession session = sessions.openSession();
+ try {
+ Map params = new HashMap();
+ params.put("account_sid", accountSid.toString());
+ params.put("extension_sid", extensionSid.toString());
+ session.delete(namespace + "deleteAccountExtensionConfiguration", params);
+ session.commit();
+ } finally {
+ session.close();
+ }
+ }
}
diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/ExtensionRequest.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/ExtensionRequest.java
new file mode 100755
index 0000000000..76231eba0d
--- /dev/null
+++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/ExtensionRequest.java
@@ -0,0 +1,46 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2013, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.restcomm.connect.extension.api;
+import org.apache.commons.configuration.Configuration;
+
+public class ExtensionRequest {
+ private Object payload;
+ private Configuration configuration;
+
+ public ExtensionRequest() {}
+
+ public Object getObject() {
+ return payload;
+ }
+
+ public void setObject(Object object) {
+ this.payload = object;
+ }
+
+ public void setConfiguration(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ public Configuration getConfiguration() {
+ return this.configuration;
+ }
+
+}
diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/ExtensionResponse.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/ExtensionResponse.java
index 065e2aff1f..2bbf8c71b6 100644
--- a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/ExtensionResponse.java
+++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/ExtensionResponse.java
@@ -26,7 +26,7 @@
*/
public class ExtensionResponse {
private Object object;
- private boolean allowed;
+ private boolean allowed = true;
public ExtensionResponse() {}
diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/MessageExtensionResponse.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/MessageExtensionResponse.java
new file mode 100644
index 0000000000..de1b637ff5
--- /dev/null
+++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/MessageExtensionResponse.java
@@ -0,0 +1,27 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2013, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * When an Extension returns a MessageReponse, RC will reconfigure the message it will send
+ */
+package org.restcomm.connect.extension.api;
+public class MessageExtensionResponse extends ExtensionResponse {
+ //TODO: needs discussion, definition
+}
diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/NodeExtensionResponse.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/NodeExtensionResponse.java
new file mode 100644
index 0000000000..ed3b2f4965
--- /dev/null
+++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/NodeExtensionResponse.java
@@ -0,0 +1,27 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2013, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * When an Extension returns a NodeReponse, RC will reconfigure the specific RC node it is in
+ */
+package org.restcomm.connect.extension.api;
+public class NodeExtensionResponse extends ExtensionResponse {
+ //TODO: needs discussion, definition
+}
diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtensionGeneric.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtensionGeneric.java
index 1fd04ff3a2..96116be9c6 100644
--- a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtensionGeneric.java
+++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/RestcommExtensionGeneric.java
@@ -57,7 +57,7 @@ public interface RestcommExtensionGeneric {
* and either block/allow it or modify the session before Restcomm process it
* @return ExtensionResponse see ExtensionResponse
*/
- ExtensionResponse preOutboundAction(Object message);
+ ExtensionResponse preOutboundAction(ExtensionRequest extensionRequest);
/**
* Method that will be executed AFTER the process of an Outbound session
* Implement this method so you will be able to check the Outgoing session
@@ -78,4 +78,15 @@ public interface RestcommExtensionGeneric {
*/
ExtensionResponse postApiAction(ApiRequest apiRequest);
+ /**
+ * Extension name getter
+ * @return String name of Extension
+ */
+ String getName();
+
+ /**
+ * Extension version getter
+ * @return String version of Extension
+ */
+ String getVersion();
}
diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/SessionExtensionResponse.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/SessionExtensionResponse.java
new file mode 100644
index 0000000000..9d8013a87f
--- /dev/null
+++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/SessionExtensionResponse.java
@@ -0,0 +1,44 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2013, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * When an Extension returns a SessionReponse, RC will reconfigure the session it is in
+ */
+package org.restcomm.connect.extension.api;
+import org.apache.commons.configuration.Configuration;
+public class SessionExtensionResponse extends ExtensionResponse {
+ //TODO: needs discussion, definition
+ /**
+ * The Extension is expected to populate the session specific
+ * Configuration
+ */
+ public void setConfiguration(Configuration configuration){
+ super.setObject(configuration);
+ }
+
+ /**
+ * RC expects an Extension to populate Configuration when it returns
+ * this SessionResponse
+ * @return Configuration object
+ */
+ public Configuration getConfiguration(){
+ return (Configuration) super.getObject();
+ }
+}
diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/SystemExtensionResponse.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/SystemExtensionResponse.java
new file mode 100644
index 0000000000..4df9d6a039
--- /dev/null
+++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/SystemExtensionResponse.java
@@ -0,0 +1,27 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2013, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * When an Extension returns a SystemReponse, RC will reconfigure itself systemwide
+ */
+package org.restcomm.connect.extension.api;
+public class SystemExtensionResponse extends ExtensionResponse {
+ //TODO: needs discussion, definition
+}
diff --git a/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/TransactionExtensionResponse.java b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/TransactionExtensionResponse.java
new file mode 100644
index 0000000000..c3ac493ab2
--- /dev/null
+++ b/restcomm/restcomm.extension.api/src/main/java/org/restcomm/connect/extension/api/TransactionExtensionResponse.java
@@ -0,0 +1,28 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2013, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+/**
+ * When an Extension returns a TransactionReponse, RC will reconfigure the transaction it
+ * is in
+ */
+package org.restcomm.connect.extension.api;
+public class TransactionExtensionResponse extends ExtensionResponse {
+ //TODO: needs discussion, definition
+}
\ No newline at end of file
diff --git a/restcomm/restcomm.extension.controller/pom.xml b/restcomm/restcomm.extension.controller/pom.xml
index 3b982e8935..94e5d2fe42 100644
--- a/restcomm/restcomm.extension.controller/pom.xml
+++ b/restcomm/restcomm.extension.controller/pom.xml
@@ -46,6 +46,22 @@
${sipservletapi.version}
provided
+
+ org.restcomm
+ restcomm-connect.dao
+ ${project.version}
+
+
+ org.restcomm
+ restcomm-connect.commons
+ ${project.version}
+
+
+ org.apache.maven
+ maven-artifact
+ 3.1.0
+
+
\ No newline at end of file
diff --git a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/configuration/DefaultExtensionConfiguration.java b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/configuration/DefaultExtensionConfiguration.java
new file mode 100755
index 0000000000..fa5690730a
--- /dev/null
+++ b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/configuration/DefaultExtensionConfiguration.java
@@ -0,0 +1,262 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2016, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ */
+package org.restcomm.connect.extension.configuration;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.util.HashMap;
+
+import java.util.Map;
+
+import org.apache.ibatis.exceptions.PersistenceException;
+import org.apache.log4j.Logger;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
+import org.joda.time.DateTime;
+import org.restcomm.connect.commons.dao.Sid;
+import org.restcomm.connect.dao.DaoManager;
+import org.restcomm.connect.dao.ExtensionsConfigurationDao;
+import org.restcomm.connect.extension.api.ConfigurationException;
+import org.restcomm.connect.extension.api.ExtensionConfiguration;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.stream.JsonReader;
+
+public class DefaultExtensionConfiguration {
+ public enum PropertyType {
+ VERSION("version");
+ private String value;
+
+ private PropertyType(String value) {
+ this.value = value;
+ }
+ };
+
+ private static final Logger logger = Logger.getLogger(DefaultExtensionConfiguration.class);
+ private boolean workingWithLocalConf;
+ private ExtensionsConfigurationDao extensionConfigurationDao;
+ private ExtensionConfiguration extensionConfiguration;
+ private JsonObject configurationJsonObj;
+ private JsonParser jsonParser;
+ private DaoManager daoManager;
+ private Gson gson;
+ private JsonObject defaultConfigurationJsonObj;
+ private String extensionName;
+ private DefaultArtifactVersion defVersion;
+ private HashMap specificConfigurationMap;
+ private Sid sid;
+ private String localConfigPath;
+
+ public DefaultExtensionConfiguration() {
+ this.sid = new Sid("EX00000000000000000000000000000001");
+ this.localConfigPath = "";
+ }
+
+ public DefaultExtensionConfiguration(final DaoManager daoManager, String extensionName, String localConfigPath) {
+ try {
+ init(daoManager, extensionName, localConfigPath);
+ } catch (Exception e) {
+ logger.error("Exception initializing");
+ }
+ }
+
+ public void init(final DaoManager daoManager, String extensionName, String localConfigPath) throws ConfigurationException {
+ try {
+ this.setDaoManager(daoManager);
+ this.extensionConfigurationDao = daoManager.getExtensionsConfigurationDao();
+
+ if (extensionName.isEmpty() && localConfigPath.isEmpty()) {
+ throw new ConfigurationException("extensionName or local config cant be empty");
+ }
+ if (!extensionName.isEmpty()) {
+ this.extensionName = extensionName;
+ }
+ if (!localConfigPath.isEmpty()) {
+ // Load the default extensionConfiguration from file
+ this.defaultConfigurationJsonObj = loadDefaultConfiguration(localConfigPath);
+
+ configurationJsonObj = this.defaultConfigurationJsonObj;
+
+ // Get the extension name from default extensionConfiguration
+ String temp = defaultConfigurationJsonObj.get("extension_name").getAsString();
+ if (!temp.isEmpty()) {
+ extensionName = temp;
+ }
+ defVersion = new DefaultArtifactVersion(defaultConfigurationJsonObj.get("version").getAsString());
+ }
+ // Load extensionConfiguration from DB
+ extensionConfiguration = extensionConfigurationDao.getConfigurationByName(extensionName);
+
+ // try fetch sid from name
+ if (extensionConfiguration == null) {
+ // If extensionConfiguration from DB is null then add the default values to DB
+ this.sid = Sid.generate(Sid.Type.EXTENSION_CONFIGURATION);
+ extensionConfiguration = new ExtensionConfiguration(sid, this.extensionName, true,
+ defaultConfigurationJsonObj.toString(), ExtensionConfiguration.configurationType.JSON, DateTime.now());
+ extensionConfigurationDao.addConfiguration(extensionConfiguration);
+
+ } else {
+ // Get configuration object
+ this.sid = extensionConfiguration.getSid();
+ // try get default config data
+ JsonObject dbConfiguration = null;
+
+ DefaultArtifactVersion currentVersion = null;
+ try {
+ dbConfiguration = (JsonObject) jsonParser.parse((String) extensionConfiguration.getConfigurationData());
+ if (dbConfiguration.get("version") != null) {
+ currentVersion = new DefaultArtifactVersion(dbConfiguration.get("version").getAsString());
+ }
+
+ if (dbConfiguration != null && (currentVersion == null || currentVersion.compareTo(defVersion) < 0)) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Configuration found in the DB is older version than the default one: "
+ + defVersion.toString());
+ }
+
+ for (Map.Entry jsonElementEntry : defaultConfigurationJsonObj.entrySet()) {
+ if (!jsonElementEntry.getKey().equalsIgnoreCase("specifics_configuration")
+ && dbConfiguration.get(jsonElementEntry.getKey()) == null) {
+ dbConfiguration.add(jsonElementEntry.getKey(), jsonElementEntry.getValue());
+ }
+ }
+ if (dbConfiguration.get("version") != null) {
+ dbConfiguration.remove("version");
+ }
+ dbConfiguration.addProperty("version", defaultConfigurationJsonObj.get("version").getAsString());
+
+ extensionConfiguration = new ExtensionConfiguration(extensionConfiguration.getSid(), extensionName,
+ extensionConfiguration.isEnabled(), dbConfiguration.toString(),
+ ExtensionConfiguration.configurationType.JSON, DateTime.now());
+ extensionConfigurationDao.updateConfiguration(extensionConfiguration);
+ }
+ configurationJsonObj = dbConfiguration;
+ // Load Specific Configuration Map
+ // loadSpecificConfigurationMap(configurationJsonObj);
+ } catch (Exception e) {
+ }
+
+ }
+ if (logger.isInfoEnabled()) {
+ logger.info("Finished loading configuration for extension: " + extensionName);
+ }
+ } catch (ConfigurationException configurationException) {
+ String errorMessage = "Exception during " + this.getClass() + " Configuration constructor ";
+ if (logger.isDebugEnabled()) {
+ logger.debug(errorMessage + configurationException);
+ }
+ throw new ConfigurationException(errorMessage);
+ } catch (PersistenceException persistenceException) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("PersistenceException during " + this.getClass() + " init, will fallback to default configuration");
+ }
+ workingWithLocalConf = true;
+ } catch (IOException e) {
+ logger.debug("IOException during " + this.getClass());
+ }
+ }
+
+ public JsonObject loadDefaultConfiguration(String localConfigFilePath) throws IOException {
+ JsonObject jsonObj = null;
+ jsonParser = new JsonParser();
+ InputStream in = (InputStream) getClass().getResourceAsStream(localConfigFilePath);
+ BufferedReader inReader = new BufferedReader(new InputStreamReader(in));
+ JsonReader reader = new JsonReader(inReader);
+ JsonElement jsonElement = jsonParser.parse(reader);
+ jsonObj = (JsonObject) jsonElement;
+ in.close();
+ inReader.close();
+ reader.close();
+ return jsonObj;
+ }
+
+ public void reloadConfiguration() {
+ if (!workingWithLocalConf) {
+ if (extensionConfigurationDao.isLatestVersionByName(extensionName, extensionConfiguration.getDateUpdated())) {
+ extensionConfiguration = extensionConfigurationDao.getConfigurationByName(extensionName);
+ String updatedConf = (String) extensionConfiguration.getConfigurationData();
+ configurationJsonObj = (JsonObject) jsonParser.parse(updatedConf);
+ // loadSpecificConfigurationMap(configurationJsonObj);
+ if (logger.isInfoEnabled()) {
+ logger.info(this.extensionName + " extension configuration reloaded");
+ }
+ }
+ }
+ }
+
+ public boolean isEnabled() {
+ reloadConfiguration();
+ if (extensionConfiguration != null) {
+ return extensionConfiguration.isEnabled();
+ } else {
+ return true;
+ }
+ }
+
+ public String getVersion() {
+ reloadConfiguration();
+ String ver = configurationJsonObj.get(PropertyType.VERSION.value).getAsString();
+ return ver;
+ }
+
+ public Sid getSid() {
+ return this.sid;
+ }
+
+ public void loadSpecificConfigurationMap(final JsonObject json) {
+ JsonArray specificConfJsonArray = json.getAsJsonArray();
+ // JsonArray specificConfJsonArray = json.getAsJsonArray("specifics_configuration");
+ // if (specificConfJsonArray != null) {
+ // specificConfigurationMap = new HashMap();
+ // Iterator iter = specificConfJsonArray.iterator();
+ // while (iter.hasNext()) {
+ // JsonElement elem = iter.next();
+ // if (elem.getAsJsonObject().get("sid") != null) {
+ // specificConfigurationMap.put(sid, value);
+ // }
+ // }
+ // }
+ // return map
+ }
+
+ // getConfigAsJson
+ // getConfigAsConfiguration
+ // getConfigAsHashMap
+ /*public void getSpecificConfigurationMapAsXml() {
+ }*/
+
+ /**
+ * @return the daoManager
+ */
+ public DaoManager getDaoManager() {
+ return daoManager;
+ }
+
+ /**
+ * @param daoManager the daoManager to set
+ */
+ public void setDaoManager(DaoManager daoManager) {
+ this.daoManager = daoManager;
+ }
+}
diff --git a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/controller/ExtensionController.java b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/controller/ExtensionController.java
index d3912c76ac..0668660738 100644
--- a/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/controller/ExtensionController.java
+++ b/restcomm/restcomm.extension.controller/src/main/java/org/restcomm/connect/extension/controller/ExtensionController.java
@@ -1,8 +1,16 @@
package org.restcomm.connect.extension.controller;
+import org.restcomm.connect.extension.api.ExtensionRequest;
+import org.restcomm.connect.extension.api.ExtensionResponse;
import org.restcomm.connect.extension.api.ExtensionType;
+import org.restcomm.connect.extension.api.MessageExtensionResponse;
+import org.restcomm.connect.extension.api.NodeExtensionResponse;
import org.restcomm.connect.extension.api.RestcommExtension;
import org.restcomm.connect.extension.api.RestcommExtensionGeneric;
+import org.restcomm.connect.extension.api.SessionExtensionResponse;
+import org.restcomm.connect.extension.api.SystemExtensionResponse;
+import org.restcomm.connect.extension.api.TransactionExtensionResponse;
+import org.apache.commons.configuration.Configuration;
import org.apache.log4j.Logger;
import java.util.List;
@@ -80,4 +88,62 @@ public void registerExtension(final RestcommExtensionGeneric extension) {
}
}
}
+
+ public ExtensionResponse executePreOutboundAction(final ExtensionRequest er, List extensions) {
+ //FIXME: if we have more than one extension in chain
+ // and all of them are successful, we only receive the last
+ // extensionResponse
+ ExtensionResponse response = new ExtensionResponse();
+ if (extensions != null && extensions.size() > 0) {
+
+ for (RestcommExtensionGeneric extension : extensions) {
+ if(logger.isInfoEnabled()) {
+ logger.info( extension.getName()+" is enabled="+extension.isEnabled());
+ }
+ if (extension.isEnabled()) {
+ response = extension.preOutboundAction(er);
+ //fail fast
+ if (!response.isAllowed()){
+ break;
+ }
+ }
+ }
+ }
+ return response;
+ }
+
+ public ExtensionResponse executePostOutboundAction(final Object er, List extensions) {
+ ExtensionResponse response = new ExtensionResponse();
+ //TODO: implement actual calls
+ return response;
+ }
+
+ //FIXME: there must be a fixed contract between the returned extensions object
+ // and how the system will reconfigure itself with the type of ExtensionResponse
+ // for now we will just map SessionExtensionResponse to Configuration object
+ //FIXME: method signature is too restrictive
+ public Object handleExtensionResponse(ExtensionResponse response, Configuration configuration){
+ //check type of extension
+ //FIXME: hack to default
+ Object object = configuration;
+ if(response instanceof SystemExtensionResponse){
+ //TODO:return systemwide level customization behaviour
+ }
+ if(response instanceof NodeExtensionResponse){
+ //TODO:return node level customization behaviour
+ }
+ if(response instanceof SessionExtensionResponse){
+ SessionExtensionResponse ser = (SessionExtensionResponse) response;
+ Configuration config = ser.getConfiguration();
+
+ object = config;
+ }
+ if(response instanceof TransactionExtensionResponse){
+ //TODO:return transaction level customization behaviour
+ }
+ if(response instanceof MessageExtensionResponse){
+ //TODO:return message level customization behaviour
+ }
+ return object;
+ }
}
diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationEndpoint.java
index ba54e6713b..856877f42e 100644
--- a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationEndpoint.java
+++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/ExtensionsConfigurationEndpoint.java
@@ -22,6 +22,7 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.thoughtworks.xstream.XStream;
+
import org.apache.commons.configuration.Configuration;
import org.joda.time.DateTime;
import org.restcomm.connect.commons.dao.Sid;
@@ -87,23 +88,44 @@ void init() {
* @param responseType
* @return
*/
- protected Response getConfiguration(final String extensionId, final MediaType responseType) {
+ protected Response getConfiguration(final String extensionId, final Sid accountSid, final MediaType responseType) {
//Parameter "extensionId" could be the extension Sid or extension name.
if (!isSuperAdmin()) {
throw new InsufficientPermission();
}
ExtensionConfiguration extensionConfiguration = null;
+ ExtensionConfiguration extensionAccountConfiguration = null;
+ Sid extensionSid = null;
+ String extensionName = null;
+
+ if(Sid.pattern.matcher(extensionId).matches()){
+ extensionSid = new Sid(extensionId);
+ } else {
+ extensionName = extensionId;
+ }
if (Sid.pattern.matcher(extensionId).matches()) {
try {
- extensionConfiguration = extensionsConfigurationDao.getConfigurationBySid(new Sid(extensionId));
+ extensionConfiguration = extensionsConfigurationDao.getConfigurationBySid(extensionSid);
} catch (Exception e) {
return status(NOT_FOUND).build();
}
} else {
try {
- extensionConfiguration = extensionsConfigurationDao.getConfigurationByName(extensionId);
+ extensionConfiguration = extensionsConfigurationDao.getConfigurationByName(extensionName);
+ } catch (Exception e) {
+ return status(NOT_FOUND).build();
+ }
+ }
+
+ if (accountSid!=null) {
+ if(extensionSid == null ){
+ extensionSid = extensionConfiguration.getSid();
+ }
+ try {
+ extensionAccountConfiguration = extensionsConfigurationDao.getAccountExtensionConfiguration(accountSid.toString(), extensionSid.toString());
+ extensionConfiguration.setConfigurationData(extensionAccountConfiguration.getConfigurationData(), extensionAccountConfiguration.getConfigurationType());
} catch (Exception e) {
return status(NOT_FOUND).build();
}
@@ -116,7 +138,7 @@ protected Response getConfiguration(final String extensionId, final MediaType re
final RestCommResponse response = new RestCommResponse(extensionConfiguration);
return ok(xstream.toXML(response), APPLICATION_XML).build();
} else if (APPLICATION_JSON_TYPE == responseType) {
- return ok(gson.toJson(extensionConfiguration), APPLICATION_JSON).build();
+ return ok(gson.toJson(extensionConfiguration.getConfigurationData()), APPLICATION_JSON).build();
} else {
return null;
}
@@ -146,6 +168,7 @@ private ExtensionConfiguration createFrom(final MultivaluedMap d
DateTime dateCreated = DateTime.now();
DateTime dateUpdated = DateTime.now();
ExtensionConfiguration extensionConfiguration = new ExtensionConfiguration(sid, extension, enabled, configurationData, configurationType, dateCreated, dateUpdated);
+
return extensionConfiguration;
}
@@ -154,17 +177,37 @@ protected Response postConfiguration(final MultivaluedMap data,
throw new InsufficientPermission();
}
- ExtensionConfiguration extensionConfiguration = null;
- try {
- extensionConfiguration = createFrom(data, responseType);
- } catch (final NullPointerException exception) {
- return status(BAD_REQUEST).entity(exception.getMessage()).build();
+ Sid accountSid = null;
+
+ String accountSidQuery = data.getFirst("AccountSid");
+ if(accountSidQuery != null && !accountSidQuery.isEmpty()){
+ accountSid = new Sid(accountSidQuery);
}
+ //if extension doesnt exist, add new extension
+ String extensionName = data.getFirst("ExtensionName");
+ ExtensionConfiguration extensionConfiguration = extensionsConfigurationDao.getConfigurationByName(extensionName);
- try {
- extensionsConfigurationDao.addConfiguration(extensionConfiguration);
- } catch (ConfigurationException exception) {
- return status(NOT_ACCEPTABLE).entity(exception.getMessage()).build();
+ if(extensionConfiguration==null){
+ try {
+ extensionConfiguration = createFrom(data, responseType);
+ } catch (final NullPointerException exception) {
+ return status(BAD_REQUEST).entity(exception.getMessage()).build();
+ }
+ try {
+ extensionsConfigurationDao.addConfiguration(extensionConfiguration);
+ } catch (ConfigurationException exception) {
+ return status(NOT_ACCEPTABLE).entity(exception.getMessage()).build();
+ }
+ }
+ if (accountSid!=null) {
+ try {
+ Object configurationData = data.getFirst("ConfigurationData");
+ // if accountSid exists, then this configuration is account specific, if it doesnt then its global config
+ extensionConfiguration.setConfigurationData(configurationData, extensionConfiguration.getConfigurationType());
+ extensionsConfigurationDao.addAccountExtensionConfiguration(extensionConfiguration, accountSid);
+ } catch (ConfigurationException exception) {
+ return status(NOT_ACCEPTABLE).entity(exception.getMessage()).build();
+ }
}
if (APPLICATION_JSON_TYPE == responseType) {
@@ -192,6 +235,12 @@ protected Response updateConfiguration(String extensionSid, MultivaluedMaprestcomm-connect.sms.api
-
+
+ org.restcomm.smpp
+ smpp-extensions
+ 1.0.13
+
org.restcomm
restcomm-connect.commons
diff --git a/restcomm/restcomm.sms.api/src/main/java/org/restcomm/connect/sms/api/SmsSessionRequest.java b/restcomm/restcomm.sms.api/src/main/java/org/restcomm/connect/sms/api/SmsSessionRequest.java
index e6d722a914..0665fdb146 100644
--- a/restcomm/restcomm.sms.api/src/main/java/org/restcomm/connect/sms/api/SmsSessionRequest.java
+++ b/restcomm/restcomm.sms.api/src/main/java/org/restcomm/connect/sms/api/SmsSessionRequest.java
@@ -22,7 +22,7 @@
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.sip.SipServletRequest;
-
+import org.restcomm.smpp.parameter.TlvSet;
import org.restcomm.connect.commons.annotations.concurrency.Immutable;
/**
@@ -36,6 +36,7 @@ public final class SmsSessionRequest {
private final Encoding encoding;
private final SipServletRequest origRequest;
private final ConcurrentHashMap customHeaders;
+ private final TlvSet tlvSet;
public enum Encoding {
UCS_2("UCS-2"),
@@ -52,9 +53,17 @@ public String toString() {
return name;
}
}
-
- //TODO need to check which is using the SmsSessionRequest and modify accordingly to include or not the custom headers
- public SmsSessionRequest(final String from, final String to, final String body, final Encoding encoding, final SipServletRequest origRequest, final ConcurrentHashMap customHeaders) {
+ //FIXME: all signatures should be changed, encoding, sipReq, tlvSet are optional and should come after headers
+ //(from, to, body, headers, encoding, sipReq, tlvSet)
+ //(from, to, body, headers, encoding, sipReq)
+ //(from, to, body, headers, encoding, tlvSet)
+ //(from, to, body, headers, sipReq, tlvSet)
+ //(from, to, body, headers, encoding)
+ //(from, to, body, headers, sipReq)
+ //(from, to, body, headers, tlvSet)
+ //(from, to, body)
+
+ public SmsSessionRequest(final String from, final String to, final String body, final Encoding encoding, final SipServletRequest origRequest, TlvSet tlvSet, final ConcurrentHashMap customHeaders) {
super();
this.from = from;
this.to = to;
@@ -62,18 +71,41 @@ public SmsSessionRequest(final String from, final String to, final String body,
this.body = body;
this.customHeaders = customHeaders;
this.encoding = encoding;
+ this.tlvSet = tlvSet;
+
+ }
+
+ //TODO need to check which is using the SmsSessionRequest and modify accordingly to include or not the custom headers
+ public SmsSessionRequest(final String from, final String to, final String body, final Encoding encoding, final SipServletRequest origRequest, final ConcurrentHashMap customHeaders) {
+ this(from, to, body, encoding, origRequest, null, customHeaders);
+ }
+
+ public SmsSessionRequest(final String from, final String to, final String body, final Encoding encoding, final TlvSet tlvSet, final ConcurrentHashMap customHeaders) {
+ this(from, to, body, encoding, null, tlvSet, customHeaders);
+ }
+
+ public SmsSessionRequest(final String from, final String to, final String body, final SipServletRequest origRequest, final TlvSet tlvSet, final ConcurrentHashMap customHeaders) {
+ this(from, to, body, Encoding.GSM, null, tlvSet, customHeaders);
}
public SmsSessionRequest(final String from, final String to, final String body, final SipServletRequest origRequest, final ConcurrentHashMap customHeaders) {
- this(from, to, body, Encoding.GSM, origRequest, customHeaders);
+ this(from, to, body, Encoding.GSM, origRequest, null, customHeaders);
}
public SmsSessionRequest(final String from, final String to, final String body, final Encoding encoding, final ConcurrentHashMap customHeaders) {
- this(from, to, body, encoding, null, customHeaders);
+ this(from, to, body, encoding, null, null, customHeaders);
+ }
+
+ public SmsSessionRequest(final String from, final String to, final String body, final TlvSet tlvSet, final ConcurrentHashMap customHeaders) {
+ this(from, to, body, Encoding.GSM, null, null, customHeaders);
}
public SmsSessionRequest(final String from, final String to, final String body, final ConcurrentHashMap customHeaders) {
- this(from, to, body, Encoding.GSM, null, customHeaders);
+ this(from, to, body, Encoding.GSM, null, null, customHeaders);
+ }
+
+ public SmsSessionRequest(final String from, final String to, final String body) {
+ this(from, to, body, Encoding.GSM, null, null, null);
}
public String from() {
@@ -92,6 +124,10 @@ public Encoding encoding() {
return encoding;
}
+ public TlvSet getTlvSet() {
+ return tlvSet;
+ }
+
public SipServletRequest getOrigRequest() {
return origRequest;
}
diff --git a/restcomm/restcomm.sms/pom.xml b/restcomm/restcomm.sms/pom.xml
index b4778f7ce3..709d8ced9d 100644
--- a/restcomm/restcomm.sms/pom.xml
+++ b/restcomm/restcomm.sms/pom.xml
@@ -17,6 +17,11 @@
+
+ org.restcomm.smpp
+ smpp-extensions
+ 1.0.13
+
log4j
log4j
diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsService.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsService.java
index dc6dc33088..86ff8949a9 100644
--- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsService.java
+++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsService.java
@@ -48,6 +48,7 @@
import org.restcomm.connect.dao.entities.SmsMessage.Direction;
import org.restcomm.connect.dao.entities.SmsMessage.Status;
import org.restcomm.connect.extension.api.ExtensionResponse;
+import org.restcomm.connect.extension.api.ExtensionRequest;
import org.restcomm.connect.extension.api.ExtensionType;
import org.restcomm.connect.extension.api.RestcommExtensionException;
import org.restcomm.connect.extension.api.RestcommExtensionGeneric;
@@ -60,10 +61,13 @@
import org.restcomm.connect.sms.api.SmsServiceResponse;
import org.restcomm.connect.sms.api.SmsSessionAttribute;
import org.restcomm.connect.sms.api.SmsSessionRequest;
+
import org.restcomm.connect.telephony.api.TextMessage;
import org.restcomm.connect.telephony.api.util.B2BUAHelper;
import org.restcomm.connect.telephony.api.util.CallControlHelper;
+import org.restcomm.smpp.parameter.TlvSet;
+
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.sip.SipApplicationSession;
@@ -72,6 +76,7 @@
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipURI;
+
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
@@ -208,8 +213,8 @@ private void message(final Object message) throws IOException {
final SipServletResponse trying = request.createResponse(SipServletResponse.SC_TRYING);
trying.send();
-
- ActorRef session = session();
+ //TODO:do extensions check here too?
+ ActorRef session = session(this.configuration);
// Create an SMS detail record.
final Sid sid = Sid.generate(Sid.Type.SMS_MESSAGE);
final SmsMessage.Builder builder = SmsMessage.builder();
@@ -236,7 +241,8 @@ private void message(final Object message) throws IOException {
// Store the sms record in the sms session.
session.tell(new SmsSessionAttribute("record", record), self());
// Send the SMS.
- final SmsSessionRequest sms = new SmsSessionRequest(client.getLogin(), toUser, new String(request.getRawContent()),request, null);
+ TlvSet tlvSet = new TlvSet();
+ final SmsSessionRequest sms = new SmsSessionRequest(client.getLogin(), toUser, new String(request.getRawContent()), request, tlvSet, null);
monitoringService.tell(new TextMessage(((SipURI)request.getFrom().getURI()).getUser(), ((SipURI)request.getTo().getURI()).getUser(), TextMessage.SmsState.INBOUND_TO_PROXY_OUT), self);
session.tell(sms, self());
}
@@ -312,7 +318,8 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SipServletRequ
}
interpreter = builder.build();
}
- final ActorRef session = session();
+ //TODO:do extensions check here too?
+ final ActorRef session = session(this.configuration);
session.tell(request, self);
final StartInterpreter start = new StartInterpreter(session);
interpreter.tell(start, self);
@@ -325,39 +332,34 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SipServletRequ
return isFoundHostedApp;
}
- private boolean executePreOutboundAction(final Object message) {
- if (extensions != null && extensions.size() > 0) {
- for (RestcommExtensionGeneric extension : extensions) {
- if (extension.isEnabled()) {
- ExtensionResponse response = extension.preOutboundAction(message);
- if (!response.isAllowed())
- return false;
- }
- }
- }
- return true;
- }
-
- private boolean executePostOutboundAction(final Object message) {
- return true;
- }
-
@Override
public void onReceive(final Object message) throws Exception {
final UntypedActorContext context = getContext();
final Class> klass = message.getClass();
final ActorRef self = self();
final ActorRef sender = sender();
+ ExtensionController ec = ExtensionController.getInstance();
if (CreateSmsSession.class.equals(klass)) {
- if (executePreOutboundAction(message)) {
- final ActorRef session = session();
+ //retrieve extension object
+ //FIXME:we need a real interface here rather than amending a preexisting request interface
+ ExtensionRequest er = new ExtensionRequest();
+ er.setObject(message);
+ er.setConfiguration(this.configuration);
+
+ ExtensionResponse extensionResponse = ec.executePreOutboundAction(er, this.extensions);
+ if (extensionResponse.isAllowed()) {
+ //pass in response object to sms session
+ Object obj = ec.handleExtensionResponse(extensionResponse, this.configuration);
+ //FIXME:not all instances of extensions should modify
+ //a session configuration, we should do checks here
+ final ActorRef session = session((Configuration)obj);
final SmsServiceResponse response = new SmsServiceResponse(session);
sender.tell(response, self);
} else {
final SmsServiceResponse response = new SmsServiceResponse(new RestcommExtensionException("Now allowed to create SmsSession"));
sender.tell(response, self());
}
- executePostOutboundAction(message);
+ ec.executePostOutboundAction(message, this.extensions);
} else if (DestroySmsSession.class.equals(klass)) {
final DestroySmsSession request = (DestroySmsSession) message;
final ActorRef session = request.session();
@@ -418,13 +420,13 @@ private SipURI outboundInterface() {
return result;
}
- private ActorRef session() {
+ private ActorRef session(final Configuration p_configuration) {
final Props props = new Props(new UntypedActorFactory() {
private static final long serialVersionUID = 1L;
@Override
public UntypedActor create() throws Exception {
- return new SmsSession(configuration, sipFactory, outboundInterface(), storage, monitoringService, servletContext);
+ return new SmsSession(p_configuration, sipFactory, outboundInterface(), storage, monitoringService, servletContext);
}
});
return system.actorOf(props);
diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsSession.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsSession.java
index dc1a9847b2..4b4cc4f3b2 100644
--- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsSession.java
+++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsSession.java
@@ -25,6 +25,9 @@
import akka.event.LoggingAdapter;
import com.cloudhopper.commons.charset.Charset;
import com.cloudhopper.commons.charset.CharsetUtil;
+import com.cloudhopper.commons.util.ByteArrayUtil;
+import com.cloudhopper.smpp.tlv.Tlv;
+import com.cloudhopper.smpp.SmppConstants;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.configuration.Configuration;
import org.restcomm.connect.sms.api.GetLastSmsRequest;
@@ -45,6 +48,7 @@
import org.restcomm.connect.sms.smpp.SmppMessageHandler;
import org.restcomm.connect.sms.smpp.SmppOutboundMessageEntity;
import org.restcomm.connect.telephony.api.TextMessage;
+import org.restcomm.smpp.parameter.TlvSet;
import javax.servlet.ServletContext;
import javax.servlet.sip.SipApplicationSession;
@@ -61,6 +65,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+
/**
* @author quintana.thomas@gmail.com (Thomas Quintana)
*/
@@ -78,6 +83,7 @@ public final class SmsSession extends UntypedActor {
private ConcurrentHashMap customRequestHeaderMap = new ConcurrentHashMap();
// Map for custom headers from HTTP App Server (when creating outbound SIP MESSAGE)
private ConcurrentHashMap customHttpHeaderMap;
+ private TlvSet tlvSet;
private final DaoManager storage;
@@ -113,6 +119,17 @@ public SmsSession(final Configuration configuration, final SipFactory factory, f
this.externalIP = this.configuration.subset("runtime-settings").getString("external-ip");
if (externalIP == null || externalIP.isEmpty() || externalIP.equals(""))
externalIP = defaultHost;
+
+ this.tlvSet = new TlvSet();
+ if(!this.configuration.subset("outbound-sms").isEmpty()) {
+ //TODO: handle arbitrary keys instead of just TAG_DEST_NETWORK_ID
+ try {
+ String valStr = this.configuration.subset("outbound-sms").getString("destination_network_id");
+ this.tlvSet.addOptionalParameter(new Tlv(SmppConstants.TAG_DEST_NETWORK_ID,ByteArrayUtil.toByteArray(Integer.parseInt(valStr))));
+ } catch (Exception e) {
+ logger.error("Error while parsing tlv configuration " + e);
+ }
+ }
}
private void inbound(final Object message) throws IOException {
@@ -135,7 +152,8 @@ private void inbound(final Object message) throws IOException {
}
}
// Store the last sms event.
- last = new SmsSessionRequest(from, to, body, customRequestHeaderMap);
+
+ last = new SmsSessionRequest(from, to, body, this.tlvSet, customRequestHeaderMap);
if (initial == null) {
initial = last;
}
@@ -154,7 +172,8 @@ private void inbound(final Object message) throws IOException {
encoding = SmsSessionRequest.Encoding.GSM;
}
// Store the last sms event.
- last = new SmsSessionRequest (request.getSmppFrom(), request.getSmppTo(), request.getSmppContent(), encoding, null);
+
+ last = new SmsSessionRequest (request.getSmppFrom(), request.getSmppTo(), request.getSmppContent(), encoding, request.getTlvSet(), null);
if (initial == null) {
initial = last;
}
@@ -275,7 +294,7 @@ private void outbound(final Object message) {
if(logger.isInfoEnabled()) {
logger.info("Destination is not a local registered client, therefore, sending through SMPP to: " + last.to() );
}
- if (sendUsingSmpp(last.from(), last.to(), last.body(), charset))
+ if (sendUsingSmpp(last.from(), last.to(), last.body(), tlvSet, charset))
return;
}
@@ -332,16 +351,19 @@ private void outbound(final Object message) {
}
// Log the exception.
logger.error(exception.getMessage(), exception);
- }}
-
+ }
+ }
private boolean sendUsingSmpp(String from, String to, String body, Charset encoding) {
+ return sendUsingSmpp(from, to, body, null, encoding);
+ }
+ private boolean sendUsingSmpp(String from, String to, String body, TlvSet tlvSet, Charset encoding) {
if ((SmppClientOpsThread.getSmppSession() != null && SmppClientOpsThread.getSmppSession().isBound()) && smppMessageHandler != null) {
if(logger.isInfoEnabled()) {
logger.info("SMPP session is available and connected, outbound message will be forwarded to : " + to );
logger.info("Encoding: " + encoding );
}
try {
- final SmppOutboundMessageEntity sms = new SmppOutboundMessageEntity(to, from, body, encoding);
+ final SmppOutboundMessageEntity sms = new SmppOutboundMessageEntity(to, from, body, encoding, tlvSet);
smppMessageHandler.tell(sms, null);
}catch (final Exception exception) {
// Log the exception.
diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInboundMessageEntity.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInboundMessageEntity.java
index af640df549..00efb68030 100644
--- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInboundMessageEntity.java
+++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInboundMessageEntity.java
@@ -1,5 +1,7 @@
package org.restcomm.connect.sms.smpp;
+import org.restcomm.smpp.parameter.TlvSet;
+
import com.cloudhopper.commons.charset.Charset;
public class SmppInboundMessageEntity {
@@ -9,19 +11,24 @@ public class SmppInboundMessageEntity {
private final String smppFrom;
private final String smppContent;
private final Charset smppEncoding;
-
-
+ private final TlvSet tlvSet;
public SmppInboundMessageEntity(String smppTo, String smppFrom, String smppContent, Charset smppEncoding){
+ this(smppTo, smppFrom, smppContent, smppEncoding, null);
+ }
+ public SmppInboundMessageEntity(String smppTo, String smppFrom, String smppContent, Charset smppEncoding, TlvSet tlvSet){
this.smppTo = smppTo;
this.smppFrom = smppFrom;
this.smppContent = smppContent;
this.smppEncoding = smppEncoding;
+ this.tlvSet = tlvSet;
}
-
+ public final TlvSet getTlvSet(){
+ return tlvSet;
+ }
public final String getSmppTo(){
return smppTo;
diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppMessageHandler.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppMessageHandler.java
index 09a775ce98..a434af6ad7 100644
--- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppMessageHandler.java
+++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppMessageHandler.java
@@ -16,6 +16,7 @@
import com.cloudhopper.smpp.type.SmppInvalidArgumentException;
import com.cloudhopper.smpp.type.SmppTimeoutException;
import com.cloudhopper.smpp.type.UnrecoverablePduException;
+import com.cloudhopper.smpp.tlv.Tlv;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import org.apache.commons.configuration.Configuration;
import org.restcomm.connect.commons.dao.Sid;
@@ -26,12 +27,19 @@
import org.restcomm.connect.dao.IncomingPhoneNumbersDao;
import org.restcomm.connect.dao.entities.Application;
import org.restcomm.connect.dao.entities.IncomingPhoneNumber;
+import org.restcomm.connect.extension.api.ExtensionRequest;
+import org.restcomm.connect.extension.api.ExtensionResponse;
+import org.restcomm.connect.extension.api.ExtensionType;
+import org.restcomm.connect.extension.api.RestcommExtensionException;
+import org.restcomm.connect.extension.api.RestcommExtensionGeneric;
+import org.restcomm.connect.extension.controller.ExtensionController;
import org.restcomm.connect.interpreter.StartInterpreter;
import org.restcomm.connect.monitoringservice.MonitoringService;
import org.restcomm.connect.sms.SmsSession;
import org.restcomm.connect.sms.api.CreateSmsSession;
import org.restcomm.connect.sms.api.DestroySmsSession;
import org.restcomm.connect.sms.api.SmsServiceResponse;
+import org.restcomm.smpp.parameter.TlvSet;
import javax.servlet.ServletContext;
import javax.servlet.sip.SipFactory;
@@ -40,6 +48,7 @@
import java.io.IOException;
import java.net.URI;
import java.util.List;
+import java.util.Collection;
public class SmppMessageHandler extends UntypedActor {
@@ -50,6 +59,8 @@ public class SmppMessageHandler extends UntypedActor {
private final Configuration configuration;
private final SipFactory sipFactory;
private final ActorRef monitoringService;
+ //List of extensions for SmsService
+ List extensions;
public SmppMessageHandler(final ServletContext servletContext) {
this.servletContext = servletContext;
@@ -57,6 +68,11 @@ public SmppMessageHandler(final ServletContext servletContext) {
this.configuration = (Configuration) servletContext.getAttribute(Configuration.class.getName());
this.sipFactory = (SipFactory) servletContext.getAttribute(SipFactory.class.getName());
this.monitoringService = (ActorRef) servletContext.getAttribute(MonitoringService.class.getName());
+ //FIXME:Should new ExtensionType.SmppMessageHandler be defined?
+ extensions = ExtensionController.getInstance().getExtensions(ExtensionType.SmsService);
+ if (logger.isInfoEnabled()) {
+ logger.info("SmsService extensions: "+(extensions != null ? extensions.size() : "0"));
+ }
}
@Override
@@ -64,6 +80,7 @@ public void onReceive(Object message) throws Exception {
final UntypedActorContext context = getContext();
final ActorRef sender = sender();
final ActorRef self = self();
+ ExtensionController ec = ExtensionController.getInstance();
if (message instanceof SmppInboundMessageEntity){
if(logger.isInfoEnabled()) {
logger.info("SmppMessageHandler processing Inbound Message " + message.toString());
@@ -75,9 +92,20 @@ public void onReceive(Object message) throws Exception {
}
outbound((SmppOutboundMessageEntity) message);
} else if (message instanceof CreateSmsSession) {
- final ActorRef session = session();
- final SmsServiceResponse response = new SmsServiceResponse(session);
- sender.tell(response, self);
+ ExtensionRequest er = new ExtensionRequest();
+ er.setObject(message);
+ er.setConfiguration(this.configuration);
+ ExtensionResponse extensionResponse = ec.executePreOutboundAction(er, this.extensions);
+ if (extensionResponse.isAllowed()) {
+ Object obj = ec.handleExtensionResponse(extensionResponse, this.configuration);
+ final ActorRef session = session((Configuration)obj);
+ final SmsServiceResponse response = new SmsServiceResponse(session);
+ sender.tell(response, self);
+ } else {
+ final SmsServiceResponse response = new SmsServiceResponse(new RestcommExtensionException("Now allowed to create SmsSession"));
+ sender.tell(response, self());
+ }
+ ec.executePostOutboundAction(message, this.extensions);
}else if (message instanceof DestroySmsSession) {
final DestroySmsSession destroySmsSession = (DestroySmsSession) message;
final ActorRef session = destroySmsSession.session();
@@ -153,8 +181,9 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SmppInboundMes
builder.setFallbackMethod(number.getSmsFallbackMethod());
}
interpreter = builder.build();
-
- final ActorRef session = session();
+ Configuration cfg = this.configuration;
+ //Extension
+ final ActorRef session = session(cfg);
session.tell(request, self);
final StartInterpreter start = new StartInterpreter(session);
interpreter.tell(start, self);
@@ -181,13 +210,13 @@ private SipURI outboundInterface() {
return result;
}
- private ActorRef session() {
+ private ActorRef session(final Configuration p_configuration) {
final Props props = new Props(new UntypedActorFactory() {
private static final long serialVersionUID = 1L;
@Override
public UntypedActor create() throws Exception {
- return new SmsSession(configuration, sipFactory, outboundInterface(), storage, monitoringService, servletContext);
+ return new SmsSession(p_configuration, sipFactory, outboundInterface(), storage, monitoringService, servletContext);
}
});
return system.actorOf(props);
@@ -214,6 +243,18 @@ public void outbound(SmppOutboundMessageEntity request) throws SmppInvalidArgume
}
submit0.setShortMessage(textBytes);
+
+ TlvSet tlvSet = request.getTlvSet();
+
+ if(tlvSet!=null) {
+ for (Tlv tlv : (Collection)tlvSet.getOptionalParameters()) {
+ submit0.setOptionalParameter(tlv);
+ }
+ }else{
+ if(logger.isInfoEnabled()) {
+ logger.info("TlvSet is null");
+ }
+ }
try {
if(logger.isInfoEnabled()) {
logger.info("Sending SubmitSM for " + request);
diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppOutboundMessageEntity.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppOutboundMessageEntity.java
index 3c2f4942b0..e70d1fdff6 100644
--- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppOutboundMessageEntity.java
+++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppOutboundMessageEntity.java
@@ -1,5 +1,7 @@
package org.restcomm.connect.sms.smpp;
+import org.restcomm.smpp.parameter.TlvSet;
+
import com.cloudhopper.commons.charset.Charset;
public class SmppOutboundMessageEntity {
@@ -9,15 +11,23 @@ public class SmppOutboundMessageEntity {
private final String smppFrom;
private final String smppContent;
private final Charset smppEncoding;
+ private final TlvSet tlvSet;
public SmppOutboundMessageEntity(String smppTo, String smppFrom, String smppContent, Charset smppEncoding){
+ this(smppTo, smppFrom, smppContent, smppEncoding, null);
+ }
+ public SmppOutboundMessageEntity(String smppTo, String smppFrom, String smppContent, Charset smppEncoding, TlvSet tlvSet){
this.smppTo = smppTo;
this.smppFrom = smppFrom;
this.smppContent = smppContent;
this.smppEncoding = smppEncoding;
+ this.tlvSet = tlvSet;
+ }
+ public final TlvSet getTlvSet(){
+ return tlvSet;
}
@@ -48,6 +58,10 @@ public String toString() {
.append(smppContent)
.append(",Encoding=")
.append(smppEncoding);
+ if(tlvSet!=null){
+ builder.append(",TlvSet=")
+ .append(tlvSet.toString());
+ }
return super.toString();
}
diff --git a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManager.java b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManager.java
index da76d16b7b..bc9bc7eda5 100644
--- a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManager.java
+++ b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManager.java
@@ -30,10 +30,13 @@
import akka.event.Logging;
import akka.event.LoggingAdapter;
import akka.util.Timeout;
+
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
+
import gov.nist.javax.sip.header.UserAgent;
+
import org.apache.commons.configuration.Configuration;
import org.joda.time.DateTime;
import org.restcomm.connect.commons.configuration.RestcommConfiguration;
@@ -57,6 +60,7 @@
import org.restcomm.connect.dao.entities.Notification;
import org.restcomm.connect.dao.entities.Registration;
import org.restcomm.connect.extension.api.CallRequest;
+import org.restcomm.connect.extension.api.ExtensionRequest;
import org.restcomm.connect.extension.api.ExtensionResponse;
import org.restcomm.connect.extension.api.ExtensionType;
import org.restcomm.connect.extension.api.RestcommExtensionException;
@@ -86,6 +90,7 @@
import org.restcomm.connect.telephony.api.UpdateCallScript;
import org.restcomm.connect.telephony.api.util.B2BUAHelper;
import org.restcomm.connect.telephony.api.util.CallControlHelper;
+
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;
@@ -105,6 +110,7 @@
import javax.servlet.sip.TelURL;
import javax.sip.header.RouteHeader;
import javax.sip.message.Response;
+
import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
@@ -476,9 +482,14 @@ private void invite(final Object message) throws IOException, NumberParseExcepti
if(logger.isInfoEnabled()) {
logger.info("Client is not null: " + client.getLogin() + " will try to proxy to client: "+ toClient);
}
+
CallRequest callRequest = new CallRequest(fromUser, toUser, CallRequest.Type.CLIENT,
client.getAccountSid(), false, false);
- if (executePreOutboundAction(callRequest)) {
+ ExtensionController ec = ExtensionController.getInstance();
+ ExtensionRequest er = new ExtensionRequest();
+ er.setObject(callRequest);
+ ExtensionResponse extensionResponse = ec.executePreOutboundAction(er, this.extensions);
+ if (extensionResponse.isAllowed()) {
if (B2BUAHelper.redirectToB2BUA(request, client, toClient, storage, sipFactory, patchForNatB2BUASessions)) {
if(logger.isInfoEnabled()) {
logger.info("Call to CLIENT. myHostIp: " + myHostIp + " mediaExternalIp: " + mediaExternalIp + " toHost: "
@@ -505,7 +516,7 @@ private void invite(final Object message) throws IOException, NumberParseExcepti
final SipServletResponse resp = request.createResponse(SC_FORBIDDEN, "Call not allowed");
resp.send();
}
- executePostOutboundAction(callRequest);
+ ec.executePostOutboundAction(callRequest, this.extensions);
return;
} else {
// toClient is null or we couldn't make the b2bua call to another client. check if this call is for a registered
@@ -536,7 +547,11 @@ private void invite(final Object message) throws IOException, NumberParseExcepti
if (proxyURI != null && !proxyURI.isEmpty()) {
// String destination = ((SipURI)request.getTo().getURI()).getUser();
CallRequest callRequest = new CallRequest(fromUser,toUser, CallRequest.Type.PSTN, client.getAccountSid(), false, false);
- if (executePreOutboundAction(callRequest)) {
+ ExtensionController ec = ExtensionController.getInstance();
+ ExtensionRequest er = new ExtensionRequest();
+ er.setObject(callRequest);
+ ExtensionResponse extensionResponse = ec.executePreOutboundAction(er, this.extensions);
+ if (extensionResponse.isAllowed()) {
proxyOut(request, client, toUser, toHost, toHostIpAddress, toPort, outboundIntf, proxyURI, proxyUsername, proxyPassword, from, to, callToSipUri);
} else {
final SipServletResponse response = request.createResponse(SC_FORBIDDEN, "Call request not allowed");
@@ -545,7 +560,7 @@ private void invite(final Object message) throws IOException, NumberParseExcepti
logger.debug("Call request now allowed: "+callRequest.toString());
}
}
- executePostOutboundAction(callRequest);
+ ec.executePostOutboundAction(callRequest, this.extensions);
return;
} else {
String msg = "Restcomm tried to proxy this call to an outbound party but it seems the outbound proxy is not configured.";
@@ -1484,9 +1499,13 @@ private void update(final Object message) throws Exception {
private void outbound(final Object message, final ActorRef sender) throws ServletParseException {
final CreateCall request = (CreateCall) message;
CallRequest callRequest = new CallRequest(request.from(), request.to(), CallRequest.Type.valueOf(request.type().name()), request.accountId(), request.isFromApi(), request.parentCallSid() != null);
+ ExtensionController ec = ExtensionController.getInstance();
+ ExtensionRequest er = new ExtensionRequest();
+ er.setObject(callRequest);
+ ExtensionResponse extensionResponse = ec.executePreOutboundAction(er, this.extensions);
switch (request.type()) {
case CLIENT: {
- if (executePreOutboundAction(callRequest)) {
+ if (extensionResponse.isAllowed()) {
outboundToClient(request, sender);
} else {
//Extensions didn't allowed this call
@@ -1494,11 +1513,11 @@ private void outbound(final Object message, final ActorRef sender) throws Servle
logger.warning(errMsg);
sender.tell(new CallManagerResponse(new RestcommExtensionException(errMsg), this.createCallRequest), self());
}
- executePostOutboundAction(callRequest);
+ ec.executePostOutboundAction(callRequest, this.extensions);
break;
}
case PSTN: {
- if (executePreOutboundAction(callRequest)) {
+ if (extensionResponse.isAllowed()) {
outboundToPstn(request, sender);
} else {
//Extensions didn't allowed this call
@@ -1506,14 +1525,14 @@ private void outbound(final Object message, final ActorRef sender) throws Servle
logger.warning(errMsg);
sender.tell(new CallManagerResponse(new RestcommExtensionException(errMsg), this.createCallRequest), self());
}
- executePostOutboundAction(callRequest);
+ ec.executePostOutboundAction(callRequest, this.extensions);
break;
}
case SIP: {
if (actAsImsUa) {
outboundToIms(request, sender);
}
- else if (executePreOutboundAction(callRequest)) {
+ else if (extensionResponse.isAllowed()) {
outboundToSip(request, sender);
} else {
//Extensions didn't allowed this call
@@ -1521,29 +1540,12 @@ else if (executePreOutboundAction(callRequest)) {
logger.warning(errMsg);
sender.tell(new CallManagerResponse(new RestcommExtensionException(errMsg), this.createCallRequest), self());
}
- executePostOutboundAction(callRequest);
+ ec.executePostOutboundAction(callRequest, this.extensions);
break;
}
}
}
- private boolean executePreOutboundAction(final Object message) {
- if (extensions != null && extensions.size() > 0) {
- for (RestcommExtensionGeneric extension : extensions) {
- if (extension.isEnabled()) {
- ExtensionResponse response = extension.preOutboundAction(message);
- if (!response.isAllowed())
- return false;
- }
- }
- }
- return true;
- }
-
- private boolean executePostOutboundAction(final CallRequest callRequest) {
- return false;
- }
-
private void outboundToClient(final CreateCall request, final ActorRef sender) throws ServletParseException {
SipURI outboundIntf = null;
SipURI from = null;