SyncConfigChangesAspect.java

/*
** Module   : SyncConfigChangesAspect.java
** Abstract : Aspect to help automate synchronization of config changes with config owners. 
**
** Copyright (c) 2015-2018, Golden Code Development Corporation.
**
** -#- -I- --Date-- --------------------------------Description-----------------------------------
** 001 HC  20150323 Created initial version
** 002 CA  20150722 Added a new exclusion in beforeConfigValueSet: LabelConfig.setDefaults is 
**                  called only from c'tors.
** 003 CA  20180130 Disabled tracking on server-side for config assignment or field assignment.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it 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 may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
** 
** Additional terms under GNU Affero GPL version 3 section 7:
** 
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
** 
**   0. Attribution Requirement.
** 
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
** 
**   1. No License To Use Trademarks.
** 
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
** 
**   2. No Misrepresentation of Affiliation.
** 
**     You may not represent yourself as Golden Code Development Corporation or FWD.
** 
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
** 
**   3. No Misrepresentation of Source or Origin.
** 
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/

package com.goldencode.p2j.aspects.ui;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

import com.goldencode.p2j.ui.*;

/**
 * The aspect monitors config changes and notifies {@link ConfigSyncManager}.
 * This automates the process of config synchronization with the config owners. 
 */
@Aspect
public class SyncConfigChangesAspect
{
   /**
    * Triggered around methods marked with {@link SyncConfigChanges}
    * annotation. The method starts and stops synchronization scopes
    * using the methods {@link ConfigSyncManager#markScopeStart()} and
    * {@link ConfigSyncManager#markScopeEnd()}.
    * 
    * @param   thisJoinPoint
    *          A join point reference.
    *          
    * @return  The value of the join point method.
    *   
    * @throws  Throwable
    *          Any exceptions are untouched propagated out. 
    */
   @Around("execution(@com.goldencode.p2j.ui.SyncConfigChanges * *(..)) || " +
           "execution(@com.goldencode.p2j.ui.SyncConfigChanges *.new(..))")
   public Object aroundSyncConfigChanges(ProceedingJoinPoint thisJoinPoint) 
   throws Throwable
   {
      ConfigSyncManager.markScopeStart();
      
      try
      {
         return thisJoinPoint.proceed();
      }
      finally
      {
         ConfigSyncManager.markScopeEnd();
      }
   }
   
   /**
    * The method is called after config reference is saved in the
    * config owner. This helps to map config and config owners in
    * cases when the config has not been assigned an id.
    * 
    * @param   target
    *          {@link ConfigOwner} reference.
    * @param   config
    *          {@link WidgetConfig} reference.
    */
   @After("target(target) && args(config) " +
          "&& (set(*..WidgetConfig+ *..ConfigOwner+.config) " +
          "    || set(*..WidgetConfig+ *..ConfigOwner+.config))" +
          "&& !within(com.goldencode.p2j.ui.LogicalTerminal) " +
          "&& !within(com.goldencode.p2j.ui.FieldGroup) " +
          "&& !within(com.goldencode.p2j.ui.GenericFrame) " +
          "&& !within(com.goldencode.p2j.ui.*Widget) " +
          "&& !within(com.goldencode.p2j.ui.*Entity)")
   public void afterConfigSet(@SuppressWarnings("rawtypes") ConfigOwner target, 
                              WidgetConfig config)
   {
      if (config == null)
      {
         return;
      }
      
      ConfigSyncManager.registerConfig(target, config);
   }
   
   /**
    * The method is called after config field is assigned. The config
    * reference is then registered with {@link ConfigSyncManager} to
    * be synchronized later with the config owner.
    * 
    * @param   config
    *          {@link WidgetConfig} reference.
    */
   @Before("target(config) && set(* *..WidgetConfig+.*)" +
           "&& !withincode(void readExternal(..)) " +
           "&& !withincode(void applyConfig(..)) " +
           "&& !withincode(private void com.goldencode.p2j.ui.LabelConfig.setDefaults(..)) " +
           "&& !withincode(com.goldencode.p2j.ui.*Config.new(..))" +
           "&& !within(com.goldencode.p2j.ui.ScreenDefinition) " +
           "&& !within(com.goldencode.p2j.ui.MenuDescription) " +
           "&& !within(com.goldencode.p2j.ui.LogicalTerminal) " +
           "&& !within(com.goldencode.p2j.ui.FieldGroup) " +
           "&& !within(com.goldencode.p2j.ui.GenericFrame) " +
           "&& !within(com.goldencode.p2j.ui.*Widget) " +
           "&& !within(com.goldencode.p2j.ui.*Entity)")
   public void beforeConfigValueSet(WidgetConfig config)
   {
      if (config == null)
      {
         return;
      }
      
      ConfigSyncManager.registerConfig(null, config);
   }
   
   /**
    * The method is called after
    * {@link WidgetConfig#applyConfig(WidgetConfig)} is executed. The target
    * config reference is then registered with {@link ConfigSyncManager} to be
    * synchronized later with the config owner.
    * 
    * @param    config
    *           {@link WidgetConfig} reference.
    */
   @After("target(config) && " +
          "execution(* com.goldencode.p2j.ui.WidgetConfig.applyConfig(..))")
   public void afterApplyConfig(WidgetConfig config)
   {
      if (config == null)
      {
         return;
      }
      
      ConfigSyncManager.registerConfig(null, config);
   }
}