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 2010-2012 UnboundID Corp. 026 */ 027 package com.unboundid.directory.sdk.ds.scripting; 028 029 030 031 import java.util.List; 032 033 import com.unboundid.directory.sdk.common.internal.Reconfigurable; 034 import com.unboundid.directory.sdk.common.types.Entry; 035 import com.unboundid.directory.sdk.common.types.OperationContext; 036 import com.unboundid.directory.sdk.ds.types.DirectoryServerContext; 037 import com.unboundid.directory.sdk.ds.config.VirtualAttributeProviderConfig; 038 import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension; 039 import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension; 040 import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension; 041 import com.unboundid.ldap.sdk.Attribute; 042 import com.unboundid.ldap.sdk.LDAPException; 043 import com.unboundid.ldap.sdk.ResultCode; 044 import com.unboundid.util.Extensible; 045 import com.unboundid.util.ThreadSafety; 046 import com.unboundid.util.ThreadSafetyLevel; 047 import com.unboundid.util.args.ArgumentException; 048 import com.unboundid.util.args.ArgumentParser; 049 050 051 052 /** 053 * This class defines an API that must be implemented by scripted extensions 054 * which construct attribute values which may be included in entries instead of 055 * or in addition to real values which are actually stored in the backend. The 056 * other attributes in the entry will be available for use in the process of 057 * generating the entry, and internal or external operations may also be 058 * performed if the generated values should incorporate data from other 059 * locations. 060 * <BR><BR> 061 * Each virtual attribute provider may be configured to indicate whether the 062 * associated virtual attribute should be included in a given entry. This 063 * criteria may include the entry's location in the DIT, whether it matches a 064 * given filter, whether it is a member of a specified group, and whether the 065 * requesting client has been assigned a given client connection policy. This 066 * is handled automatically by the server, so individual virtual attribute 067 * provider implementations do not need to attempt to perform that filtering on 068 * their own. However, they may perform additional processing if desired to 069 * further narrow the set of entries for which the virtual attribute should be 070 * generated. 071 * <BR><BR> 072 * In addition, virtual attribute providers may be configured to indicate the 073 * behavior that should be exhibited in the event that the target attribute 074 * already exists in the entry with one or more real values. In this case, the 075 * real values may be used instead of generating virtual values, the virtual 076 * values may be used in place of the real values, or both the real and virtual 077 * values may be merged and presented together. This work is also automatically 078 * performed by the server, so virtual attribute providers do not need to do any 079 * processing to determine whether to generate a value based on whether the 080 * target attribute already exists in the entry. 081 * <BR><BR> 082 * Note that at most one virtual attribute provider may be used to generate a 083 * value for the same attribute in any entry. If multiple virtual attribute 084 * providers are configured to generate values for the same attribute, then they 085 * should also be configured with different sets of criteria so that they will 086 * only be used for different sets of entries. If multiple virtual attribute 087 * providers targeting the same attribute apply to the same entry, then only 088 * one of them will be used, and it is undefined which one will be selected. 089 * <BR> 090 * <H2>Configuring Groovy-Scripted virtual attribute providers</H2> 091 * In order to configure a scripted virtual attribute provider based on this API 092 * and written in the Groovy scripting language, use a command like: 093 * <PRE> 094 * dsconfig create-virtual-attribute \ 095 * --name "<I>{name}</I>" \ 096 * --type groovy-scripted \ 097 * --set enabled:true \ 098 * --set attribute-type:{attribute} \ 099 * --set "script-class:<I>{class-name}</I>" \ 100 * --set "script-argument:<I>{name=value}</I>" 101 * </PRE> 102 * where "<I>{name}</I>" is the name to use for the virtual attribute provider 103 * instance, "<I>{attribute}</I>", is the name of the attribute for which the 104 * virtual attribute provider should be used to generate values, 105 * "<I>{class-name}</I>" is the fully-qualified name of the Groovy class written 106 * using this API, and "<I>{name=value}</I>" represents name-value pairs for any 107 * arguments to provide to the virtual attribute provider. If multiple 108 * arguments should be provided to the virtual attribute provider, then the 109 * "<CODE>--set script-argument:<I>{name=value}</I></CODE>" option should be 110 * provided multiple times. 111 * 112 * @see com.unboundid.directory.sdk.ds.api.VirtualAttributeProvider 113 */ 114 @Extensible() 115 @DirectoryServerExtension() 116 @DirectoryProxyServerExtension(appliesToLocalContent=true, 117 appliesToRemoteContent=false) 118 @SynchronizationServerExtension(appliesToLocalContent=true, 119 appliesToSynchronizedContent=false) 120 @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE) 121 public abstract class ScriptedVirtualAttributeProvider 122 implements Reconfigurable<VirtualAttributeProviderConfig> 123 { 124 /** 125 * Creates a new instance of this virtual attribute provider. All virtual 126 * attribute provider implementations must include a default constructor, but 127 * any initialization should generally be done in the 128 * {@code initializeVirtualAttributeProvider} method. 129 */ 130 public ScriptedVirtualAttributeProvider() 131 { 132 // No implementation is required. 133 } 134 135 136 137 /** 138 * {@inheritDoc} 139 */ 140 public void defineConfigArguments(final ArgumentParser parser) 141 throws ArgumentException 142 { 143 // No arguments will be allowed by default. 144 } 145 146 147 148 /** 149 * Initializes this virtual attribute provider. 150 * 151 * @param serverContext A handle to the server context for the server in 152 * which this extension is running. 153 * @param config The general configuration for this virtual attribute 154 * provider. 155 * @param parser The argument parser which has been initialized from 156 * the configuration for this virtual attribute 157 * provider. 158 * 159 * @throws LDAPException If a problem occurs while initializing this virtual 160 * attribute provider. 161 */ 162 public void initializeVirtualAttributeProvider( 163 final DirectoryServerContext serverContext, 164 final VirtualAttributeProviderConfig config, 165 final ArgumentParser parser) 166 throws LDAPException 167 { 168 // No initialization will be performed by default. 169 } 170 171 172 173 /** 174 * Performs any cleanup which may be necessary when this virtual attribute 175 * provider is to be taken out of service. 176 */ 177 public void finalizeVirtualAttributeProvider() 178 { 179 // No implementation is required. 180 } 181 182 183 184 /** 185 * {@inheritDoc} 186 */ 187 public boolean isConfigurationAcceptable( 188 final VirtualAttributeProviderConfig config, 189 final ArgumentParser parser, 190 final List<String> unacceptableReasons) 191 { 192 // No extended validation will be performed. 193 return true; 194 } 195 196 197 198 /** 199 * {@inheritDoc} 200 */ 201 public ResultCode applyConfiguration( 202 final VirtualAttributeProviderConfig config, 203 final ArgumentParser parser, 204 final List<String> adminActionsRequired, 205 final List<String> messages) 206 { 207 // By default, no configuration changes will be applied. If there are any 208 // arguments, then add an admin action message indicating that the extension 209 // needs to be restarted for any changes to take effect. 210 if (! parser.getNamedArguments().isEmpty()) 211 { 212 adminActionsRequired.add( 213 "No configuration change has actually been applied. The new " + 214 "configuration will not take effect until this virtual " + 215 "attribute provider is disabled and re-enabled or until the " + 216 "server is restarted."); 217 } 218 219 return ResultCode.SUCCESS; 220 } 221 222 223 224 /** 225 * Indicates whether the server may cache values generated by this virtual 226 * attribute provider for reuse against the same entry in the course of 227 * processing the same operation. 228 * 229 * @return {@code true} if the server may cache the value generated by this 230 * virtual attribute provider for reuse with the same entry in the 231 * same operation, or {@code false} if not. 232 */ 233 public boolean mayCacheInOperation() 234 { 235 return false; 236 } 237 238 239 240 /** 241 * Indicates whether this virtual attribute provider may generate attributes 242 * with multiple values. 243 * 244 * @return {@code true} if this virtual attribute provider may generate 245 * attributes with multiple values, or {@code false} if it will only 246 * generate single-valued attributes. 247 */ 248 public abstract boolean isMultiValued(); 249 250 251 252 /** 253 * Generates an attribute for inclusion in the provided entry. 254 * 255 * @param operationContext The operation context for the operation in 256 * progress, if any. It may be {@code null} if no 257 * operation is available. 258 * @param entry The entry for which the attribute is to be 259 * generated. 260 * @param attributeName The name of the attribute to be generated. 261 * 262 * @return The generated attribute, or {@code null} if no attribute should be 263 * generated. 264 */ 265 public abstract Attribute generateAttribute( 266 final OperationContext operationContext, 267 final Entry entry, final String attributeName); 268 }