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