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