# HG changeset patch
# User Augusto Mauch <augusto.mauch@openbravo.com>
# Date 1477585117 -7200
#      Thu Oct 27 18:18:37 2016 +0200
# Node ID 846ddd8a000b1775e2682ac5b10774244329bc69
# Parent  fa1155a3635ec5852cc715dc6692bab611647026
Fixes issue 34224: SymmetricDS triggers can be disabled programatically

The class SymmetricDSTriggerHandler enables/reenables the SymmetricDS in a similar way the TriggerHandler class does the same with the standard Openbravo triggers.

A column called EM_Strsync_Symds_Trg_Disabled has been added to ad_session_status, the SymmetricDSTriggerHandler trigger adds a record with that column set to 'TRUE' to soft disable the triggers. The SymmetricDS triggers are now appended by a check that calls the function STRSYNC_ISTRIGGERENABLED, it will soft disable the trigger if it returns true.

This fix depends on the fix of this issue [1] to be compatible with the TriggerHandler. Without this change, calling TriggerHandler.enable will result in the SymmetricDS triggers being enabled to.

In the future the SymmetricDSTriggerHandler might be updated to use a temporary table instead of ad_session_status. This way it can be ensured that the insertions done to the table are not accidentally commited in the database.

[1] https://issues.openbravo.com/view.php?id=34323

diff --git a/src-db/database/model/functions/STRSYNC_ISTRIGGERENABLED.xml b/src-db/database/model/functions/STRSYNC_ISTRIGGERENABLED.xml
new file mode 100644
--- /dev/null
+++ b/src-db/database/model/functions/STRSYNC_ISTRIGGERENABLED.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+  <database name="FUNCTION STRSYNC_ISTRIGGERENABLED">
+    <function name="STRSYNC_ISTRIGGERENABLED" type="CHAR">
+      <body><![CDATA[/**************************************************************************
+ * Openbravo DB Synchronization module
+ * Copyright (C) 2016 Openbravo SLU 
+ *
+ * The content of this file 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.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *************************************************************************/
+ v_aux CHAR;
+BEGIN
+  SELECT CASE WHEN EXISTS(SELECT 1 
+                          FROM ad_session_status
+                          WHERE em_strsync_symds_trg_disabled = 'Y') 
+              THEN 'N' 
+              ELSE 'Y' 
+              END 
+  INTO v_aux;
+  RETURN v_aux;
+EXCEPTION
+WHEN OTHERS THEN
+  RETURN 'Y';
+END STRSYNC_ISTRIGGERENABLED
+]]></body>
+    </function>
+  </database>
diff --git a/src-db/database/model/modifiedTables/AD_SESSION_STATUS.xml b/src-db/database/model/modifiedTables/AD_SESSION_STATUS.xml
new file mode 100644
--- /dev/null
+++ b/src-db/database/model/modifiedTables/AD_SESSION_STATUS.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+  <database name="MODIFIED TABLE AD_SESSION_STATUS">
+    <table name="AD_SESSION_STATUS" primaryKey="AD_SESSION_STATUS_KEY">
+      <column name="EM_STRSYNC_SYMDS_TRG_DISABLED" primaryKey="false" required="true" type="CHAR" size="1" autoIncrement="false">
+        <default><![CDATA[N]]></default>
+        <onCreateDefault/>
+      </column>
+    </table>
+  </database>
diff --git a/src-db/database/sourcedata/AD_COLUMN.xml b/src-db/database/sourcedata/AD_COLUMN.xml
--- a/src-db/database/sourcedata/AD_COLUMN.xml
+++ b/src-db/database/sourcedata/AD_COLUMN.xml
@@ -564,6 +564,42 @@
 <!--219A5C5528FF4C3DAB4E726CFDA35BB6-->  <ALLOWED_CROSS_ORG_LINK><![CDATA[N]]></ALLOWED_CROSS_ORG_LINK>
 <!--219A5C5528FF4C3DAB4E726CFDA35BB6--></AD_COLUMN>
 
+<!--2AB8CFE807D847E4AA9624E902009206--><AD_COLUMN>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <AD_COLUMN_ID><![CDATA[2AB8CFE807D847E4AA9624E902009206]]></AD_COLUMN_ID>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <NAME><![CDATA[EM_Strsync_Symds_Trg_Disabled]]></NAME>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <COLUMNNAME><![CDATA[EM_Strsync_Symds_Trg_Disabled]]></COLUMNNAME>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <AD_TABLE_ID><![CDATA[BBB7275AB448478885E0FB24AA4BCB0B]]></AD_TABLE_ID>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <AD_REFERENCE_ID><![CDATA[20]]></AD_REFERENCE_ID>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <FIELDLENGTH><![CDATA[1]]></FIELDLENGTH>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <DEFAULTVALUE><![CDATA[N]]></DEFAULTVALUE>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISKEY><![CDATA[N]]></ISKEY>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISPARENT><![CDATA[N]]></ISPARENT>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISMANDATORY><![CDATA[Y]]></ISMANDATORY>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISUPDATEABLE><![CDATA[Y]]></ISUPDATEABLE>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISIDENTIFIER><![CDATA[N]]></ISIDENTIFIER>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <SEQNO><![CDATA[100]]></SEQNO>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISTRANSLATED><![CDATA[N]]></ISTRANSLATED>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISENCRYPTED><![CDATA[N]]></ISENCRYPTED>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISSELECTIONCOLUMN><![CDATA[N]]></ISSELECTIONCOLUMN>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISSESSIONATTR><![CDATA[N]]></ISSESSIONATTR>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISSECONDARYKEY><![CDATA[N]]></ISSECONDARYKEY>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISDESENCRYPTABLE><![CDATA[N]]></ISDESENCRYPTABLE>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <DEVELOPMENTSTATUS><![CDATA[RE]]></DEVELOPMENTSTATUS>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <AD_MODULE_ID><![CDATA[ADF9A88E7EE541FE8629FE741A6F96F9]]></AD_MODULE_ID>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <POSITION><![CDATA[10]]></POSITION>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISTRANSIENT><![CDATA[N]]></ISTRANSIENT>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISAUTOSAVE><![CDATA[Y]]></ISAUTOSAVE>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <VALIDATEONNEW><![CDATA[Y]]></VALIDATEONNEW>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <IMAGESIZEVALUESACTION><![CDATA[N]]></IMAGESIZEVALUESACTION>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ISUSEDSEQUENCE><![CDATA[N]]></ISUSEDSEQUENCE>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ALLOWSORTING><![CDATA[Y]]></ALLOWSORTING>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ALLOWFILTERING><![CDATA[Y]]></ALLOWFILTERING>
+<!--2AB8CFE807D847E4AA9624E902009206-->  <ALLOWED_CROSS_ORG_LINK><![CDATA[N]]></ALLOWED_CROSS_ORG_LINK>
+<!--2AB8CFE807D847E4AA9624E902009206--></AD_COLUMN>
+
 <!--2F739BA9ADA64281840F37F2BCBD3DE5--><AD_COLUMN>
 <!--2F739BA9ADA64281840F37F2BCBD3DE5-->  <AD_COLUMN_ID><![CDATA[2F739BA9ADA64281840F37F2BCBD3DE5]]></AD_COLUMN_ID>
 <!--2F739BA9ADA64281840F37F2BCBD3DE5-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
diff --git a/src/org/openbravo/replication/symmetricds/SymmetricDSConfiguration_data.xsql b/src/org/openbravo/replication/symmetricds/SymmetricDSConfiguration_data.xsql
--- a/src/org/openbravo/replication/symmetricds/SymmetricDSConfiguration_data.xsql
+++ b/src/org/openbravo/replication/symmetricds/SymmetricDSConfiguration_data.xsql
@@ -219,8 +219,14 @@
        <Sql> 
        <![CDATA[ 
            insert into sym_trigger 
-             (trigger_id,source_table_name,channel_id,sync_on_update, sync_on_insert, sync_on_delete, name_for_update_trigger,name_for_insert_trigger, name_for_delete_trigger, excluded_column_names, sync_on_incoming_batch, use_capture_lobs, last_update_time,create_time) 
-           VALUES (?,?,?,to_number(?),to_number(?),to_number(?),?,?,?,?,to_number(?),1,current_timestamp,current_timestamp)
+             (trigger_id,source_table_name,channel_id,sync_on_update, sync_on_insert, sync_on_delete, 
+             name_for_update_trigger,name_for_insert_trigger, name_for_delete_trigger, 
+             sync_on_update_condition, sync_on_insert_condition ,sync_on_delete_condition,             
+             excluded_column_names, sync_on_incoming_batch, use_capture_lobs, last_update_time,create_time) 
+           VALUES (?,?,?,to_number(?),to_number(?),to_number(?),
+                   ?,?,?,
+                   ?, ?, ?,
+                   ?,to_number(?),1,current_timestamp,current_timestamp)
          ]]>
         </Sql>
     <Parameter name="triggerId"/>
@@ -232,6 +238,9 @@
     <Parameter name="updateTriggerName"/>
     <Parameter name="insertTriggerName"/>
     <Parameter name="deleteTriggerName"/>
+    <Parameter name="triggerEnablementCondition"/>
+    <Parameter name="triggerEnablementCondition"/>
+    <Parameter name="triggerEnablementCondition"/>
     <Parameter name="excludedColumnNames"/>
     <Parameter name="syncOnIncomingBatch"/>
    </SqlMethod>
diff --git a/src/org/openbravo/replication/symmetricds/SymmetricDsTablePopulator.java b/src/org/openbravo/replication/symmetricds/SymmetricDsTablePopulator.java
--- a/src/org/openbravo/replication/symmetricds/SymmetricDsTablePopulator.java
+++ b/src/org/openbravo/replication/symmetricds/SymmetricDsTablePopulator.java
@@ -245,7 +245,8 @@
         fromStringBooleanToNumericString(synchronizedTable.synchUpdates),
         fromStringBooleanToNumericString(synchronizedTable.synchInserts),
         fromStringBooleanToNumericString(synchronizedTable.synchDeletes), updateTriggerName,
-        insertTriggerName, deleteTriggerName, excludedPropertiesNames, syncOnIncomingBatch);
+        insertTriggerName, deleteTriggerName, "STRSYNC_ISTRIGGERENABLED()='Y'",
+        excludedPropertiesNames, syncOnIncomingBatch);
 
     if ("Y".equals(synchronizedTable.synchUpdates)) {
       System.out.println("            Adding metadata for trigger " + updateTriggerName);
diff --git a/src/org/openbravo/replication/symmetricds/util/SymmetricDSTriggerHandler.java b/src/org/openbravo/replication/symmetricds/util/SymmetricDSTriggerHandler.java
new file mode 100644
--- /dev/null
+++ b/src/org/openbravo/replication/symmetricds/util/SymmetricDSTriggerHandler.java
@@ -0,0 +1,121 @@
+/*
+ *************************************************************************
+ * Openbravo DB Synchronization module
+ * Copyright (C) 2016 Openbravo SLU 
+ *
+ * The content of this file 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.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ ************************************************************************
+ */
+
+package org.openbravo.replication.symmetricds.util;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import org.apache.log4j.Logger;
+import org.openbravo.base.exception.OBException;
+import org.openbravo.base.provider.OBProvider;
+import org.openbravo.base.util.Check;
+import org.openbravo.dal.service.OBDal;
+
+/**
+ * Supports disabling and again enabling of the triggers SymmetricDS places on the Openbravo tables.
+ * 
+ * The user of this class should call disable() after beginning the transaction and enable at the
+ * end, before committing.
+ * 
+ */
+
+public class SymmetricDSTriggerHandler {
+  private static final Logger log = Logger.getLogger(SymmetricDSTriggerHandler.class);
+
+  private static SymmetricDSTriggerHandler instance;
+
+  public static SymmetricDSTriggerHandler getInstance() {
+    if (instance == null) {
+      instance = OBProvider.getInstance().get(SymmetricDSTriggerHandler.class);
+    }
+    return instance;
+  }
+
+  private ThreadLocal<Boolean> sessionStatus = new ThreadLocal<Boolean>();
+
+  /**
+   * Disabled all triggers in the database. This is done by creating an ADSessionStatus object and
+   * storing it in the AD_SESSION_STATUS table. Note: this method will also call
+   * {@link OBDal#flush() OBDal.flush()}.
+   */
+  public void disable() {
+    log.debug("Disabling SymmetricDS triggers");
+    Check.isNull(sessionStatus.get(), "There is already a ADSessionStatus present in this thread, "
+        + "call enable before calling disable again");
+    Connection con = OBDal.getInstance().getConnection();
+    PreparedStatement ps = null;
+    try {
+      ps = con
+          .prepareStatement("INSERT INTO AD_SESSION_STATUS(ad_session_status_id, ad_client_id, ad_org_id, createdby, updatedby, isimporting, em_strsync_symds_trg_disabled)  VALUES (get_uuid(), '0', '0', '0', '0', 'N', 'Y')");
+      ps.executeUpdate();
+      sessionStatus.set(Boolean.TRUE);
+    } catch (Exception e) {
+      throw new OBException("Couldn't disable triggers: ", e);
+    } finally {
+      try {
+        ps.close();
+      } catch (SQLException e) {
+      }
+    }
+  }
+
+  /**
+   * @return true if the database triggers are disabled, false in other cases.
+   */
+  public boolean isDisabled() {
+    return sessionStatus.get() != null;
+  }
+
+  /**
+   * Clears the SessionStatus from the threadlocal, must be done in case of rollback
+   */
+  public void clear() {
+    sessionStatus.set(null);
+  }
+
+  /**
+   * Enables triggers in the database. It does this by removing the ADSessionStatus from the
+   * database.
+   */
+  public void enable() {
+    log.debug("Enabling triggers");
+    Check.isNotNull(sessionStatus.get(), "SessionStatus not set, call disable "
+        + "before calling this method");
+
+    Connection con = OBDal.getInstance().getConnection();
+    PreparedStatement ps = null;
+    try {
+      ps = con
+          .prepareStatement("DELETE FROM ad_session_status WHERE em_strsync_symds_trg_disabled = 'Y'");
+      ps.executeUpdate();
+    } catch (Exception e) {
+      throw new OBException("Couldn't disable triggers: ", e);
+    } finally {
+      // always clear the threadlocal
+      clear();
+      try {
+        ps.close();
+      } catch (SQLException e) {
+      }
+    }
+  }
+}
\ No newline at end of file
