/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Portions Copyright 2013-2015 ForgeRock AS
*/
/**
* Common utility methods needed by the upgrade.
*/
final class UpgradeUtils
{
/** The config folder of the current instance. */
/** The template folder of the current installation. */
/** The lib folder of the current installation. */
/** The bin folder of the current installation. */
static final File binDirectory = new File(getInstallationPath(), Installation.UNIX_BINARIES_PATH_RELATIVE);
/** The bat folder of the current installation. */
static final File batDirectory = new File(getInstallationPath(), Installation.WINDOWS_BINARIES_PATH_RELATIVE);
/**
* Returns the path of the installation of the directory server. Note that
* this method assumes that this code is being run locally.
*
* @return the path of the installation of the directory server.
*/
{
if (installPath != null)
{
return installPath;
}
/* Get the install path from the Class Path */
final String[] classPaths =
{
/*
* Do a best effort to avoid having a relative representation (for
* instance to avoid having ../../../).
*/
try
{
}
catch (IOException ioe)
{
// Best effort
}
}
return installPath;
}
{
{
{
return classPath;
}
}
return null;
}
/**
* Returns the path of the installation of the directory server. Note that
* this method assumes that this code is being run locally.
*
* @param installPath
* The installation path
* @return the path of the installation of the directory server.
*/
{
final File _svcScriptPath =
// look for /etc/opt/opendj/instance.loc
{
// look for <installPath>/instance.loc
f = new File(instancePathFileName);
if (!f.exists())
{
return installPath;
}
}
try
{
}
catch (Exception e)
{
return installPath;
}
// Read the first line and close the file.
try
{
if (instanceLoc.isAbsolute())
{
return instanceLoc.getAbsolutePath();
}
else
{
.getAbsolutePath();
}
}
catch (Exception e)
{
return installPath;
}
finally
{
}
}
/**
* Returns the absolute path for the given file. It tries to get the canonical
* file path. If it fails it returns the string representation.
*
* @param f
* File to get the path
* @return the absolute path for the given file.
*/
{
if (f != null)
{
try
{
/*
* Do a best effort to avoid having a relative representation (for
* instance to avoid having ../../../).
*/
f = f.getCanonicalFile();
}
catch (IOException ioe)
{
/*
* This is a best effort to get the best possible representation of the
* file: reporting the error is not necessary.
*/
}
}
return path;
}
/**
* Returns the absolute path for the given parentPath and relativePath.
*
* @param parentPath
* the parent path.
* @param relativePath
* the relative path.
* @return the absolute path for the given parentPath and relativePath.
*/
final String relativePath)
{
}
{
}
/**
* Determines whether one file is the parent of another.
*
* @param ancestor
* possible parent of <code>descendant</code>
* @param descendant
* possible child 0f <code>ancestor</code>
* @return return true if ancestor is a parent of descendant
*/
{
{
{
return false;
}
{
}
}
}
/**
* Returns <CODE>true</CODE> if the first provided path is under the second
* path in the file system.
* @param descendant the descendant candidate path.
* @param path the path.
* @return <CODE>true</CODE> if the first provided path is under the second
* path in the file system; <code>false</code> otherwise or if
* either of the files are null
*/
return true;
}
}
}
return false;
}
/**
* Returns the instance root directory (the path where the instance is
* installed).
*
* @return the instance root directory (the path where the instance is
* installed).
*/
{
if (installPath == null)
{
return null;
}
}
/**
* Returns the server's installation path.
*
* @return The server's installation path.
*/
{
// The upgrade runs from the bits extracted by BuildExtractor
// in the staging directory. However
// we still want the Installation to point at the build being
// upgraded so the install path reported in [installroot].
if (installationPath == null)
{
{
if (f.getParentFile() != null
{
}
else
{
}
}
}
return installationPath;
}
/**
* Retrieves the backends from the current configuration file. The backends
* must be enabled to be listed. No operations should be done within a
* disabled backend.
*
* @return A backend list.
*/
{
"(&(objectclass=ds-cfg-pluggable-backend)(ds-cfg-enabled=true))",
"ds-cfg-base-dn");
{
while (entryReader.hasNext())
{
}
}
{
}
return listBackends;
}
{
final LDIFEntryReader entryReader = new LDIFEntryReader(new FileInputStream(configFile)).setSchema(schema);
}
/**
* Updates the config file during the upgrade process.
*
* @param configPath
* The original path to the file.
* @param filter
* The filter to select entries. Only useful for modify change type.
* @param changeType
* The change type which must be applied to ldif lines.
* @param ldifLines
* The change record ldif lines.
* For ADD change type, the first line must be the dn.
* For DELETE change type, the first and only line must be the dn.
* @throws IOException
* If an Exception occurs during the input output methods.
* @return The changes number that have occurred.
*/
{
final File copyConfig =
int changeCount = 0;
try
{
// Writes the header on the new file.
boolean entryAlreadyExist = false;
{
// The first line should start with dn:
}
while (entryReader.hasNext())
{
// Searching for the related entries
if (changeType == MODIFY
{
try
{
changeCount++;
"The following entry has been modified : %s", entryDN));
}
{
}
}
{
entryAlreadyExist = true;
if (changeType == DELETE)
{
changeCount++;
"The following entry has been deleted : %s", entryDN));
}
}
{
}
}
{
changeCount++;
}
}
{
}
finally
{
// The reader and writer must be close before renaming files.
// Otherwise it causes exceptions under windows OS.
}
try
{
// Renaming the file, overwriting previous one.
}
catch (IOException e)
{
throw e;
}
return changeCount;
}
/**
* This task adds new attributes / object classes to the specified destination
* file. The new attributes and object classes must be originally defined in
* the template file.
*
* @param templateFile
* @param destination
* The file where we want to add the new definitions.
* @param attributes
* Those attributes needed to be inserted into the new destination
* file.
* @param objectClasses
* Those object classes needed to be inserted into the new
* destination file.
* @return An integer which represents each time an attribute / object class
* is inserted successfully to the destination file.
* @throws IOException
* If an unexpected IO error occurred while reading the entry.
* @throws IllegalStateException
* Failure to find an attribute in the template schema indicates
* either a programming error (e.g. typo in the attribute name) or
* template corruption. Upgrade should stop.
*/
throws IOException, IllegalStateException
{
int changeCount = 0;
try
{
if (!templateReader.hasNext())
{
// Unless template are corrupted, this should not happen.
}
destinationReader = new LDIFEntryReader(
new FileInputStream(destination));
if (!destinationReader.hasNext())
{
// Unless template are corrupted, this should not happen.
}
if (attributes != null)
{
{
final ByteString attributeType =
changeCount++;
}
}
if (objectClasses != null)
{
{
final ByteString objectClass =
changeCount++;
}
}
// Then writes the new schema entry.
copy =
// Copy comments to fos (get License and first comments only).
// Writes the entry after.
}
finally
{
// Readers and writer must be close before writing files.
// This causes exceptions under windows OS.
}
// Renames the copy to make it the new schema file.
try
{
}
catch (IOException e)
{
throw e;
}
return changeCount;
}
/**
* Gets and writes the first comments of a file.
*
* @param file
* The selected file to get the comments.
* @param writer
* The writer which is going to write the comments.
* @throws IOException
* If an error occurred with the file.
*/
{
try
{
{
}
}
catch (IOException ex)
{
throw ex;
}
finally
{
}
}
/**
* Returns the definition of the selected attribute / object class OID.
*
* @param schemaEntry
* The selected schema entry to search on.
* @param type
* The type of the research. ("objectClasses" or "attributeTypes")
* @param oid
* The OID of the element to search for.
* @return The byte string definition of the element.
*/
{
final MatchingRule mrule =
try
{
{
{
return value;
}
}
}
catch (DecodeException e)
{
throw new IllegalStateException(e);
}
.toString());
}
/**
* folder.
*
* @param folder
* The folder containing the schema files.
* @param revision
* The revision number of the current binary version.
* @throws Exception
* If we cannot read the files contained in the folder where the
* schema files are supposed to be, or the file has errors.
*/
{
// We need to upgrade the schema.ldif.<rev> file contained in the
// will be read at start-up.
try
{
if (folder.isDirectory())
{
final FilenameFilter filter =
{
.getAbsolutePath())));
try
{
{
{
}
}
}
{
throw new Exception("Error parsing existing schema file "
}
}
// Creates a File object representing
// config/upgrade/schema.ldif.revision which the server creates
// the first time it starts if there are schema customizations.
final File destination =
// Checks if the parent exists (eg. embedded
// server doesn't seem to provide that folder)
if (!parentDirectory.exists())
{
destination.getPath())));
parentDirectory.getPath())));
}
if (!destination.exists())
{
}
.getAbsolutePath())));
"%s created and completed successfully.", destination
.getAbsolutePath())));
}
}
finally
{
}
}
/**
* Returns a schema used by upgrade(default octet string matching rule and
* directory string syntax). Added attribute types which we know we are
* sensitive to in the unit tests, e.g. ds-cfg-enabled (boolean syntax),
* ds-cfg-filter(case ingnore), ds-cfg-collation (case ignore)... related to
* upgrade tasks. See OPENDJ-1245.
*
* @return A schema which may used in the upgrade context.
*/
// Adds ds-cfg-enabled / boolean syntax
+ " EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7"
+ " SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' )", false);
// Adds ds-cfg-filter / ignore match syntax
+ " EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
+ " X-ORIGIN 'OpenDS Directory Server' )", false);
// Adds ds-cfg-collation / ignore match syntax
+ " EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
+ " X-ORIGIN 'OpenDS Directory Server' )", false);
}
{
if (changeType == MODIFY)
{
}
return modifiedLines;
}
/** Prevent instantiation. */
private UpgradeUtils()
{
throw new AssertionError();
}
}