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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
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 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.plugins;
028
029
030 import java.util.LinkedHashSet;
031 import java.util.List;
032 import java.util.Set;
033
034 import org.opends.messages.Message;
035 import org.opends.server.admin.server.ConfigurationChangeListener;
036 import org.opends.server.admin.std.meta.PluginCfgDefn;
037 import org.opends.server.admin.std.server.LDAPAttributeDescriptionListPluginCfg;
038 import org.opends.server.admin.std.server.PluginCfg;
039 import org.opends.server.api.plugin.DirectoryServerPlugin;
040 import org.opends.server.api.plugin.PluginType;
041 import org.opends.server.api.plugin.PluginResult;
042 import org.opends.server.config.ConfigException;
043 import org.opends.server.types.AttributeType;
044 import org.opends.server.types.ConfigChangeResult;
045 import org.opends.server.types.DirectoryConfig;
046 import org.opends.server.types.ObjectClass;
047 import org.opends.server.types.ResultCode;
048 import org.opends.server.types.operation.PreParseSearchOperation;
049
050 import static org.opends.server.loggers.debug.DebugLogger.*;
051 import org.opends.server.loggers.debug.DebugTracer;
052 import static org.opends.messages.PluginMessages.*;
053
054 import static org.opends.server.util.ServerConstants.*;
055 import static org.opends.server.util.StaticUtils.*;
056
057
058 /**
059 * This pre-parse plugin modifies the operation to allow an object class
060 * identifier to be specified in attributes lists, such as in Search requests,
061 * to request the return all attributes belonging to an object class as per the
062 * specification in RFC 4529. The "@" character is used to distinguish an
063 * object class identifier from an attribute descriptions.
064 */
065 public final class LDAPADListPlugin
066 extends DirectoryServerPlugin<LDAPAttributeDescriptionListPluginCfg>
067 implements ConfigurationChangeListener<
068 LDAPAttributeDescriptionListPluginCfg>
069 {
070 /**
071 * The tracer object for the debug logger.
072 */
073 private static final DebugTracer TRACER = getTracer();
074
075
076
077 // The current configuration for this plugin.
078 private LDAPAttributeDescriptionListPluginCfg currentConfig;
079
080
081
082 /**
083 * Creates a new instance of this Directory Server plugin. Every plugin must
084 * implement a default constructor (it is the only one that will be used to
085 * create plugins defined in the configuration), and every plugin constructor
086 * must call <CODE>super()</CODE> as its first element.
087 */
088 public LDAPADListPlugin()
089 {
090 super();
091 }
092
093
094
095 /**
096 * {@inheritDoc}
097 */
098 @Override()
099 public final void initializePlugin(Set<PluginType> pluginTypes,
100 LDAPAttributeDescriptionListPluginCfg configuration)
101 throws ConfigException
102 {
103 currentConfig = configuration;
104 configuration.addLDAPAttributeDescriptionListChangeListener(this);
105
106 // The set of plugin types must contain only the pre-parse search element.
107 if (pluginTypes.isEmpty())
108 {
109 Message message = ERR_PLUGIN_ADLIST_NO_PLUGIN_TYPES.get(
110 String.valueOf(configuration.dn()));
111 throw new ConfigException(message);
112 }
113 else
114 {
115 for (PluginType t : pluginTypes)
116 {
117 if (t != PluginType.PRE_PARSE_SEARCH)
118 {
119 Message message = ERR_PLUGIN_ADLIST_INVALID_PLUGIN_TYPE.get(
120 String.valueOf(configuration.dn()), String.valueOf(t));
121 throw new ConfigException(message);
122 }
123 }
124 }
125
126
127 // Register the appropriate supported feature with the Directory Server.
128 DirectoryConfig.registerSupportedFeature(OID_LDAP_ADLIST_FEATURE);
129 }
130
131
132
133 /**
134 * {@inheritDoc}
135 */
136 @Override()
137 public final void finalizePlugin()
138 {
139 currentConfig.removeLDAPAttributeDescriptionListChangeListener(this);
140 }
141
142
143
144 /**
145 * {@inheritDoc}
146 */
147 @Override()
148 public final PluginResult.PreParse
149 doPreParse(PreParseSearchOperation searchOperation)
150 {
151 // Iterate through the requested attributes to see if any of them start with
152 // an "@" symbol. If not, then we don't need to do anything. If so, then
153 // keep track of them.
154 LinkedHashSet<String> attributes = searchOperation.getAttributes();
155 boolean foundOC = false;
156 for (String attrName : attributes)
157 {
158 if (attrName.startsWith("@"))
159 {
160 foundOC = true;
161 break;
162 }
163 }
164
165 if (foundOC)
166 {
167 LinkedHashSet<String> newAttrs = new LinkedHashSet<String>();
168 for (String attrName : attributes)
169 {
170 if (attrName.startsWith("@"))
171 {
172 String lowerName = toLowerCase(attrName.substring(1));
173 ObjectClass oc = DirectoryConfig.getObjectClass(lowerName, false);
174 if (oc == null)
175 {
176 if (debugEnabled())
177 {
178 TRACER.debugWarning("Cannot replace unknown objectclass %s",
179 lowerName);
180 }
181 }
182 else
183 {
184 if (debugEnabled())
185 {
186 TRACER.debugInfo("Replacing objectclass %s", lowerName);
187 }
188
189 for (AttributeType at : oc.getRequiredAttributeChain())
190 {
191 newAttrs.add(at.getNameOrOID());
192 }
193
194 for (AttributeType at : oc.getOptionalAttributeChain())
195 {
196 newAttrs.add(at.getNameOrOID());
197 }
198 }
199 }
200 else
201 {
202 newAttrs.add(attrName);
203 }
204 }
205
206 searchOperation.setAttributes(newAttrs);
207 }
208
209
210 return PluginResult.PreParse.continueOperationProcessing();
211 }
212
213
214
215 /**
216 * {@inheritDoc}
217 */
218 @Override()
219 public boolean isConfigurationAcceptable(PluginCfg configuration,
220 List<Message> unacceptableReasons)
221 {
222 LDAPAttributeDescriptionListPluginCfg cfg =
223 (LDAPAttributeDescriptionListPluginCfg) configuration;
224 return isConfigurationChangeAcceptable(cfg, unacceptableReasons);
225 }
226
227
228
229 /**
230 * {@inheritDoc}
231 */
232 public boolean isConfigurationChangeAcceptable(
233 LDAPAttributeDescriptionListPluginCfg configuration,
234 List<Message> unacceptableReasons)
235 {
236 boolean configAcceptable = true;
237
238 // Ensure that the set of plugin types contains only pre-parse search.
239 for (PluginCfgDefn.PluginType pluginType : configuration.getPluginType())
240 {
241 switch (pluginType)
242 {
243 case PREPARSESEARCH:
244 // This is acceptable.
245 break;
246
247
248 default:
249 Message message = ERR_PLUGIN_ADLIST_INVALID_PLUGIN_TYPE.get(
250 String.valueOf(configuration.dn()),
251 String.valueOf(pluginType));
252 unacceptableReasons.add(message);
253 configAcceptable = false;
254 }
255 }
256
257 return configAcceptable;
258 }
259
260
261
262 /**
263 * {@inheritDoc}
264 */
265 public ConfigChangeResult applyConfigurationChange(
266 LDAPAttributeDescriptionListPluginCfg
267 configuration)
268 {
269 currentConfig = configuration;
270 return new ConfigChangeResult(ResultCode.SUCCESS, false);
271 }
272 }
273