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