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