├── .gitignore ├── LICENSE ├── README.md └── src ├── classes ├── AccountTriggerHandler.cls ├── AccountTriggerHandler.cls-meta.xml ├── TriggerHandler.cls ├── TriggerHandler.cls-meta.xml ├── TriggerHandlerManager.cls └── TriggerHandlerManager.cls-meta.xml └── triggers ├── AccountTrigger.trigger └── AccountTrigger.trigger-meta.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Xiaoan Lin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SFDC Apex Trigger Framework 2 | @see https://www.xgeek.net/salesforce/a-simple-salesforce-trigger-framework/ 3 | 4 | 5 | Deploy to Salesforce 7 | 8 | 9 | Well,this is another Salesforce Trigger framework but more simple. 10 | 11 | ## Usage 12 | ###AccountTriggerHandler.cls 13 | ```java 14 | //This is a sample code for AccountTriggerHandler 15 | public class AccountTriggerHandler extends TriggerHandler{ 16 | 17 | public override void beforeInsert(){ 18 | System.debug( 'AccountTriggerHandler beforeInsert Start' ); 19 | 20 | System.debug( 'Trigger.isExecuting : ' + isExecuting ); 21 | System.debug( 'Trigger.isInsert : ' + isInsert ); 22 | System.debug( 'Trigger.isUpdate : ' + isUpdate ); 23 | System.debug( 'Trigger.isDelete : ' + isDelete ); 24 | System.debug( 'Trigger.isBefore : ' + isBefore ); 25 | System.debug( 'Trigger.isAfter : ' + isAfter ); 26 | System.debug( 'Trigger.isUndelete : ' + isUndelete ); 27 | System.debug( 'Trigger.new : ' + newList ); 28 | System.debug( 'Trigger.newMap : ' + newMap ); 29 | System.debug( 'Trigger.old : ' + oldList ); 30 | System.debug( 'Trigger.oldMap : ' + oldMap ); 31 | System.debug( 'Trigger.size : ' + size ); 32 | 33 | System.debug('AccountTriggerHandler beforeInsert End'); 34 | } 35 | 36 | public override void afterInsert(){ 37 | System.debug('AccountTriggerHandler afterInsert Start'); 38 | } 39 | 40 | public override void beforeUpdate(){ 41 | System.debug('AccountTriggerHandler beforeUpdate Start'); 42 | } 43 | 44 | public override void afterUpdate(){ 45 | System.debug('AccountTriggerHandler afterUpdate Start'); 46 | } 47 | 48 | public override void beforeDelete(){ 49 | System.debug('AccountTriggerHandler beforeDelete Start'); 50 | } 51 | 52 | public override void afterDelete(){ 53 | System.debug('AccountTriggerHandler afterDelete Start'); 54 | } 55 | 56 | public override void afterUndelete(){ 57 | System.debug('AccountTriggerHandler afterUndelete Start'); 58 | } 59 | 60 | } 61 | ``` 62 | ###AccountTrigger.trigger 63 | ####In normal case. 64 | ```java 65 | trigger AccountTrigger on Account (before delete, before insert, before update, 66 | after delete, after insert, after update,after Undelete) { 67 | TriggerHandlerManager handlerManager = new TriggerHandlerManager(); 68 | handlerManager.add( new AccountTriggerHandler() ); 69 | handlerManager.run(); 70 | } 71 | ``` 72 | ####Other cases 73 | Stop and resume sObject Trigger in APEX code 74 | ```java 75 | TriggerHandlerManager.stop( 'CustomObject__c' ); 76 | TriggerHandlerManager.resume( 'CustomObject__c' ); 77 | ``` 78 | Stop and resume a TriggerHandler in APEX code 79 | ```java 80 | TriggerHandlerManager.stop( 'AccountTriggerHandler' ); 81 | TriggerHandlerManager.resume( 'AccountTriggerHandler' ); 82 | ``` 83 | -------------------------------------------------------------------------------- /src/classes/AccountTriggerHandler.cls: -------------------------------------------------------------------------------- 1 | //Sample code for AccountTriggerHandler 2 | public class AccountTriggerHandler extends TriggerHandler{ 3 | 4 | public override void beforeInsert(){ 5 | System.debug( 'AccountTriggerHandler beforeInsert Start' ); 6 | 7 | System.debug( 'Trigger.isExecuting : ' + isExecuting ); 8 | System.debug( 'Trigger.isInsert : ' + isInsert ); 9 | System.debug( 'Trigger.isUpdate : ' + isUpdate ); 10 | System.debug( 'Trigger.isDelete : ' + isDelete ); 11 | System.debug( 'Trigger.isBefore : ' + isBefore ); 12 | System.debug( 'Trigger.isAfter : ' + isAfter ); 13 | System.debug( 'Trigger.isUndelete : ' + isUndelete ); 14 | System.debug( 'Trigger.new : ' + newList ); 15 | System.debug( 'Trigger.newMap : ' + newMap ); 16 | System.debug( 'Trigger.old : ' + oldList ); 17 | System.debug( 'Trigger.oldMap : ' + oldMap ); 18 | System.debug( 'Trigger.size : ' + size ); 19 | 20 | System.debug('AccountTriggerHandler beforeInsert End'); 21 | } 22 | 23 | public override void afterInsert(){ 24 | System.debug('AccountTriggerHandler afterInsert Start'); 25 | } 26 | 27 | public override void beforeUpdate(){ 28 | System.debug('AccountTriggerHandler beforeUpdate Start'); 29 | } 30 | 31 | public override void afterUpdate(){ 32 | System.debug('AccountTriggerHandler afterUpdate Start'); 33 | } 34 | 35 | public override void beforeDelete(){ 36 | System.debug('AccountTriggerHandler beforeDelete Start'); 37 | } 38 | 39 | public override void afterDelete(){ 40 | System.debug('AccountTriggerHandler afterDelete Start'); 41 | } 42 | 43 | public override void afterUndelete(){ 44 | System.debug('AccountTriggerHandler afterUndelete Start'); 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /src/classes/AccountTriggerHandler.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/TriggerHandler.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012, Xgeek.net, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the Xgeek.net, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | public virtual class TriggerHandler{ 28 | 29 | protected Boolean isExecuting = Trigger.isExecuting; 30 | protected Boolean isInsert = Trigger.isInsert; 31 | protected Boolean isUpdate = Trigger.isUpdate; 32 | protected Boolean isDelete = Trigger.isDelete; 33 | protected Boolean isBefore = Trigger.isBefore; 34 | protected Boolean isAfter = Trigger.isAfter; 35 | protected Boolean isUndelete = Trigger.isUndelete; 36 | protected List newList = Trigger.new; 37 | protected Map newMap = Trigger.newMap; 38 | protected List oldList = Trigger.old; 39 | protected Map oldMap = Trigger.oldMap; 40 | protected Integer size = Trigger.size; 41 | 42 | /** 43 | * Get TriggerHandler class name 44 | * @return String Class Name 45 | */ 46 | public String getName(){ 47 | return String.valueOf( this ).split( ':' )[0]; 48 | } 49 | 50 | /** 51 | * Get sObject name from Trigger 52 | * @return String sObject Name 53 | */ 54 | public String getObjectName(){ 55 | if( newList != null && !newList.isEmpty() ) return newList[0].getSObjectType().getDescribe().getName(); 56 | else return oldList[0].getSObjectType().getDescribe().getName(); 57 | } 58 | 59 | public virtual void beforeInsert(){} 60 | 61 | public virtual void beforeUpdate(){} 62 | 63 | public virtual void beforeDelete(){} 64 | 65 | public virtual void afterInsert(){} 66 | 67 | public virtual void afterUpdate(){} 68 | 69 | public virtual void afterDelete(){} 70 | 71 | public virtual void afterUndelete(){} 72 | 73 | } -------------------------------------------------------------------------------- /src/classes/TriggerHandler.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/TriggerHandlerManager.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012, Xgeek.net, inc 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * - Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * - Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * - Neither the name of the Xgeek.net, inc nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | public class TriggerHandlerManager{ 28 | 29 | private List handlerList = new List(); 30 | 31 | private static Map handlerLockMap = new Map(); 32 | 33 | /** 34 | * Add a TriggerHandler 35 | * @param TriggerHandler handler 36 | */ 37 | public void add( TriggerHandler handler ) { 38 | 39 | handlerList.add( handler ); 40 | } 41 | 42 | /** 43 | * Run Trigger Handlers 44 | */ 45 | public void run() { 46 | 47 | if( handlerList.isEmpty() ) return; 48 | 49 | for( TriggerHandler handler : handlerList ) { 50 | //TriggerHandler has been locked. 51 | if( isHandlerLock( handler.getName() ) ) continue; 52 | //sObject Trigger has been locked. 53 | if( isHandlerLock( handler.getObjectName() ) ) continue; 54 | 55 | if( Trigger.isBefore && Trigger.isInsert ) { 56 | handler.beforeInsert(); 57 | } else if( Trigger.isBefore && Trigger.isUpdate ) { 58 | handler.beforeUpdate(); 59 | } else if( Trigger.isBefore && Trigger.isDelete ) { 60 | handler.beforeDelete(); 61 | } else if( Trigger.isAfter && Trigger.isInsert ) { 62 | handler.afterInsert(); 63 | } else if( Trigger.isAfter && Trigger.isUpdate ) { 64 | handler.afterUpdate(); 65 | } else if( Trigger.isAfter && Trigger.isDelete ) { 66 | handler.afterDelete(); 67 | } else if( Trigger.isAfter && Trigger.isUndelete ) { 68 | handler.afterUndelete(); 69 | } 70 | } 71 | } 72 | 73 | /** 74 | * Stop a TriggerHandler 75 | * @param String TriggerHandler class name 76 | * @return none 77 | */ 78 | public static void stop( String handlerName ) { 79 | 80 | handlerLockMap.put( handlerName, true ); 81 | } 82 | /** 83 | * Resume a TriggerHandler 84 | * @param String TriggerHandler class name 85 | * @return none 86 | */ 87 | public static void resume( String handlerName ) { 88 | 89 | handlerLockMap.put( handlerName, false ); 90 | } 91 | 92 | //TriggerHandler or sObject is locked 93 | private Boolean isHandlerLock( String handlerName ) { 94 | 95 | if( !handlerLockMap.containsKey( handlerName ) ) return false; 96 | 97 | Boolean isLock = handlerLockMap.get( handlerName ); 98 | return isLock; 99 | } 100 | 101 | } -------------------------------------------------------------------------------- /src/classes/TriggerHandlerManager.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/triggers/AccountTrigger.trigger: -------------------------------------------------------------------------------- 1 | trigger AccountTrigger on Account (before delete, before insert, before update, 2 | after delete, after insert, after update, 3 | after Undelete) { 4 | 5 | //TriggerHandlerManager.stop( 'CustomObject__c' ); 6 | //TriggerHandlerManager.resume( 'CustomObject__c' ); 7 | TriggerHandlerManager handlerManager = new TriggerHandlerManager(); 8 | handlerManager.add( new AccountTriggerHandler() ); 9 | handlerManager.run(); 10 | //TriggerHandlerManager.stop( 'AccountTriggerHandler' ); 11 | //TriggerHandlerManager.resume( 'AccountTriggerHandler' ); 12 | } -------------------------------------------------------------------------------- /src/triggers/AccountTrigger.trigger-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 32.0 4 | Active 5 | 6 | --------------------------------------------------------------------------------