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}