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 static org.opends.server.config.ConfigConstants.ATTR_BACKEND_ID;
020
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025
026import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1;
027import org.forgerock.i18n.slf4j.LocalizedLogger;
028import org.forgerock.opendj.adapter.server3x.Converters;
029import org.forgerock.opendj.config.server.ConfigException;
030import org.forgerock.opendj.ldap.ByteString;
031import org.forgerock.opendj.ldap.ResultCode;
032import org.forgerock.opendj.ldap.requests.ModifyRequest;
033import org.forgerock.opendj.server.config.server.BackendCfg;
034import org.forgerock.opendj.server.config.server.RootCfg;
035import org.opends.server.api.Backend;
036import org.opends.server.tools.BackendToolUtils;
037import org.opends.server.types.Entry;
038import org.opends.server.config.ConfigurationHandler;
039import org.opends.server.core.DirectoryServer;
040import org.opends.server.core.ModifyOperation;
041import org.opends.server.types.Attribute;
042import org.forgerock.opendj.ldap.DN;
043import org.opends.server.types.DirectoryException;
044
045import static org.forgerock.opendj.ldap.ModificationType.*;
046import static org.forgerock.opendj.ldap.requests.Requests.*;
047import static org.opends.messages.TaskMessages.*;
048import static org.opends.messages.ToolMessages.*;
049import static org.opends.server.config.ConfigConstants.*;
050import static org.opends.server.protocols.internal.InternalClientConnection.*;
051import static org.opends.server.util.ServerConstants.*;
052import static org.opends.server.util.StaticUtils.*;
053
054/**
055 * This class defines a number of static utility methods for server tasks.
056 */
057public class TaskUtils
058{
059  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
060
061
062
063
064  /**
065   * Get the backend ID of a backend configuration entry.
066   *
067   * @param configEntry A backend configuration entry.
068   * @return The backend ID.
069   */
070  public static String getBackendID(Entry configEntry)
071  {
072    try
073    {
074      return BackendToolUtils.getStringSingleValuedAttribute(configEntry, ATTR_BACKEND_ID);
075    }
076    catch (Exception e)
077    {
078      logger.error(ERR_CANNOT_DETERMINE_BACKEND_ID, configEntry.getName(), getExceptionMessage(e));
079      return null;
080    }
081  }
082
083  /**
084   * Get all the backend configuration entries defined in the server mapped
085   * by their backend ID.
086   * @return A map of backend IDs to their corresponding configuration entries.
087   */
088  public static Map<String,Entry> getBackendConfigEntries()
089  {
090    Map<String,Entry> configEntries = new HashMap<>();
091
092    // FIXME The error messages should not be the LDIF import messages
093
094    // Get the base entry for all backend configuration.
095    DN backendBaseDN;
096    try
097    {
098      backendBaseDN = DN.valueOf(DN_BACKEND_BASE);
099    }
100    catch (Exception e)
101    {
102      logger.error(ERR_CANNOT_DECODE_BACKEND_BASE_DN, DN_BACKEND_BASE, getExceptionMessage(e));
103      return configEntries;
104    }
105
106    // Iterate through the immediate children, attempting to parse them as
107    // backends.
108    try
109    {
110      ConfigurationHandler configHandler = DirectoryServer.getConfigurationHandler();
111      for (DN childrenDn : configHandler.getChildren(backendBaseDN))
112      {
113        // Get the backend ID attribute from the entry.  If there isn't one, then
114        // skip the entry.
115        Entry configEntry = null;
116        String backendID;
117        try
118        {
119          configEntry = Converters.to(configHandler.getEntry(childrenDn));
120          backendID = BackendToolUtils.getStringSingleValuedAttribute(configEntry, ATTR_BACKEND_ID);
121          if (backendID == null)
122          {
123            continue;
124          }
125        }
126        catch (Exception e)
127        {
128          logger.error(ERR_CANNOT_DETERMINE_BACKEND_ID, childrenDn, getExceptionMessage(e));
129          continue;
130        }
131
132        configEntries.put(backendID, configEntry);
133      }
134    }
135    catch (ConfigException e)
136    {
137      logger.error(ERR_CANNOT_RETRIEVE_BACKEND_BASE_ENTRY, DN_BACKEND_BASE, e.getMessage());
138    }
139
140    return configEntries;
141  }
142
143  /**
144   * Get the configuration entry for a given backend.
145   *
146   * @param backend The backend whose configuration entry is wanted.
147   * @return The configuration entry of the backend, or null if it could not
148   * be found.
149   */
150  public static BackendCfg getConfigEntry(Backend<?> backend)
151  {
152    try
153    {
154      return getRootConfig().getBackend(backend.getBackendID());
155    }
156    catch (ConfigException e)
157    {
158      return null;
159    }
160  }
161
162  private static RootCfg getRootConfig()
163  {
164    return DirectoryServer.getInstance().getServerContext().getRootConfig();
165  }
166
167  /**
168   * Enables a backend using an internal modify operation on the
169   * backend configuration entry.
170   *
171   * @param backendID Identifies the backend to be enabled.
172   * @throws DirectoryException If the internal modify operation failed.
173   */
174  public static void enableBackend(String backendID)
175       throws DirectoryException
176  {
177    enableBackend(backendID, TRUE_VALUE, ERR_TASK_CANNOT_ENABLE_BACKEND);
178  }
179
180
181
182  /**
183   * Disables a backend using an internal modify operation on the
184   * backend configuration entry.
185   *
186   * @param backendID Identifies the backend to be disabled.
187   * @throws DirectoryException If the internal modify operation failed.
188   */
189  public static void disableBackend(String backendID) throws DirectoryException
190  {
191    enableBackend(backendID, FALSE_VALUE, ERR_TASK_CANNOT_DISABLE_BACKEND);
192  }
193
194  private static void enableBackend(String backendID, ByteString enableValue, Arg1<Object> errorMsg)
195        throws DirectoryException {
196    DN configEntryDN;
197    try
198    {
199      configEntryDN = getRootConfig().getBackend(backendID).dn();
200    }
201    catch (ConfigException e)
202    {
203      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), e.getMessageObject(), e);
204    }
205
206    ModifyRequest modifyRequest = newModifyRequest(configEntryDN)
207        .addModification(REPLACE, ATTR_BACKEND_ENABLED, enableValue);
208    ModifyOperation modifyOp = getRootConnection().processModify(modifyRequest);
209
210    ResultCode resultCode = modifyOp.getResultCode();
211    if (resultCode != ResultCode.SUCCESS)
212    {
213      throw new DirectoryException(resultCode, errorMsg.get(configEntryDN));
214    }
215  }
216
217
218
219  /**
220   * Get the single boolean value of an entry attribute that is defined in the
221   * schema as a single valued boolean attribute, and that is not expected to
222   * have attribute options.
223   *
224   * @param attrList The attribute value of the entry attribute.
225   * @param defaultValue The default value to be returned if there is no
226   * recognizable boolean attribute value.
227   * @return The boolean value of the attribute, or the provided default value
228   * if there is no value.
229   */
230  public static boolean getBoolean(List<Attribute> attrList,
231                                   boolean defaultValue)
232  {
233    for (Attribute a : attrList)
234    {
235      for (ByteString v  : a)
236      {
237        String valueString = toLowerCase(v.toString());
238        if (valueString.equals("true") || valueString.equals("yes") ||
239            valueString.equals("on") || valueString.equals("1"))
240        {
241          return true;
242        }
243        else if (valueString.equals("false") || valueString.equals("no") ||
244                 valueString.equals("off") || valueString.equals("0"))
245        {
246          return false;
247        }
248      }
249    }
250
251    return defaultValue;
252  }
253
254
255
256  /**
257   * Get the multiple string values of an entry attribute that is defined in the
258   * schema as a multi-valued string attribute, and that is not expected to
259   * have attribute options.
260   *
261   * @param attrList The attribute values of the entry attribute.
262   * @return The string values of the attribute, empty if there are none.
263   */
264  public static ArrayList<String> getMultiValueString(List<Attribute> attrList)
265  {
266    ArrayList<String> valueStrings = new ArrayList<>();
267    if (!attrList.isEmpty())
268    {
269      Attribute attr = attrList.get(0);
270      if (!attr.isEmpty())
271      {
272        for (ByteString value : attr)
273        {
274          valueStrings.add(value.toString());
275        }
276      }
277    }
278    return valueStrings;
279  }
280
281
282
283  /**
284   * Get the single string value of an entry attribute that is defined in the
285   * schema as a single valued string attribute, and that is not expected to
286   * have attribute options.
287   *
288   * @param attrList The attribute value of the entry attribute.
289   * @return The string value of the attribute, or null if there is none.
290   */
291  public static String getSingleValueString(List<Attribute> attrList)
292  {
293    if (!attrList.isEmpty())
294    {
295      Attribute attr = attrList.get(0);
296      if (!attr.isEmpty())
297      {
298        return attr.iterator().next().toString();
299      }
300    }
301    return null;
302  }
303
304
305  /**
306   * Get the single integer value of an entry attribute that is defined in the
307   * schema as a single valued integer attribute, and that is not expected to
308   * have attribute options.
309   *
310   * @param attrList The attribute value of the entry attribute.
311   * @param defaultValue The default value to be returned if there is no
312   * recognizable integer attribute value.
313   * @return The integer value of the attribute, or the provided default value
314   * if there is no value.
315   */
316  public static int getSingleValueInteger(List<Attribute> attrList, int defaultValue)
317  {
318    if (!attrList.isEmpty())
319    {
320      Attribute attr = attrList.get(0);
321      if (!attr.isEmpty())
322      {
323        try
324        {
325          return Integer.parseInt(attr.iterator().next().toString());
326        }
327        catch (NumberFormatException e)
328        {
329          logger.traceException(e);
330        }
331      }
332    }
333
334    return defaultValue;
335  }
336}