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 legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2008 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.tasks; 028 029import java.util.ArrayList; 030import java.util.HashMap; 031import java.util.List; 032import java.util.Map; 033 034import org.forgerock.i18n.LocalizableMessage; 035import org.forgerock.i18n.slf4j.LocalizedLogger; 036import org.forgerock.opendj.config.server.ConfigException; 037import org.forgerock.opendj.ldap.ByteString; 038import org.forgerock.opendj.ldap.ModificationType; 039import org.forgerock.opendj.ldap.ResultCode; 040import org.opends.messages.TaskMessages; 041import org.opends.server.admin.server.ServerManagementContext; 042import org.opends.server.admin.std.server.BackendCfg; 043import org.opends.server.admin.std.server.RootCfg; 044import org.opends.server.api.Backend; 045import org.opends.server.config.ConfigEntry; 046import org.opends.server.config.StringConfigAttribute; 047import org.opends.server.core.DirectoryServer; 048import org.opends.server.core.ModifyOperation; 049import org.opends.server.protocols.ldap.LDAPAttribute; 050import org.opends.server.protocols.ldap.LDAPModification; 051import org.opends.server.types.Attribute; 052import org.opends.server.types.DN; 053import org.opends.server.types.DirectoryException; 054import org.opends.server.types.RawModification; 055import org.opends.server.util.CollectionUtils; 056import org.opends.server.util.ServerConstants; 057 058import static org.opends.messages.ConfigMessages.*; 059import static org.opends.messages.ToolMessages.*; 060import static org.opends.server.config.ConfigConstants.*; 061import static org.opends.server.protocols.internal.InternalClientConnection.*; 062import static org.opends.server.util.StaticUtils.*; 063 064/** 065 * This class defines a number of static utility methods for server tasks. 066 */ 067public class TaskUtils 068{ 069 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 070 071 072 073 074 /** 075 * Get the backend ID of a backend configuration entry. 076 * 077 * @param configEntry A backend configuration entry. 078 * @return The backend ID. 079 */ 080 public static String getBackendID(ConfigEntry configEntry) 081 { 082 try 083 { 084 StringConfigAttribute idStub = 085 new StringConfigAttribute( 086 ATTR_BACKEND_ID, 087 INFO_CONFIG_BACKEND_ATTR_DESCRIPTION_BACKEND_ID.get(), 088 true, false, true); 089 StringConfigAttribute idAttr = 090 (StringConfigAttribute) configEntry.getConfigAttribute(idStub); 091 return idAttr.activeValue(); 092 } 093 catch (org.opends.server.config.ConfigException ce) 094 { 095 logger.error(ERR_CANNOT_DETERMINE_BACKEND_ID, configEntry.getDN(), ce.getMessage()); 096 return null; 097 } 098 catch (Exception e) 099 { 100 logger.error(ERR_CANNOT_DETERMINE_BACKEND_ID, configEntry.getDN(), getExceptionMessage(e)); 101 return null; 102 } 103 } 104 105 /** 106 * Get all the backend configuration entries defined in the server mapped 107 * by their backend ID. 108 * @return A map of backend IDs to their corresponding configuration entries. 109 */ 110 public static Map<String,ConfigEntry> getBackendConfigEntries() 111 { 112 Map<String,ConfigEntry> configEntries = new HashMap<>(); 113 114 // FIXME The error messages should not be the LDIF import messages 115 116 // Get the base entry for all backend configuration. 117 DN backendBaseDN; 118 try 119 { 120 backendBaseDN = DN.valueOf(DN_BACKEND_BASE); 121 } 122 catch (DirectoryException de) 123 { 124 logger.error(ERR_CANNOT_DECODE_BACKEND_BASE_DN, DN_BACKEND_BASE, de.getMessageObject()); 125 return configEntries; 126 } 127 catch (Exception e) 128 { 129 logger.error(ERR_CANNOT_DECODE_BACKEND_BASE_DN, DN_BACKEND_BASE, getExceptionMessage(e)); 130 return configEntries; 131 } 132 133 ConfigEntry baseEntry; 134 try 135 { 136 baseEntry = DirectoryServer.getConfigEntry(backendBaseDN); 137 } 138 catch (ConfigException ce) 139 { 140 logger.error(ERR_CANNOT_RETRIEVE_BACKEND_BASE_ENTRY, DN_BACKEND_BASE, ce.getMessage()); 141 return configEntries; 142 } 143 catch (Exception e) 144 { 145 logger.error(ERR_CANNOT_RETRIEVE_BACKEND_BASE_ENTRY, DN_BACKEND_BASE, getExceptionMessage(e)); 146 return configEntries; 147 } 148 149 150 // Iterate through the immediate children, attempting to parse them as 151 // backends. 152 for (ConfigEntry configEntry : baseEntry.getChildren().values()) 153 { 154 // Get the backend ID attribute from the entry. If there isn't one, then 155 // skip the entry. 156 String backendID; 157 try 158 { 159 StringConfigAttribute idStub = 160 new StringConfigAttribute( 161 ATTR_BACKEND_ID, 162 INFO_CONFIG_BACKEND_ATTR_DESCRIPTION_BACKEND_ID.get(), 163 true, false, true); 164 StringConfigAttribute idAttr = 165 (StringConfigAttribute) configEntry.getConfigAttribute(idStub); 166 if (idAttr == null) 167 { 168 continue; 169 } 170 else 171 { 172 backendID = idAttr.activeValue(); 173 } 174 } 175 catch (org.opends.server.config.ConfigException ce) 176 { 177 logger.error(ERR_CANNOT_DETERMINE_BACKEND_ID, configEntry.getDN(), ce.getMessage()); 178 continue; 179 } 180 catch (Exception e) 181 { 182 logger.error(ERR_CANNOT_DETERMINE_BACKEND_ID, configEntry.getDN(), getExceptionMessage(e)); 183 continue; 184 } 185 186 configEntries.put(backendID, configEntry); 187 } 188 189 return configEntries; 190 } 191 192 /** 193 * Get the configuration entry for a given backend. 194 * 195 * @param backend The backend whose configuration entry is wanted. 196 * @return The configuration entry of the backend, or null if it could not 197 * be found. 198 */ 199 public static BackendCfg getConfigEntry(Backend backend) 200 { 201 RootCfg root = ServerManagementContext.getInstance(). 202 getRootConfiguration(); 203 try 204 { 205 return root.getBackend(backend.getBackendID()); 206 } 207 catch (ConfigException e) 208 { 209 return null; 210 } 211 } 212 213 214 215 /** 216 * Enables a backend using an internal modify operation on the 217 * backend configuration entry. 218 * 219 * @param backendID Identifies the backend to be enabled. 220 * @throws DirectoryException If the internal modify operation failed. 221 */ 222 public static void enableBackend(String backendID) 223 throws DirectoryException 224 { 225 DN configEntryDN; 226 RootCfg root = ServerManagementContext.getInstance().getRootConfiguration(); 227 try 228 { 229 BackendCfg cfg = root.getBackend(backendID); 230 configEntryDN = cfg.dn(); 231 } 232 catch (ConfigException e) 233 { 234 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 235 e.getMessageObject(), e); 236 } 237 238 LDAPAttribute a = new LDAPAttribute(ATTR_BACKEND_ENABLED, ServerConstants.TRUE_VALUE); 239 LDAPModification m = new LDAPModification(ModificationType.REPLACE, a); 240 241 ArrayList<RawModification> modList = CollectionUtils.<RawModification> newArrayList(m); 242 243 String backendDNString = configEntryDN.toString(); 244 ByteString rawEntryDN = ByteString.valueOfUtf8(backendDNString); 245 ModifyOperation internalModify = getRootConnection().processModify(rawEntryDN, modList); 246 247 ResultCode resultCode = internalModify.getResultCode(); 248 if (resultCode != ResultCode.SUCCESS) 249 { 250 LocalizableMessage message = 251 TaskMessages.ERR_TASK_CANNOT_ENABLE_BACKEND.get(backendDNString); 252 throw new DirectoryException(resultCode, message); 253 } 254 } 255 256 257 258 /** 259 * Disables a backend using an internal modify operation on the 260 * backend configuration entry. 261 * 262 * @param backendID Identifies the backend to be disabled. 263 * @throws DirectoryException If the internal modify operation failed. 264 */ 265 public static void disableBackend(String backendID) 266 throws DirectoryException 267 { 268 DN configEntryDN; 269 RootCfg root = ServerManagementContext.getInstance().getRootConfiguration(); 270 try 271 { 272 BackendCfg cfg = root.getBackend(backendID); 273 configEntryDN = cfg.dn(); 274 } 275 catch (ConfigException e) 276 { 277 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 278 e.getMessageObject(), e); 279 } 280 281 LDAPAttribute a = new LDAPAttribute(ATTR_BACKEND_ENABLED, ServerConstants.FALSE_VALUE); 282 LDAPModification m = new LDAPModification(ModificationType.REPLACE, a); 283 284 ArrayList<RawModification> modList = CollectionUtils.<RawModification> newArrayList(m); 285 286 String backendDNString = configEntryDN.toString(); 287 ByteString rawEntryDN = ByteString.valueOfUtf8(backendDNString); 288 ModifyOperation internalModify = getRootConnection().processModify(rawEntryDN, modList); 289 290 ResultCode resultCode = internalModify.getResultCode(); 291 if (resultCode != ResultCode.SUCCESS) 292 { 293 LocalizableMessage message = 294 TaskMessages.ERR_TASK_CANNOT_DISABLE_BACKEND.get(backendDNString); 295 throw new DirectoryException(resultCode, message); 296 } 297 } 298 299 300 301 /** 302 * Get the single boolean value of an entry attribute that is defined in the 303 * schema as a single valued boolean attribute, and that is not expected to 304 * have attribute options. 305 * 306 * @param attrList The attribute value of the entry attribute. 307 * @param defaultValue The default value to be returned if there is no 308 * recognizable boolean attribute value. 309 * @return The boolean value of the attribute, or the provided default value 310 * if there is no value. 311 */ 312 public static boolean getBoolean(List<Attribute> attrList, 313 boolean defaultValue) 314 { 315 if (attrList == null || attrList.isEmpty()) 316 { 317 return defaultValue; 318 } 319 320 for (Attribute a : attrList) 321 { 322 for (ByteString v : a) 323 { 324 String valueString = toLowerCase(v.toString()); 325 if (valueString.equals("true") || valueString.equals("yes") || 326 valueString.equals("on") || valueString.equals("1")) 327 { 328 return true; 329 } 330 else if (valueString.equals("false") || valueString.equals("no") || 331 valueString.equals("off") || valueString.equals("0")) 332 { 333 return false; 334 } 335 } 336 } 337 338 return defaultValue; 339 } 340 341 342 343 /** 344 * Get the multiple string values of an entry attribute that is defined in the 345 * schema as a multi-valued string attribute, and that is not expected to 346 * have attribute options. 347 * 348 * @param attrList The attribute values of the entry attribute. 349 * @return The string values of the attribute, empty if there are none. 350 */ 351 public static ArrayList<String> getMultiValueString(List<Attribute> attrList) 352 { 353 ArrayList<String> valueStrings = new ArrayList<>(); 354 355 if (attrList != null && !attrList.isEmpty()) 356 { 357 Attribute attr = attrList.get(0); 358 if (!attr.isEmpty()) 359 { 360 for (ByteString value : attr) 361 { 362 valueStrings.add(value.toString()); 363 } 364 } 365 } 366 return valueStrings; 367 } 368 369 370 371 /** 372 * Get the single string value of an entry attribute that is defined in the 373 * schema as a single valued string attribute, and that is not expected to 374 * have attribute options. 375 * 376 * @param attrList The attribute value of the entry attribute. 377 * @return The string value of the attribute, or null if there is none. 378 */ 379 public static String getSingleValueString(List<Attribute> attrList) 380 { 381 if (attrList != null && !attrList.isEmpty()) 382 { 383 Attribute attr = attrList.get(0); 384 if (!attr.isEmpty()) 385 { 386 return attr.iterator().next().toString(); 387 } 388 } 389 return null; 390 } 391 392 393 /** 394 * Get the single integer value of an entry attribute that is defined in the 395 * schema as a single valued integer attribute, and that is not expected to 396 * have attribute options. 397 * 398 * @param attrList The attribute value of the entry attribute. 399 * @param defaultValue The default value to be returned if there is no 400 * recognizable integer attribute value. 401 * @return The integer value of the attribute, or the provided default value 402 * if there is no value. 403 */ 404 public static int getSingleValueInteger(List<Attribute> attrList, 405 int defaultValue) 406 { 407 if (attrList != null && !attrList.isEmpty()) 408 { 409 Attribute attr = attrList.get(0); 410 if (!attr.isEmpty()) 411 { 412 try 413 { 414 return Integer.parseInt(attr.iterator().next().toString()); 415 } 416 catch (NumberFormatException e) 417 { 418 logger.traceException(e); 419 } 420 } 421 } 422 423 return defaultValue; 424 } 425}