001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * docs/licenses/cddl.txt 011 * or http://www.opensource.org/licenses/cddl1.php. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * docs/licenses/cddl.txt. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2018-2019 Ping Identity Corporation 026 */ 027package com.unboundid.directory.sdk.ds.api; 028 029 030 031import java.time.ZonedDateTime; 032import java.util.Collections; 033import java.util.List; 034import java.util.Map; 035 036import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider; 037import com.unboundid.directory.sdk.common.internal.Reconfigurable; 038import com.unboundid.directory.sdk.common.internal.UnboundIDExtension; 039import com.unboundid.directory.sdk.ds.config.RecurringTaskConfig; 040import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension; 041import com.unboundid.directory.sdk.ds.types.DirectoryServerContext; 042import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension; 043import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension; 044import com.unboundid.ldap.sdk.LDAPException; 045import com.unboundid.ldap.sdk.ReadOnlyEntry; 046import com.unboundid.ldap.sdk.ResultCode; 047import com.unboundid.util.Extensible; 048import com.unboundid.util.ThreadSafety; 049import com.unboundid.util.ThreadSafetyLevel; 050import com.unboundid.util.args.ArgumentException; 051import com.unboundid.util.args.ArgumentParser; 052 053 054 055/** 056 * This class defines an API that must be implemented by extensions that may be 057 * used to schedule administrative tasks on a recurring basis. Recurring 058 * tasks are part of a recurring task chain, which combines the configuration 059 * needed to define the schedule with the recurring tasks that define the 060 * content of the tasks to schedule. 061 * <BR><BR> 062 * Recurring tasks created via this API can only be used to schedule 063 * {@link Task} instances that have themselves been implemented using the Server 064 * SDK. As when scheduling an individual instance of these tasks, the server 065 * must be configured as follows to allow creation of third-party tasks: 066 * <PRE> 067 * dsconfig set-global-configuration-prop 068 * --add allowed-task:com.unboundid.directory.sdk.extensions.ThirdPartyTask 069 * </PRE> 070 * <BR><BR> 071 * The {@code Task} instance actually performs the core processing for the 072 * administrative task, while the {@code RecurringTask} instance merely ensures 073 * that the {@code Task} is scheduled with the appropriate arguments. 074 */ 075@Extensible() 076@DirectoryServerExtension() 077@DirectoryProxyServerExtension(appliesToLocalContent=true, 078 appliesToRemoteContent=false) 079@SynchronizationServerExtension(appliesToLocalContent=true, 080 appliesToSynchronizedContent=false) 081@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE) 082public abstract class RecurringTask 083 implements UnboundIDExtension, Reconfigurable<RecurringTaskConfig>, 084 ExampleUsageProvider 085{ 086 /** 087 * Creates a new instance of this recurring task. All recurring task 088 * implementations must include a default constructor, but any initialization 089 * should generally be done in the {@link #initializeRecurringTask} method. 090 */ 091 public RecurringTask() 092 { 093 // No implementation is required. 094 } 095 096 097 098 /** 099 * {@inheritDoc} 100 */ 101 @Override() 102 public abstract String getExtensionName(); 103 104 105 106 /** 107 * {@inheritDoc} 108 */ 109 @Override() 110 public abstract String[] getExtensionDescription(); 111 112 113 114 /** 115 * {@inheritDoc} 116 */ 117 @Override() 118 public void defineConfigArguments(final ArgumentParser parser) 119 throws ArgumentException 120 { 121 // No arguments will be allowed by default. 122 } 123 124 125 126 /** 127 * Initializes this recurring task. 128 * 129 * @param serverContext A handle to the server context for the server in 130 * which this extension is running. 131 * @param config The general configuration for this recurring task. 132 * @param parser The argument parser which has been initialized from 133 * the configuration for this recurring task. 134 * 135 * @throws LDAPException If a problem occurs while initializing this 136 * recurring task. 137 */ 138 public void initializeRecurringTask( 139 final DirectoryServerContext serverContext, 140 final RecurringTaskConfig config, 141 final ArgumentParser parser) 142 throws LDAPException 143 { 144 // No initialization will be performed by default. 145 } 146 147 148 149 /** 150 * {@inheritDoc} 151 */ 152 @Override() 153 public boolean isConfigurationAcceptable(final RecurringTaskConfig config, 154 final ArgumentParser parser, 155 final List<String> unacceptableReasons) 156 { 157 // No extended validation will be performed by default. 158 return true; 159 } 160 161 162 163 /** 164 * {@inheritDoc} 165 */ 166 @Override() 167 public ResultCode applyConfiguration(final RecurringTaskConfig config, 168 final ArgumentParser parser, 169 final List<String> adminActionsRequired, 170 final List<String> messages) 171 { 172 // By default, no configuration changes will be applied. If there are any 173 // arguments, then add an admin action message indicating that the extension 174 // needs to be restarted for any changes to take effect. 175 if (! parser.getNamedArguments().isEmpty()) 176 { 177 adminActionsRequired.add( 178 "No configuration change has actually been applied. The new " + 179 "configuration will not take effect until the server is " + 180 "restarted."); 181 } 182 183 return ResultCode.SUCCESS; 184 } 185 186 187 188 /** 189 * Performs any cleanup which may be necessary when this recurring task is 190 * to be taken out of service. 191 */ 192 public void finalizeRecurringTask() 193 { 194 // No implementation is required. 195 } 196 197 198 199 /** 200 * Retrieves the Java class that will be used to process instances of this 201 * recurring task. 202 * 203 * @return The java class that will be used to process instances of this 204 * recurring task. It must not be {@code null}. 205 */ 206 public abstract Class<? extends Task> getTaskJavaClass(); 207 208 209 210 /** 211 * Retrieves the list of values that should be provided to the 212 * ds-third-party-task-argument attribute for the task instance that is 213 * created. 214 * 215 * @param scheduledStartTime The scheduled start time that will be used for 216 * the task that is created. 217 * @param lastTaskEntry The entry for the last instance of the 218 * recurring task that was scheduled. It may be 219 * {@code null} if the last instance is not 220 * available (for example, because no instances of 221 * the recurring task have yet been scheduled. 222 * 223 * @return The list of values that should be provided to the 224 * ds-third-party-task-argument for the task instance that is 225 * created. It may be {@code null} or empty if the task does not 226 * require any arguments. 227 */ 228 public abstract List<String> getTaskArguments( 229 final ZonedDateTime scheduledStartTime, 230 final ReadOnlyEntry lastTaskEntry); 231 232 233 234 /** 235 * {@inheritDoc} 236 */ 237 @Override() 238 public Map<List<String>,String> getExamplesArgumentSets() 239 { 240 return Collections.emptyMap(); 241 } 242}