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