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-2014 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 * The server supports multiple virtual attribute providers targeting the same
089 * attribute applying to the same entry. Evaluation order and value selection is
090 * determined by the server based on configuration of the virtual attribute
091 * providers.
092 * <BR>
093 * <H2>Configuring Virtual Attribute Providers</H2>
094 * In order to configure a virtual attribute provider created using this API,
095 * use a command like:
096 * <PRE>
097 * dsconfig create-virtual-attribute \
098 * --name "<I>{name}</I>" \
099 * --type third-party \
100 * --set enabled:true \
101 * --set attribute-type:{attribute} \
102 * --set "extension-class:<I>{class-name}</I>" \
103 * --set "extension-argument:<I>{name=value}</I>"
104 * </PRE>
105 * where "<I>{name}</I>" is the name to use for the virtual attribute provider
106 * instance, "<I>{attribute}</I>" is the name of the attribute for which the
107 * virtual attribute provider should be used to generate values,
108 * "<I>{class-name}</I>" is the fully-qualified name of the Java class that
109 * extends {@code com.unboundid.directory.sdk.ds.api.VirtualAttributeProvider},
110 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
111 * provide to the virtual attribute provider. If multiple arguments should be
112 * provided to the virtual attribute provider, then the
113 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
114 * provided multiple times.
115 *
116 * @see ScriptedVirtualAttributeProvider
117 */
118 @Extensible()
119 @DirectoryServerExtension()
120 @DirectoryProxyServerExtension(appliesToLocalContent=true,
121 appliesToRemoteContent=false)
122 @SynchronizationServerExtension(appliesToLocalContent=true,
123 appliesToSynchronizedContent=false)
124 @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
125 public abstract class VirtualAttributeProvider
126 implements UnboundIDExtension,
127 Reconfigurable<VirtualAttributeProviderConfig>,
128 ExampleUsageProvider
129 {
130 /**
131 * Creates a new instance of this virtual attribute provider. All virtual
132 * attribute provider implementations must include a default constructor, but
133 * any initialization should generally be done in the
134 * {@code initializeVirtualAttributeProvider} method.
135 */
136 public VirtualAttributeProvider()
137 {
138 // No implementation is required. However, we need to reference the
139 // scripted virtual attribute provider so that checkstyle is satisfied with
140 // the import.
141 final ScriptedVirtualAttributeProvider scriptedProvider = null;
142 }
143
144
145
146 /**
147 * {@inheritDoc}
148 */
149 public abstract String getExtensionName();
150
151
152
153 /**
154 * {@inheritDoc}
155 */
156 public abstract String[] getExtensionDescription();
157
158
159
160 /**
161 * {@inheritDoc}
162 */
163 public void defineConfigArguments(final ArgumentParser parser)
164 throws ArgumentException
165 {
166 // No arguments will be allowed by default.
167 }
168
169
170
171 /**
172 * Initializes this virtual attribute provider.
173 *
174 * @param serverContext A handle to the server context for the server in
175 * which this extension is running.
176 * @param config The general configuration for this virtual attribute
177 * provider.
178 * @param parser The argument parser which has been initialized from
179 * the configuration for this virtual attribute
180 * provider.
181 *
182 * @throws LDAPException If a problem occurs while initializing this virtual
183 * attribute provider.
184 */
185 public void initializeVirtualAttributeProvider(
186 final DirectoryServerContext serverContext,
187 final VirtualAttributeProviderConfig config,
188 final ArgumentParser parser)
189 throws LDAPException
190 {
191 // No initialization will be performed by default.
192 }
193
194
195
196 /**
197 * {@inheritDoc}
198 */
199 public boolean isConfigurationAcceptable(
200 final VirtualAttributeProviderConfig config,
201 final ArgumentParser parser,
202 final List<String> unacceptableReasons)
203 {
204 // No extended validation will be performed by default.
205 return true;
206 }
207
208
209
210 /**
211 * {@inheritDoc}
212 */
213 public ResultCode applyConfiguration(
214 final VirtualAttributeProviderConfig config,
215 final ArgumentParser parser,
216 final List<String> adminActionsRequired,
217 final List<String> messages)
218 {
219 // By default, no configuration changes will be applied. If there are any
220 // arguments, then add an admin action message indicating that the extension
221 // needs to be restarted for any changes to take effect.
222 if (! parser.getNamedArguments().isEmpty())
223 {
224 adminActionsRequired.add(
225 "No configuration change has actually been applied. The new " +
226 "configuration will not take effect until this virtual " +
227 "attribute provider is disabled and re-enabled or until the " +
228 "server is restarted.");
229 }
230
231 return ResultCode.SUCCESS;
232 }
233
234
235
236 /**
237 * Performs any cleanup which may be necessary when this virtual attribute
238 * provider is to be taken out of service.
239 */
240 public void finalizeVirtualAttributeProvider()
241 {
242 // No implementation is required.
243 }
244
245
246
247 /**
248 * Indicates whether the server may cache values generated by this virtual
249 * attribute provider for reuse against the same entry in the course of
250 * processing the same operation.
251 *
252 * @return {@code true} if the server may cache the value generated by this
253 * virtual attribute provider for reuse with the same entry in the
254 * same operation, or {@code false} if not.
255 */
256 public boolean mayCacheInOperation()
257 {
258 return false;
259 }
260
261
262
263 /**
264 * Indicates whether this virtual attribute provider may generate attributes
265 * with multiple values.
266 *
267 * @return {@code true} if this virtual attribute provider may generate
268 * attributes with multiple values, or {@code false} if it will only
269 * generate single-valued attributes.
270 */
271 public abstract boolean isMultiValued();
272
273
274
275 /**
276 * Generates an attribute for inclusion in the provided entry.
277 *
278 * @param operationContext The operation context for the operation in
279 * progress, if any. It may be {@code null} if no
280 * operation is available.
281 * @param entry The entry for which the attribute is to be
282 * generated.
283 * @param attributeName The name of the attribute to be generated.
284 *
285 * @return The generated attribute, or {@code null} if no attribute should be
286 * generated.
287 */
288 public abstract Attribute generateAttribute(
289 final OperationContext operationContext,
290 final Entry entry, final String attributeName);
291
292
293
294 /**
295 * {@inheritDoc}
296 */
297 public Map<List<String>,String> getExamplesArgumentSets()
298 {
299 return Collections.emptyMap();
300 }
301 }