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