001package com.identityworksllc.iiq.common.service; 002 003import org.apache.commons.logging.Log; 004import org.apache.commons.logging.LogFactory; 005import sailpoint.api.SailPointContext; 006import sailpoint.server.BasePluginService; 007import sailpoint.server.Service; 008import sailpoint.tools.GeneralException; 009 010import java.util.concurrent.atomic.AtomicBoolean; 011import java.util.concurrent.atomic.AtomicLong; 012 013/** 014 * Abstract super-class for services. This class provides some minimal 015 * services, such as tracking execution counts and last execution times, 016 * then delegates to the {@link #implementation(SailPointContext)} method. 017 */ 018public abstract class BaseCommonService extends Service implements BaseServiceImplementation { 019 020 /** 021 * The logger for use by this class 022 */ 023 private static final Log _bcpsLogger = LogFactory.getLog(BaseCommonService.class); 024 025 /** 026 * The execution count for this service, available to sub-classes 027 */ 028 protected AtomicBoolean executedOnce; 029 030 /** 031 * The execution count for this service, available to sub-classes 032 */ 033 protected AtomicLong executionCount; 034 035 /** 036 * The last start time, stored by default in {@link #beforeExecution(SailPointContext)} 037 */ 038 private final AtomicLong lastStartTime; 039 040 /** 041 * The actual callback to the user's implementation for this service 042 */ 043 protected ServiceImplementationInvoker invoker; 044 045 /** 046 * Base common plugin service constructor 047 */ 048 protected BaseCommonService() { 049 this.executedOnce = new AtomicBoolean(); 050 this.executionCount = new AtomicLong(); 051 this.lastStartTime = new AtomicLong(); 052 this.invoker = this::implementation; 053 } 054 055 /** 056 * @see BaseServiceImplementation#afterExecution(SailPointContext) 057 */ 058 @Override 059 public void afterExecution(SailPointContext context) throws GeneralException { 060 this.incrementExecutions(); 061 062 ServiceUtils.storeTimestamps(context, getDefinition(), this.lastStartTime.get()); 063 } 064 065 /** 066 * @see BaseServiceImplementation#beforeExecution(SailPointContext) (SailPointContext) 067 */ 068 @Override 069 public void beforeExecution(SailPointContext context) throws GeneralException { 070 this.lastStartTime.set(System.currentTimeMillis()); 071 } 072 073 /** 074 * The main entry point of the service 075 * 076 * @see Service#execute(SailPointContext) 077 * @param context The IIQ context for this service run 078 * @throws GeneralException if the service execution failed 079 */ 080 @Override 081 public final void execute(SailPointContext context) throws GeneralException { 082 beforeExecution(context); 083 084 if (this.executionCount.get() >= skipExecutionCount()) { 085 this.invoker.invokeImplementation(context); 086 } else { 087 _bcpsLogger.info("Skipping execution (count = " + this.executionCount.get() + ") of service " + getDefinition().getName()); 088 } 089 090 afterExecution(context); 091 } 092 093 /** 094 * Returns the elapsed runtime of this service, in milliseconds. Services 095 * should use this method to stop after a certain timeout period has been 096 * reached to avoid bogging down the {@link sailpoint.server.Servicer}. 097 * 098 * @return The elapsed runtime of this service, in milliseconds 099 */ 100 protected long getElapsedRuntimeMillis() { 101 return (System.currentTimeMillis() - this.lastStartTime.get()); 102 } 103 104 /** 105 * Increments the execution count and sets the executed-once flag to true 106 */ 107 @Override 108 public final void incrementExecutions() { 109 this.executedOnce.set(true); 110 this.executionCount.incrementAndGet(); 111 } 112 113}