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