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}