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 2015 ForgeRock AS
025 */
026package org.opends.server.tools;
027
028import java.util.ArrayList;
029import java.util.LinkedList;
030import java.util.List;
031import java.util.regex.Matcher;
032import java.util.regex.Pattern;
033
034import org.forgerock.opendj.config.AbstractManagedObjectDefinition;
035import org.forgerock.opendj.config.ManagedObjectDefinition;
036import org.forgerock.opendj.server.config.client.BackendCfgClient;
037import org.forgerock.opendj.server.config.meta.LocalDBBackendCfgDefn;
038import org.forgerock.opendj.server.config.meta.PluggableBackendCfgDefn;
039import org.forgerock.opendj.server.config.server.BackendCfg;
040import org.opends.guitools.controlpanel.util.Utilities;
041import org.opends.server.backends.jeb.RemoveOnceLocalDBBackendIsPluggable;
042import org.opends.server.util.RemoveOnceNewConfigFrameworkIsUsed;
043
044/**
045 * Helper class for setup applications. It helps applications to provide a
046 * backend type choice to the user.
047 */
048public class BackendTypeHelper
049{
050
051  /**
052   * Filter the provided backend name by removing the backend suffix.
053   *
054   * @param dsCfgBackendName
055   *          The backend name
056   * @return The backend name with the '-backend' suffix filtered out
057   */
058  public static String filterSchemaBackendName(final String dsCfgBackendName)
059  {
060    final String cfgNameRegExp = "(.*)-backend.*";
061    final Matcher regExpMatcher = Pattern.compile(cfgNameRegExp, Pattern.CASE_INSENSITIVE).matcher(dsCfgBackendName);
062    if (regExpMatcher.matches())
063    {
064      return regExpMatcher.group(1);
065    }
066
067    return dsCfgBackendName;
068  }
069
070  /** Adaptor to allow backend type selection in UIs. */
071  public static class BackendTypeUIAdapter
072  {
073    private final ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backend;
074
075    /**
076     * Create a new {@code BackendTypeUIAdapter}.
077     *
078     * @param backend
079     *          The backend to adapt
080     */
081    private BackendTypeUIAdapter(ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backend)
082    {
083      this.backend = backend;
084    }
085
086    /**
087     * Return a user friendly readable name for this backend.
088     *
089     * @return A user friendly readable name for this backend.
090     */
091    @Override
092    public String toString()
093    {
094      return backend.getUserFriendlyName().toString();
095    }
096
097    @Override
098    public boolean equals(Object obj)
099    {
100      return obj instanceof BackendTypeUIAdapter && ((BackendTypeUIAdapter) obj).toString().equals(toString());
101    }
102
103    @Override
104    public int hashCode()
105    {
106      return toString().hashCode();
107    }
108
109    /**
110     * Return the adapted backend object.
111     *
112     * @return The adapted backend object
113     */
114    public ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> getBackend()
115    {
116      return backend;
117    }
118
119    /**
120     * Return the old configuration framework backend object.
121     *
122     * @return The old configuration framework backend object
123     */
124    @SuppressWarnings("unchecked")
125    @RemoveOnceNewConfigFrameworkIsUsed
126    public org.opends.server.admin.ManagedObjectDefinition<
127        ? extends org.opends.server.admin.std.client.BackendCfgClient,
128        ? extends org.opends.server.admin.std.server.BackendCfg> getLegacyConfigurationFrameworkBackend()
129    {
130      Utilities.initializeLegacyConfigurationFramework();
131      if (isLocalDBBackend())
132      {
133        return org.opends.server.admin.std.meta.LocalDBBackendCfgDefn.getInstance();
134      }
135
136      for (org.opends.server.admin.AbstractManagedObjectDefinition<?, ?> oldConfigBackend :
137        org.opends.server.admin.std.meta.PluggableBackendCfgDefn.getInstance().getAllChildren())
138      {
139        if (oldConfigBackend.getName().equals(getBackend().getName()))
140        {
141          return (org.opends.server.admin.ManagedObjectDefinition<
142              ? extends org.opends.server.admin.std.client.BackendCfgClient,
143              ? extends org.opends.server.admin.std.server.BackendCfg>) oldConfigBackend;
144        }
145      }
146      throw new IllegalArgumentException("Impossible to find the equivalent backend type in old config framework: "
147          + getBackend().getName());
148    }
149
150    @RemoveOnceLocalDBBackendIsPluggable
151    private boolean isLocalDBBackend()
152    {
153      return getBackend().getName().equals(LocalDBBackendCfgDefn.getInstance().getName());
154    }
155  }
156
157  private final List<ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg>> backends;
158
159  /** Creates a new backend type helper. */
160  @SuppressWarnings("unchecked")
161  public BackendTypeHelper()
162  {
163    Utilities.initializeConfigurationFramework();
164
165    backends = new LinkedList<>();
166
167    // Add the JE backend if it is supported in this release.
168    try
169    {
170      Class.forName("org.opends.server.backends.jeb.BackendImpl");
171      backends.add(LocalDBBackendCfgDefn.getInstance());
172    }
173    catch (ClassNotFoundException ignored)
174    {
175      // Ignore: JE backend not supported.
176    }
177
178    for (AbstractManagedObjectDefinition<?, ?> backendType : PluggableBackendCfgDefn.getInstance().getAllChildren())
179    {
180      // Filtering out only the non-abstract backends to avoid users attempt to create abstract ones
181      if (backendType instanceof ManagedObjectDefinition)
182      {
183        backends.add((ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg>) backendType);
184      }
185    }
186  }
187
188  ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> retrieveBackendTypeFromName(
189      final String backendTypeStr)
190  {
191    for (ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backendType : getBackendTypes())
192    {
193      final String name = backendType.getName();
194      if (backendTypeStr.equalsIgnoreCase(name)
195          || backendTypeStr.equalsIgnoreCase(filterSchemaBackendName(name)))
196      {
197        return backendType;
198      }
199    }
200
201    return null;
202  }
203
204  List<ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg>> getBackendTypes()
205  {
206    return backends;
207  }
208
209  String getPrintableBackendTypeNames()
210  {
211    String backendTypeNames = "";
212    for (ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backend : getBackendTypes())
213    {
214      backendTypeNames += filterSchemaBackendName(backend.getName()) + ", ";
215    }
216
217    if (backendTypeNames.isEmpty())
218    {
219      return "Impossible to retrieve supported backend type list";
220    }
221
222    return backendTypeNames.substring(0, backendTypeNames.length() - 2);
223  }
224
225  /**
226   * Return a list which contains all available backend type adapted for UI.
227   *
228   * @return a list which contains all available backend type adapted for UI
229   */
230  public BackendTypeUIAdapter[] getBackendTypeUIAdaptors()
231  {
232    List<BackendTypeUIAdapter> adaptors = new ArrayList<>();
233    for (ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backend : getBackendTypes())
234    {
235      adaptors.add(new BackendTypeUIAdapter(backend));
236    }
237
238    return adaptors.toArray(new BackendTypeUIAdapter[adaptors.size()]);
239  }
240
241  /**
242   * Return a BackendTypeUIAdapter which adapts the backend identified by the
243   * provided backend name.
244   *
245   * @param backendName
246   *          the backend name which identifies the backend to adapt.
247   * @return a BackendTypeUIAdapter which adapts the backend identified by the
248   *         provided backend name.
249   */
250  public static BackendTypeUIAdapter getBackendTypeAdapter(String backendName)
251  {
252    ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backend =
253        new BackendTypeHelper().retrieveBackendTypeFromName(backendName);
254    return backend != null ? getBackendTypeAdapter(backend) : null;
255  }
256
257  /**
258   * Return a BackendTypeUIAdapter which adapts the provided backend.
259   *
260   * @param backend
261   *          the backend type to adapt.
262   * @return a BackendTypeUIAdapter which adapts the provided backend.
263   */
264  public static BackendTypeUIAdapter getBackendTypeAdapter(
265      ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backend)
266  {
267    return new BackendTypeUIAdapter(backend);
268  }
269
270}