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