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.Iterator;
030import java.util.LinkedList;
031import java.util.List;
032import java.util.regex.Matcher;
033import java.util.regex.Pattern;
034
035import org.forgerock.opendj.config.AbstractManagedObjectDefinition;
036import org.forgerock.opendj.config.DefinedDefaultBehaviorProvider;
037import org.forgerock.opendj.config.ManagedObjectDefinition;
038import org.forgerock.opendj.server.config.client.BackendCfgClient;
039import org.forgerock.opendj.server.config.meta.PluggableBackendCfgDefn;
040import org.forgerock.opendj.server.config.server.BackendCfg;
041import org.opends.guitools.controlpanel.util.Utilities;
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
132      for (org.opends.server.admin.AbstractManagedObjectDefinition<?, ?> oldConfigBackend :
133        org.opends.server.admin.std.meta.PluggableBackendCfgDefn.getInstance().getAllChildren())
134      {
135        if (oldConfigBackend.getName().equals(getBackend().getName()))
136        {
137          return (org.opends.server.admin.ManagedObjectDefinition<
138              ? extends org.opends.server.admin.std.client.BackendCfgClient,
139              ? extends org.opends.server.admin.std.server.BackendCfg>) oldConfigBackend;
140        }
141      }
142      throw new IllegalArgumentException("Impossible to find the equivalent backend type in old config framework: "
143          + getBackend().getName());
144    }
145  }
146
147  private final List<ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg>> backends;
148
149  /** Creates a new backend type helper. */
150  @SuppressWarnings("unchecked")
151  public BackendTypeHelper()
152  {
153    Utilities.initializeConfigurationFramework();
154
155    backends = new LinkedList<>();
156
157    for (AbstractManagedObjectDefinition<?, ?> backendType : PluggableBackendCfgDefn.getInstance().getAllChildren())
158    {
159      // Filtering out only the non-abstract backends to avoid users attempt to create abstract ones
160      if (backendType instanceof ManagedObjectDefinition)
161      {
162        final DefinedDefaultBehaviorProvider<String> defaultBehaviorProvider =
163                (DefinedDefaultBehaviorProvider<String>) backendType.getPropertyDefinition("java-class")
164                                                                    .getDefaultBehaviorProvider();
165        final Iterator<String> defaultBackendClassNameIterator = defaultBehaviorProvider.getDefaultValues().iterator();
166        if (!defaultBackendClassNameIterator.hasNext())
167        {
168          return;
169        }
170        addToBackendListIfClassExists(defaultBackendClassNameIterator.next(),
171                (ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg>) backendType);
172      }
173    }
174  }
175
176  private void addToBackendListIfClassExists(final String backendClassName,
177          final ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backendToAdd)
178  {
179    try
180    {
181      Class.forName(backendClassName);
182      backends.add(backendToAdd);
183    }
184    catch (ClassNotFoundException ignored)
185    {
186      // The backend is not supported in the running version.
187    }
188  }
189
190
191  ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> retrieveBackendTypeFromName(
192      final String backendTypeStr)
193  {
194    for (ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backendType : getBackendTypes())
195    {
196      final String name = backendType.getName();
197      if (backendTypeStr.equalsIgnoreCase(name)
198          || backendTypeStr.equalsIgnoreCase(filterSchemaBackendName(name)))
199      {
200        return backendType;
201      }
202    }
203
204    return null;
205  }
206
207  List<ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg>> getBackendTypes()
208  {
209    return backends;
210  }
211
212  String getPrintableBackendTypeNames()
213  {
214    String backendTypeNames = "";
215    for (ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backend : getBackendTypes())
216    {
217      backendTypeNames += filterSchemaBackendName(backend.getName()) + ", ";
218    }
219
220    if (backendTypeNames.isEmpty())
221    {
222      return "Impossible to retrieve supported backend type list";
223    }
224
225    return backendTypeNames.substring(0, backendTypeNames.length() - 2);
226  }
227
228  /**
229   * Return a list which contains all available backend type adapted for UI.
230   *
231   * @return a list which contains all available backend type adapted for UI
232   */
233  public BackendTypeUIAdapter[] getBackendTypeUIAdaptors()
234  {
235    List<BackendTypeUIAdapter> adaptors = new ArrayList<>();
236    for (ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backend : getBackendTypes())
237    {
238      adaptors.add(new BackendTypeUIAdapter(backend));
239    }
240
241    return adaptors.toArray(new BackendTypeUIAdapter[adaptors.size()]);
242  }
243
244  /**
245   * Return a BackendTypeUIAdapter which adapts the backend identified by the
246   * provided backend name.
247   *
248   * @param backendName
249   *          the backend name which identifies the backend to adapt.
250   * @return a BackendTypeUIAdapter which adapts the backend identified by the
251   *         provided backend name.
252   */
253  public static BackendTypeUIAdapter getBackendTypeAdapter(String backendName)
254  {
255    ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backend =
256        new BackendTypeHelper().retrieveBackendTypeFromName(backendName);
257    return backend != null ? getBackendTypeAdapter(backend) : null;
258  }
259
260  /**
261   * Return a BackendTypeUIAdapter which adapts the provided backend.
262   *
263   * @param backend
264   *          the backend type to adapt.
265   * @return a BackendTypeUIAdapter which adapts the provided backend.
266   */
267  public static BackendTypeUIAdapter getBackendTypeAdapter(
268      ManagedObjectDefinition<? extends BackendCfgClient, ? extends BackendCfg> backend)
269  {
270    return new BackendTypeUIAdapter(backend);
271  }
272
273}