/* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2015 ForgeRock AS. */ package org.forgerock.opendj.maven; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.LinkedList; import java.util.List; import java.util.TreeSet; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; /** * Concatenates the contents of the files in the schema directory to create a * base schema that may be used during the upgrade process. Each element will * also include the X-SCHEMA-FILE extension to indicate the source schema file. *

* There is a single goal that generates the base schema. *

*/ @Mojo(name = "concat", defaultPhase = LifecyclePhase.GENERATE_SOURCES) public final class ConcatSchemaMojo extends AbstractMojo { /** * The Maven Project. */ @Parameter(property = "project", required = true, readonly = true) private MavenProject project; /** * The path to the directory containing the schema files. */ @Parameter(required = true, defaultValue = "${basedir}/resource/schema") private String schemaDirectory; /** * The directory path of the concatenated schema file to create. Must be in ${project.build.directory} */ @Parameter(required = true) private String outputDirectory; /** * The file name of the concatenated schema file to create. */ @Parameter(required = true) private String outputFile; /** {@inheritDoc} */ @Override public void execute() throws MojoExecutionException, MojoFailureException { String projectBuildDir = project.getBuild().getDirectory(); String outputFilePath = outputDirectory + System.getProperty("file.separator") + outputFile; if (!outputDirectory.contains(projectBuildDir)) { String errorMsg = String.format("outputDirectory parameter (%s) must be included " + "in ${project.build.directory} (%s)", outputDirectory, projectBuildDir); getLog().error(errorMsg); throw new MojoExecutionException(errorMsg); } getLog().info(String.format("Concatenating all ldif files from directory: %s", schemaDirectory)); getLog().info(String.format("Concatenated file: %s", outputFilePath)); new File(outputFilePath).getParentFile().mkdirs(); // Get a sorted list of the files in the schema directory. TreeSet schemaFileNames = new TreeSet<>(); for (File f : new File(schemaDirectory).listFiles()) { if (f.isFile()) { schemaFileNames.add(f.getName()); } } // Create a set of lists that will hold the schema elements read from the files. LinkedList attributeTypes = new LinkedList<>(); LinkedList objectClasses = new LinkedList<>(); LinkedList nameForms = new LinkedList<>(); LinkedList ditContentRules = new LinkedList<>(); LinkedList ditStructureRules = new LinkedList<>(); LinkedList matchingRuleUses = new LinkedList<>(); LinkedList ldapSyntaxes = new LinkedList<>(); int curLineNumber = 0; // Open each of the files in order and read the elements that they contain, // appending them to the appropriate lists. for (String name : schemaFileNames) { // Read the contents of the file into a list with one schema element per // list element. LinkedList lines = new LinkedList<>(); try { BufferedReader reader = new BufferedReader(new FileReader(new File(schemaDirectory, name))); String line = reader.readLine(); while (line != null) { curLineNumber++; if (line.length() > 0 && !line.startsWith("#")) { if (line.startsWith(" ")) { lines.getLast().append(line.substring(1)); } else { lines.add(new StringBuilder(line)); } } line = reader.readLine(); } reader.close(); } catch (Exception e) { getLog().error(String.format( "Error while reading schema file %s at line %d: %s", name, curLineNumber, e.getMessage())); throw new MojoExecutionException(e.getMessage(), e); } // Iterate through each line in the list. Find the colon and get the // attribute name at the beginning. If it's someting that we don't // recognize, then skip it. Otherwise, add the X-SCHEMA-FILE extension // and add it to the appropriate schema element list. for (StringBuilder buffer : lines) { // Get the line and add the X-SCHEMA-FILE extension to the end of it. // All of them should end with " )" but some might have the parenthesis // crammed up against the last character so deal with that as well. String line = buffer.toString().trim(); if (line.endsWith(" )")) { line = line.substring(0, line.length() - 1) + "X-SCHEMA-FILE '" + name + "' )"; } else if (line.endsWith(")")) { line = line.substring(0, line.length() - 1) + " X-SCHEMA-FILE '" + name + "' )"; } else { continue; } String lowerLine = line.toLowerCase(); if (lowerLine.startsWith("attributetypes:")) { attributeTypes.add(line); } else if (lowerLine.startsWith("objectclasses:")) { objectClasses.add(line); } else if (lowerLine.startsWith("nameforms:")) { nameForms.add(line); } else if (lowerLine.startsWith("ditcontentrules:")) { ditContentRules.add(line); } else if (lowerLine.startsWith("ditstructurerules:")) { ditStructureRules.add(line); } else if (lowerLine.startsWith("matchingruleuse:")) { matchingRuleUses.add(line); } else if (lowerLine.startsWith("ldapsyntaxes:")) { ldapSyntaxes.add(line); } } } // Write the resulting output to the merged schema file. try { BufferedWriter writer = new BufferedWriter(new FileWriter(outputFilePath)); writer.write("dn: cn=schema"); writer.newLine(); writer.write("objectClass: top"); writer.newLine(); writer.write("objectClass: ldapSubentry"); writer.newLine(); writer.write("objectClass: subschema"); writer.newLine(); writeSchemaElements(ldapSyntaxes, writer); writeSchemaElements(attributeTypes, writer); writeSchemaElements(objectClasses, writer); writeSchemaElements(nameForms, writer); writeSchemaElements(ditContentRules, writer); writeSchemaElements(ditStructureRules, writer); writeSchemaElements(matchingRuleUses, writer); writer.close(); } catch (Exception e) { getLog().error( String.format("Error while writing concatenated schema file %s: %s", outputFile, e.getMessage())); throw new MojoExecutionException(e.getMessage(), e); } } private void writeSchemaElements(List schemaElements, BufferedWriter writer) throws IOException { for (String line : schemaElements) { writer.write(line); writer.newLine(); } } }