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-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.guitools.controlpanel.util;
028
029import static org.forgerock.util.Reject.*;
030import static org.opends.messages.ConfigMessages.*;
031import static org.opends.server.util.StaticUtils.*;
032
033import java.io.File;
034import java.util.Collections;
035import java.util.HashMap;
036import java.util.Set;
037
038import org.forgerock.i18n.LocalizableMessage;
039import org.forgerock.opendj.config.server.ConfigException;
040import org.forgerock.opendj.ldap.ConditionResult;
041import org.opends.server.admin.std.server.BackendCfg;
042import org.opends.server.api.ConfigHandler;
043import org.opends.server.config.ConfigEntry;
044import org.opends.server.core.AddOperation;
045import org.opends.server.core.DeleteOperation;
046import org.opends.server.core.DirectoryServer;
047import org.opends.server.core.ModifyDNOperation;
048import org.opends.server.core.ModifyOperation;
049import org.opends.server.core.SearchOperation;
050import org.opends.server.core.ServerContext;
051import org.opends.server.types.AttributeType;
052import org.opends.server.types.BackupConfig;
053import org.opends.server.types.BackupDirectory;
054import org.opends.server.types.CanceledOperationException;
055import org.opends.server.types.DN;
056import org.opends.server.types.DirectoryEnvironmentConfig;
057import org.opends.server.types.DirectoryException;
058import org.opends.server.types.Entry;
059import org.opends.server.types.IndexType;
060import org.opends.server.types.InitializationException;
061import org.opends.server.types.LDIFExportConfig;
062import org.opends.server.types.LDIFImportConfig;
063import org.opends.server.types.LDIFImportResult;
064import org.opends.server.types.RestoreConfig;
065import org.opends.server.util.LDIFException;
066import org.opends.server.util.LDIFReader;
067
068/**
069 * A class used to read the configuration from a file.  This config file
070 * handler does not allow to modify the configuration, only to read it.
071 */
072public class ReadOnlyConfigFileHandler extends ConfigHandler<BackendCfg>
073{
074  /**
075   * The mapping that holds all of the configuration entries that have been read
076   * from the LDIF file.
077   */
078  private HashMap<DN,ConfigEntry> configEntries = new HashMap<>();
079
080  /** The reference to the configuration root entry. */
081  private ConfigEntry configRootEntry;
082
083  /** The server root. */
084  private String serverRoot;
085
086  /** The instance root. */
087  private String instanceRoot;
088
089  private DN[] baseDNs;
090
091  /** {@inheritDoc} */
092  @Override
093  public void finalizeConfigHandler()
094  {
095    finalizeBackend();
096  }
097
098  /** {@inheritDoc} */
099  @Override
100  public ConfigEntry getConfigEntry(DN entryDN) throws ConfigException
101  {
102    return configEntries.get(entryDN);
103  }
104
105  /** {@inheritDoc} */
106  @Override
107  public ConfigEntry getConfigRootEntry() throws ConfigException
108  {
109    return configRootEntry;
110  }
111
112  /** {@inheritDoc} */
113  @Override
114  public String getServerRoot()
115  {
116    return serverRoot;
117  }
118
119  /** {@inheritDoc} */
120  @Override
121  public String getInstanceRoot()
122  {
123    return instanceRoot;
124  }
125
126  /** {@inheritDoc} */
127  @Override
128  public synchronized void initializeConfigHandler(String configFile,
129      boolean checkSchema)
130  throws InitializationException
131  {
132    File f = new File(configFile);
133    // We will use the LDIF reader to read the configuration file.  Create an
134    // LDIF import configuration to do this and then get the reader.
135    LDIFReader reader = null;
136    try
137    {
138      try
139      {
140        LDIFImportConfig importConfig =
141          new LDIFImportConfig(f.getAbsolutePath());
142
143        reader = new LDIFReader(importConfig);
144      }
145      catch (Throwable t)
146      {
147        throw new InitializationException(
148            ERR_CONFIG_FILE_CANNOT_OPEN_FOR_READ.get(f.getAbsolutePath(), t), t);
149      }
150
151      if (! f.exists())
152      {
153        LocalizableMessage message =
154          ERR_CONFIG_FILE_DOES_NOT_EXIST.get(f.getAbsolutePath());
155        throw new InitializationException(message);
156      }
157
158      configEntries.clear();
159
160      // Read the first entry from the configuration file.
161      Entry entry;
162      try
163      {
164        entry = reader.readEntry(checkSchema);
165        if (entry == null)
166        {
167          LocalizableMessage message = ERR_CONFIG_FILE_EMPTY.get(f.getAbsolutePath());
168          throw new InitializationException(message);
169        }
170        configRootEntry = new ConfigEntry(entry, null);
171
172        baseDNs = new DN[] { configRootEntry.getDN() };
173
174        configEntries.put(entry.getName(), configRootEntry);
175        // Iterate through the rest of the configuration file and process the
176        // remaining entries.
177        while (entry != null)
178        {
179          // Read the next entry from the configuration.
180          entry = reader.readEntry(checkSchema);
181          if (entry != null)
182          {
183            DN entryDN = entry.getName();
184            DN parentDN = entryDN.parent();
185            ConfigEntry parentEntry = null;
186            if (parentDN != null)
187            {
188              parentEntry = configEntries.get(parentDN);
189            }
190            if (parentEntry == null)
191            {
192              if (parentDN == null)
193              {
194                LocalizableMessage message = ERR_CONFIG_FILE_UNKNOWN_PARENT.get(
195                    entryDN, reader.getLastEntryLineNumber(), f.getAbsolutePath());
196                throw new InitializationException(message);
197              }
198              else
199              {
200                LocalizableMessage message = ERR_CONFIG_FILE_NO_PARENT.get(entryDN,
201                    reader.getLastEntryLineNumber(), f.getAbsolutePath(), parentDN);
202                throw new InitializationException(message);
203              }
204            }
205            else
206            {
207              ConfigEntry configEntry = new ConfigEntry(entry, parentEntry);
208              parentEntry.addChild(configEntry);
209              configEntries.put(entryDN, configEntry);
210            }
211          }
212        }
213      }
214      catch (InitializationException ie)
215      {
216        throw ie;
217      }
218      catch (LDIFException le)
219      {
220        throw new InitializationException(
221            ERR_CONFIG_FILE_INVALID_LDIF_ENTRY.get(le.getLineNumber(), f.getAbsolutePath(), le), le);
222      }
223      catch (Throwable t)
224      {
225        throw new InitializationException(
226            ERR_CONFIG_FILE_READ_ERROR.get(f.getAbsolutePath(), t), t);
227      }
228
229
230      // Determine the appropriate server root.
231      File rootFile = DirectoryServer.getEnvironmentConfig().getServerRoot();
232      serverRoot = rootFile.getAbsolutePath();
233
234      File instanceRootFile =
235        DirectoryEnvironmentConfig.getInstanceRootFromServerRoot(rootFile);
236      instanceRoot = instanceRootFile.getAbsolutePath();
237    }
238    catch (InitializationException ie)
239    {
240      throw ie;
241    }
242    catch (Throwable t)
243    {
244    }
245    finally
246    {
247      close(reader);
248    }
249  }
250
251  /** {@inheritDoc} */
252  @Override
253  public void writeSuccessfulStartupConfig()
254  {
255  }
256
257  /** {@inheritDoc} */
258  @Override
259  public void writeUpdatedConfig() throws DirectoryException
260  {
261  }
262
263  /** {@inheritDoc} */
264  @Override
265  public void addEntry(Entry entry, AddOperation arg1)
266  throws DirectoryException, CanceledOperationException
267  {
268  }
269
270  /** {@inheritDoc} */
271  @Override
272  public void configureBackend(BackendCfg cfg, ServerContext serverContext) throws ConfigException
273  {
274  }
275
276  /** {@inheritDoc} */
277  @Override
278  public void createBackup(BackupConfig arg0) throws DirectoryException
279  {
280  }
281
282  /** {@inheritDoc} */
283  @Override
284  public void deleteEntry(DN arg0, DeleteOperation arg1)
285  throws DirectoryException, CanceledOperationException
286  {
287  }
288
289  /** {@inheritDoc} */
290  @Override
291  public void exportLDIF(LDIFExportConfig arg0) throws DirectoryException
292  {
293  }
294
295  /** {@inheritDoc} */
296  @Override
297  public DN[] getBaseDNs()
298  {
299    return baseDNs;
300  }
301
302  /** {@inheritDoc} */
303  @Override
304  public Entry getEntry(DN entryDN)
305  throws DirectoryException
306  {
307    ConfigEntry configEntry = configEntries.get(entryDN);
308    if (configEntry != null)
309    {
310      return configEntry.getEntry();
311    }
312    return null;
313  }
314
315  /** {@inheritDoc} */
316  @Override
317  public long getEntryCount()
318  {
319    return configEntries.size();
320  }
321
322  /** {@inheritDoc} */
323  @Override
324  public Set<String> getSupportedControls()
325  {
326    return Collections.emptySet();
327  }
328
329  /** {@inheritDoc} */
330  @Override
331  public Set<String> getSupportedFeatures()
332  {
333    return Collections.emptySet();
334  }
335
336  /** {@inheritDoc} */
337  @Override
338  public ConditionResult hasSubordinates(DN entryDN) throws DirectoryException
339  {
340    ConfigEntry baseEntry = configEntries.get(entryDN);
341    if (baseEntry != null)
342    {
343      return ConditionResult.valueOf(baseEntry.hasChildren());
344    }
345    return ConditionResult.UNDEFINED;
346  }
347
348  /** {@inheritDoc} */
349  @Override
350  public LDIFImportResult importLDIF(LDIFImportConfig importConfig, ServerContext serverContext)
351      throws DirectoryException
352  {
353    return null;
354  }
355
356  /** {@inheritDoc} */
357  @Override
358  public void openBackend() throws ConfigException, InitializationException
359  {
360  }
361
362  /** {@inheritDoc} */
363  @Override
364  public boolean isIndexed(AttributeType arg0, IndexType arg1)
365  {
366    return false;
367  }
368
369  /** {@inheritDoc} */
370  @Override
371  public long getNumberOfChildren(DN parentDN) throws DirectoryException {
372    checkNotNull(parentDN, "parentDN must not be null");
373    return numSubordinates(parentDN, false);
374  }
375
376  /** {@inheritDoc} */
377  @Override
378  public long getNumberOfEntriesInBaseDN(DN baseDN) throws DirectoryException {
379    checkNotNull(baseDN, "baseDN must not be null");
380    return numSubordinates(baseDN, true) + 1;
381  }
382
383  private long numSubordinates(DN entryDN, boolean subtree) throws DirectoryException
384  {
385    final ConfigEntry baseEntry = configEntries.get(entryDN);
386    if (baseEntry == null)
387    {
388      return -1;
389    }
390
391    if(!subtree)
392    {
393      return baseEntry.getChildren().size();
394    }
395    long count = 0;
396    for (ConfigEntry child : baseEntry.getChildren().values())
397    {
398      count += numSubordinates(child.getDN(), true);
399      count++;
400    }
401    return count;
402  }
403
404  /** {@inheritDoc} */
405  @Override
406  public void removeBackup(BackupDirectory backupDirectory, String backupID)
407  throws DirectoryException
408  {
409  }
410
411  /** {@inheritDoc} */
412  @Override
413  public void renameEntry(DN currentDN, Entry entry, ModifyDNOperation modifyDNOperation)
414  throws DirectoryException, CanceledOperationException
415  {
416  }
417
418  /** {@inheritDoc} */
419  @Override
420  public void replaceEntry(Entry oldEntry, Entry newEntry, ModifyOperation modifyOperation)
421  throws DirectoryException, CanceledOperationException
422  {
423  }
424
425  /** {@inheritDoc} */
426  @Override
427  public void restoreBackup(RestoreConfig restoreConfig) throws DirectoryException
428  {
429  }
430
431  /** {@inheritDoc} */
432  @Override
433  public void search(SearchOperation searchOperation)
434  throws DirectoryException, CanceledOperationException
435  {
436  }
437
438  /** {@inheritDoc} */
439  @Override
440  public boolean supports(BackendOperation backendOperation)
441  {
442    return false;
443  }
444}