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 2008-2011 Sun Microsystems, Inc.
025 *      Portions Copyright 2013-2015 ForgeRock AS.
026 */
027package org.opends.guitools.controlpanel.util;
028
029import static org.opends.messages.AdminToolMessages.*;
030import static org.opends.server.backends.pluggable.SuffixContainer.*;
031
032import java.net.InetAddress;
033import java.util.ArrayList;
034import java.util.Collection;
035import java.util.Collections;
036import java.util.HashSet;
037import java.util.List;
038import java.util.Set;
039import java.util.SortedSet;
040import java.util.TreeSet;
041
042import org.forgerock.i18n.LocalizableMessage;
043import org.forgerock.i18n.slf4j.LocalizedLogger;
044import org.forgerock.opendj.config.server.ConfigException;
045import org.opends.guitools.controlpanel.datamodel.AbstractIndexDescriptor;
046import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
047import org.opends.guitools.controlpanel.datamodel.BaseDNDescriptor;
048import org.opends.guitools.controlpanel.datamodel.ConnectionHandlerDescriptor;
049import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
050import org.opends.guitools.controlpanel.datamodel.IndexDescriptor;
051import org.opends.guitools.controlpanel.datamodel.IndexTypeDescriptor;
052import org.opends.guitools.controlpanel.datamodel.VLVIndexDescriptor;
053import org.opends.guitools.controlpanel.datamodel.VLVSortOrder;
054import org.opends.guitools.controlpanel.task.OfflineUpdateException;
055import org.opends.server.admin.server.ServerManagementContext;
056import org.opends.server.admin.std.server.AdministrationConnectorCfg;
057import org.opends.server.admin.std.server.BackendCfg;
058import org.opends.server.admin.std.server.BackendIndexCfg;
059import org.opends.server.admin.std.server.BackendVLVIndexCfg;
060import org.opends.server.admin.std.server.BackupBackendCfg;
061import org.opends.server.admin.std.server.ConnectionHandlerCfg;
062import org.opends.server.admin.std.server.HTTPConnectionHandlerCfg;
063import org.opends.server.admin.std.server.JMXConnectionHandlerCfg;
064import org.opends.server.admin.std.server.LDAPConnectionHandlerCfg;
065import org.opends.server.admin.std.server.LDIFBackendCfg;
066import org.opends.server.admin.std.server.LDIFConnectionHandlerCfg;
067import org.opends.server.admin.std.server.LocalDBBackendCfg;
068import org.opends.server.admin.std.server.LocalDBIndexCfg;
069import org.opends.server.admin.std.server.LocalDBVLVIndexCfg;
070import org.opends.server.admin.std.server.MemoryBackendCfg;
071import org.opends.server.admin.std.server.MonitorBackendCfg;
072import org.opends.server.admin.std.server.PluggableBackendCfg;
073import org.opends.server.admin.std.server.ReplicationDomainCfg;
074import org.opends.server.admin.std.server.ReplicationServerCfg;
075import org.opends.server.admin.std.server.ReplicationSynchronizationProviderCfg;
076import org.opends.server.admin.std.server.RootCfg;
077import org.opends.server.admin.std.server.RootDNCfg;
078import org.opends.server.admin.std.server.RootDNUserCfg;
079import org.opends.server.admin.std.server.SNMPConnectionHandlerCfg;
080import org.opends.server.admin.std.server.TaskBackendCfg;
081import org.opends.server.backends.jeb.RemoveOnceLocalDBBackendIsPluggable;
082import org.opends.server.core.DirectoryServer;
083import org.opends.server.types.DN;
084import org.opends.server.types.OpenDsException;
085
086/**
087 * A class that reads the configuration information from the files.
088 */
089public class ConfigFromFile extends ConfigReader
090{
091  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
092
093  /**
094   * Creates a new instance of this config file handler. No initialization
095   * should be performed here, as all of that work should be done in the
096   * <CODE>initializeConfigHandler</CODE> method.
097   */
098  public ConfigFromFile()
099  {
100    super();
101  }
102
103  /**
104   * Reads configuration information from the configuration files.
105   */
106  public void readConfiguration()
107  {
108    final List<OpenDsException> errors = new ArrayList<>();
109    final Set<ConnectionHandlerDescriptor> connectionHandlers = new HashSet<>();
110    final Set<BackendDescriptor> backendDescriptors = new HashSet<>();
111    final Set<DN> alternateBindDNs = new HashSet<>();
112    try
113    {
114      DirectoryServer.getInstance().initializeConfiguration();
115
116      readSchemaIfNeeded(errors);
117      readConfig(connectionHandlers, backendDescriptors, alternateBindDNs, errors);
118    }
119    catch (final OpenDsException oe)
120    {
121      errors.add(oe);
122    }
123    catch (final Throwable t)
124    {
125      logger.warn(LocalizableMessage.raw("Error reading configuration: " + t, t));
126      errors.add(new OfflineUpdateException(ERR_READING_CONFIG_LDAP.get(t.getMessage()), t));
127    }
128
129    if (!errors.isEmpty() && environmentSettingException != null)
130    {
131      errors.add(0, environmentSettingException);
132    }
133
134    for (final OpenDsException oe : errors)
135    {
136      logger.warn(LocalizableMessage.raw("Error reading configuration: " + oe, oe));
137    }
138    exceptions = Collections.unmodifiableList(errors);
139    administrativeUsers = Collections.unmodifiableSet(alternateBindDNs);
140    listeners = Collections.unmodifiableSet(connectionHandlers);
141    backends = Collections.unmodifiableSet(backendDescriptors);
142  }
143
144  private void readSchemaIfNeeded(final List<OpenDsException> errors) throws ConfigException
145  {
146    if (mustReadSchema())
147    {
148      try
149      {
150        readSchema();
151        if (getSchema() != null)
152        {
153          // Update the schema: so that when we call the server code the
154          // latest schema read on the server we are managing is used.
155          DirectoryServer.setSchema(getSchema());
156        }
157      }
158      catch (final OpenDsException oe)
159      {
160        errors.add(oe);
161      }
162    }
163  }
164
165  private void readConfig(final Set<ConnectionHandlerDescriptor> connectionHandlers,
166      final Set<BackendDescriptor> backendDescriptors, final Set<DN> alternateBindDNs,
167      final List<OpenDsException> errors) throws OpenDsException, ConfigException
168  {
169    // Get the Directory Server configuration handler and use it.
170    final RootCfg root = ServerManagementContext.getInstance().getRootConfiguration();
171    readAdminConnector(root, errors);
172    readConnectionHandlers(connectionHandlers, root, errors);
173    isSchemaEnabled = root.getGlobalConfiguration().isCheckSchema();
174
175    readBackendConfiguration(backendDescriptors, root, errors);
176    boolean isReplicationSecure = readIfReplicationIsSecure(root, errors);
177    ReplicationSynchronizationProviderCfg sync = readSyncProviderIfExists(root);
178    if (sync != null)
179    {
180      readReplicationConfig(connectionHandlers, backendDescriptors, sync, isReplicationSecure, errors);
181    }
182    readAlternateBindDNs(alternateBindDNs, root, errors);
183  }
184
185  private void readAdminConnector(final RootCfg root, final List<OpenDsException> errors) throws OpenDsException
186  {
187    try
188    {
189      final AdministrationConnectorCfg adminConnector = root.getAdministrationConnector();
190      this.adminConnector = getConnectionHandler(adminConnector);
191    }
192    catch (final ConfigException ce)
193    {
194      errors.add(toConfigException(ce));
195    }
196  }
197
198  private void readConnectionHandlers(final Set<ConnectionHandlerDescriptor> connectionHandlers, final RootCfg root,
199      final List<OpenDsException> errors) throws ConfigException
200  {
201    for (final String connHandler : root.listConnectionHandlers())
202    {
203      try
204      {
205        final ConnectionHandlerCfg connectionHandler = root.getConnectionHandler(connHandler);
206        connectionHandlers.add(getConnectionHandler(connectionHandler, connHandler));
207      }
208      catch (final OpenDsException oe)
209      {
210        errors.add(oe);
211      }
212    }
213  }
214
215  private void readBackendConfiguration(final Set<BackendDescriptor> backendDescriptors, final RootCfg root,
216      final List<OpenDsException> errors)
217  {
218    for (final String backendName : root.listBackends())
219    {
220      try
221      {
222        final BackendCfg backend = root.getBackend(backendName);
223        final Set<BaseDNDescriptor> baseDNs = new HashSet<>();
224        for (final DN dn : backend.getBaseDN())
225        {
226          final BaseDNDescriptor baseDN =
227              new BaseDNDescriptor(BaseDNDescriptor.Type.NOT_REPLICATED, dn, null, -1, -1, -1);
228          baseDNs.add(baseDN);
229        }
230        final Set<IndexDescriptor> indexes = new HashSet<>();
231        final Set<VLVIndexDescriptor> vlvIndexes = new HashSet<>();
232        BackendDescriptor.Type type;
233        if (backend instanceof LocalDBBackendCfg)
234        {
235          type = BackendDescriptor.Type.LOCAL_DB;
236          refreshLocalDBBackendConfig(errors, backend, indexes, vlvIndexes);
237        }
238        else if (backend instanceof PluggableBackendCfg)
239        {
240          type = BackendDescriptor.Type.PLUGGABLE;
241          refreshBackendConfig(indexes, vlvIndexes, backend, errors);
242        }
243        else if (backend instanceof LDIFBackendCfg)
244        {
245          type = BackendDescriptor.Type.LDIF;
246        }
247        else if (backend instanceof MemoryBackendCfg)
248        {
249          type = BackendDescriptor.Type.MEMORY;
250        }
251        else if (backend instanceof BackupBackendCfg)
252        {
253          type = BackendDescriptor.Type.BACKUP;
254        }
255        else if (backend instanceof MonitorBackendCfg)
256        {
257          type = BackendDescriptor.Type.MONITOR;
258        }
259        else if (backend instanceof TaskBackendCfg)
260        {
261          type = BackendDescriptor.Type.TASK;
262        }
263        else
264        {
265          type = BackendDescriptor.Type.OTHER;
266        }
267        final BackendDescriptor desc =
268            new BackendDescriptor(backend.getBackendId(), baseDNs, indexes, vlvIndexes, -1, backend.isEnabled(), type);
269        for (final AbstractIndexDescriptor index : indexes)
270        {
271          index.setBackend(desc);
272        }
273        for (final AbstractIndexDescriptor index : vlvIndexes)
274        {
275          index.setBackend(desc);
276        }
277
278        backendDescriptors.add(desc);
279      }
280      catch (final ConfigException ce)
281      {
282        errors.add(toConfigException(ce));
283      }
284    }
285  }
286
287  private void refreshBackendConfig(final Set<IndexDescriptor> indexes,
288      final Set<VLVIndexDescriptor> vlvIndexes, final BackendCfg backend, final List<OpenDsException> errors)
289  {
290    final PluggableBackendCfg db = (PluggableBackendCfg) backend;
291    readBackendIndexes(indexes, errors, db);
292    readBackendVLVIndexes(vlvIndexes, errors, db);
293  }
294
295  private void readBackendIndexes(final Set<IndexDescriptor> indexes, final List<OpenDsException> errors,
296      final PluggableBackendCfg db)
297  {
298    indexes.add(new IndexDescriptor(DN2ID_INDEX_NAME));
299    indexes.add(new IndexDescriptor(ID2CHILDREN_COUNT_NAME));
300    try
301    {
302      for (final String indexName : db.listBackendIndexes())
303      {
304        final BackendIndexCfg index = db.getBackendIndex(indexName);
305        indexes.add(new IndexDescriptor(
306            index.getAttribute().getNameOrOID(), index.getAttribute(),
307            null, IndexTypeDescriptor.fromBackendIndexTypes(index.getIndexType()), index.getIndexEntryLimit()));
308      }
309    }
310    catch (ConfigException ce)
311    {
312      errors.add(toConfigException(ce));
313    }
314  }
315
316  private void readBackendVLVIndexes(final Set<VLVIndexDescriptor> vlvIndexes,
317      final List<OpenDsException> errors, final PluggableBackendCfg db)
318  {
319    try
320    {
321      for (final String vlvIndexName : db.listBackendVLVIndexes())
322      {
323        final BackendVLVIndexCfg index = db.getBackendVLVIndex(vlvIndexName);
324        final List<VLVSortOrder> sortOrder = getVLVSortOrder(index.getSortOrder());
325        vlvIndexes.add(new VLVIndexDescriptor(
326            index.getName(), null, index.getBaseDN(), VLVIndexDescriptor.toSearchScope(index.getScope()),
327            index.getFilter(), sortOrder));
328      }
329    }
330    catch (ConfigException ce)
331    {
332      errors.add(toConfigException(ce));
333    }
334  }
335
336  @RemoveOnceLocalDBBackendIsPluggable
337  private void refreshLocalDBBackendConfig(final List<OpenDsException> errors, final BackendCfg backend,
338      final Set<IndexDescriptor> indexes, final Set<VLVIndexDescriptor> vlvIndexes)
339  {
340    final LocalDBBackendCfg db = (LocalDBBackendCfg) backend;
341    try
342    {
343      for (final String indexName : db.listLocalDBIndexes())
344      {
345        final LocalDBIndexCfg index = db.getLocalDBIndex(indexName);
346        indexes.add(new IndexDescriptor(index.getAttribute().getNameOrOID(), index.getAttribute(), null,
347            IndexTypeDescriptor.fromLocalDBIndexTypes(index.getIndexType()), index.getIndexEntryLimit()));
348      }
349    }
350    catch (final ConfigException ce)
351    {
352      errors.add(toConfigException(ce));
353    }
354    indexes.add(new IndexDescriptor(DN2ID_INDEX_NAME));
355    if (db.isSubordinateIndexesEnabled())
356    {
357      indexes.add(new IndexDescriptor(ID2CHILDREN_INDEX_NAME));
358      indexes.add(new IndexDescriptor(ID2SUBTREE_INDEX_NAME));
359    }
360
361    try
362    {
363      for (final String vlvIndexName : db.listLocalDBVLVIndexes())
364      {
365        final LocalDBVLVIndexCfg index = db.getLocalDBVLVIndex(vlvIndexName);
366        final String s = index.getSortOrder();
367        final List<VLVSortOrder> sortOrder = getVLVSortOrder(s);
368        vlvIndexes.add(new VLVIndexDescriptor(index.getName(), null, index.getBaseDN(), VLVIndexDescriptor
369            .toSearchScope(index.getScope()), index.getFilter(), sortOrder));
370      }
371    }
372    catch (final ConfigException ce)
373    {
374      errors.add(toConfigException(ce));
375    }
376  }
377
378  private boolean readIfReplicationIsSecure(final RootCfg root, final List<OpenDsException> errors)
379  {
380    try
381    {
382      return root.getCryptoManager().isSSLEncryption();
383    }
384    catch (final ConfigException ce)
385    {
386      errors.add(toConfigException(ce));
387      return false;
388    }
389  }
390
391  private ReplicationSynchronizationProviderCfg readSyncProviderIfExists(final RootCfg root)
392  {
393    replicationPort = -1;
394    try
395    {
396      return (ReplicationSynchronizationProviderCfg) root.getSynchronizationProvider("Multimaster Synchronization");
397    }
398    catch (final ConfigException ce)
399    {
400      // Ignore this one
401      return null;
402    }
403  }
404
405  private void readReplicationConfig(final Set<ConnectionHandlerDescriptor> connectionHandlers,
406      final Set<BackendDescriptor> backendDescriptors, ReplicationSynchronizationProviderCfg sync,
407      boolean isReplicationSecure, final List<OpenDsException> errors)
408  {
409    try
410    {
411      if (sync.isEnabled() && sync.hasReplicationServer())
412      {
413        final ReplicationServerCfg replicationServer = sync.getReplicationServer();
414        if (replicationServer != null)
415        {
416          replicationPort = replicationServer.getReplicationPort();
417          final ConnectionHandlerDescriptor.Protocol protocol =
418              isReplicationSecure ? ConnectionHandlerDescriptor.Protocol.REPLICATION_SECURE
419                  : ConnectionHandlerDescriptor.Protocol.REPLICATION;
420          final Set<CustomSearchResult> emptySet = Collections.emptySet();
421          final ConnectionHandlerDescriptor connHandler =
422              new ConnectionHandlerDescriptor(new HashSet<InetAddress>(), replicationPort, protocol,
423                  ConnectionHandlerDescriptor.State.ENABLED, "Multimaster Synchronization", emptySet);
424          connectionHandlers.add(connHandler);
425        }
426      }
427      final String[] domains = sync.listReplicationDomains();
428      if (domains != null)
429      {
430        for (final String domain2 : domains)
431        {
432          final ReplicationDomainCfg domain = sync.getReplicationDomain(domain2);
433          final DN dn = domain.getBaseDN();
434          for (final BackendDescriptor backend : backendDescriptors)
435          {
436            for (final BaseDNDescriptor baseDN : backend.getBaseDns())
437            {
438              if (baseDN.getDn().equals(dn))
439              {
440                baseDN
441                    .setType(sync.isEnabled() ? BaseDNDescriptor.Type.REPLICATED : BaseDNDescriptor.Type.DISABLED);
442                baseDN.setReplicaID(domain.getServerId());
443              }
444            }
445          }
446        }
447      }
448    }
449    catch (final ConfigException ce)
450    {
451      errors.add(toConfigException(ce));
452    }
453  }
454
455  private void readAlternateBindDNs(final Set<DN> dns, final RootCfg root, final List<OpenDsException> errors)
456  {
457    try
458    {
459      final RootDNCfg rootDN = root.getRootDN();
460      final String[] rootUsers = rootDN.listRootDNUsers();
461      dns.clear();
462      if (rootUsers != null)
463      {
464        for (final String rootUser2 : rootUsers)
465        {
466          final RootDNUserCfg rootUser = rootDN.getRootDNUser(rootUser2);
467          dns.addAll(rootUser.getAlternateBindDN());
468        }
469      }
470    }
471    catch (final ConfigException ce)
472    {
473      errors.add(toConfigException(ce));
474    }
475  }
476
477  private org.opends.server.config.ConfigException toConfigException(final ConfigException ce)
478  {
479    return new org.opends.server.config.ConfigException(ce.getMessageObject(), ce);
480  }
481
482  private ConnectionHandlerDescriptor getConnectionHandler(final ConnectionHandlerCfg connHandler, final String name)
483      throws OpenDsException
484  {
485    final SortedSet<InetAddress> addresses = new TreeSet<>(getInetAddressComparator());
486
487    final ConnectionHandlerDescriptor.State state =
488        connHandler.isEnabled() ? ConnectionHandlerDescriptor.State.ENABLED
489            : ConnectionHandlerDescriptor.State.DISABLED;
490
491    ConnectionHandlerDescriptor.Protocol protocol;
492    int port;
493    if (connHandler instanceof LDAPConnectionHandlerCfg)
494    {
495      final LDAPConnectionHandlerCfg ldap = (LDAPConnectionHandlerCfg) connHandler;
496      if (ldap.isUseSSL())
497      {
498        protocol = ConnectionHandlerDescriptor.Protocol.LDAPS;
499      }
500      else if (ldap.isAllowStartTLS())
501      {
502        protocol = ConnectionHandlerDescriptor.Protocol.LDAP_STARTTLS;
503      }
504      else
505      {
506        protocol = ConnectionHandlerDescriptor.Protocol.LDAP;
507      }
508      addAll(addresses, ldap.getListenAddress());
509      port = ldap.getListenPort();
510    }
511    else if (connHandler instanceof HTTPConnectionHandlerCfg)
512    {
513      final HTTPConnectionHandlerCfg http = (HTTPConnectionHandlerCfg) connHandler;
514      if (http.isUseSSL())
515      {
516        protocol = ConnectionHandlerDescriptor.Protocol.HTTPS;
517      }
518      else
519      {
520        protocol = ConnectionHandlerDescriptor.Protocol.HTTP;
521      }
522      addAll(addresses, http.getListenAddress());
523      port = http.getListenPort();
524    }
525    else if (connHandler instanceof JMXConnectionHandlerCfg)
526    {
527      final JMXConnectionHandlerCfg jmx = (JMXConnectionHandlerCfg) connHandler;
528      if (jmx.isUseSSL())
529      {
530        protocol = ConnectionHandlerDescriptor.Protocol.JMXS;
531      }
532      else
533      {
534        protocol = ConnectionHandlerDescriptor.Protocol.JMX;
535      }
536      addresses.add(jmx.getListenAddress());
537      port = jmx.getListenPort();
538    }
539    else if (connHandler instanceof LDIFConnectionHandlerCfg)
540    {
541      protocol = ConnectionHandlerDescriptor.Protocol.LDIF;
542      port = -1;
543    }
544    else if (connHandler instanceof SNMPConnectionHandlerCfg)
545    {
546      protocol = ConnectionHandlerDescriptor.Protocol.SNMP;
547      final SNMPConnectionHandlerCfg snmp = (SNMPConnectionHandlerCfg) connHandler;
548      addAll(addresses, snmp.getListenAddress());
549      port = snmp.getListenPort();
550    }
551    else
552    {
553      protocol = ConnectionHandlerDescriptor.Protocol.OTHER;
554      port = -1;
555    }
556    final Set<CustomSearchResult> emptySet = Collections.emptySet();
557    return new ConnectionHandlerDescriptor(addresses, port, protocol, state, name, emptySet);
558  }
559
560  private <T> void addAll(final Collection<T> target, final Collection<T> source)
561  {
562    if (source != null)
563    {
564      target.addAll(source);
565    }
566  }
567
568  private ConnectionHandlerDescriptor getConnectionHandler(final AdministrationConnectorCfg adminConnector)
569      throws OpenDsException
570  {
571    final SortedSet<InetAddress> addresses = new TreeSet<>(getInetAddressComparator());
572
573    final ConnectionHandlerDescriptor.Protocol protocol = ConnectionHandlerDescriptor.Protocol.ADMINISTRATION_CONNECTOR;
574    final ConnectionHandlerDescriptor.State state = ConnectionHandlerDescriptor.State.ENABLED;
575
576    addAll(addresses, adminConnector.getListenAddress());
577    final int port = adminConnector.getListenPort();
578    final Set<CustomSearchResult> emptySet = Collections.emptySet();
579    return new ConnectionHandlerDescriptor(addresses, port, protocol, state,
580        INFO_CTRL_PANEL_CONN_HANDLER_ADMINISTRATION.get().toString(), emptySet);
581  }
582}