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