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