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