mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
05.54.2011 886a64b8c1ddc854958bbac92cc9b76d91d3fe26
OPENDJ-370: Implement an example Sun DSEE -> OpenDJ change log based synchronization daemon.

Initial commit of core APIs and build infrastructure, including:

* core filter APIs
* common transformations
* common matchers for conditional processing of transformations
* ChangeRecordWriter transformation
18 files added
1 files modified
3004 ■■■■■ changed files
opendj3/opendj-ldap-sync/README 14 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/pom.xml 127 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/assembly/bat/ldapsync.bat 33 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/assembly/bin/ldapsync 37 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/assembly/descriptor.xml 99 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/assembly/libbat/_client-script.bat 53 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/assembly/libbat/_script-util.bat 201 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/assembly/libbat/setcp.bat 40 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/assembly/libbin/_client-script.sh 65 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/assembly/libbin/_script-util.sh 130 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/Main.java 54 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/ChangeRecordContext.java 138 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Filter.java 107 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/FilterResult.java 267 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Matchers.java 910 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Transforms.java 657 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/package-info.java 34 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/package-info.java 37 ●●●●● patch | view | raw | blame | history
opendj3/pom.xml 1 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sync/README
New file
@@ -0,0 +1,14 @@
OpenDJ LDAP synchronization tool.
This Maven project contains the OpenDJ LDAP synchronization daemon. It is 100%
Java based and requires Java 1.6.
OpenDJ is a downstream build of the OpenDS project, with a different name
to avoid trademark issues.
Complete documentation for this product may be found online
at http://www.forgerock.com/opendj.html.
This product is made available under the Common Development and Distribution
License (CDDL).  The complete text for this license, and for alternate licenses
of included components, may be found in the legal-notices directory.
opendj3/opendj-ldap-sync/pom.xml
New file
@@ -0,0 +1,127 @@
<?xml version="1.0"?>
<!--
 ! 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
 ! trunk/opendj3/legal-notices/CDDLv1_0.txt
 ! or http://forgerock.org/license/CDDLv1.0.html.
 ! 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
 ! trunk/opendj3/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
 !
 !      Copyright 2011 ForgeRock AS
 !
 -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <artifactId>opendj-project</artifactId>
    <groupId>org.forgerock.opendj</groupId>
    <version>3.0.0-SNAPSHOT</version>
  </parent>
  <artifactId>opendj-ldap-sync</artifactId>
  <name>OpenDJ LDAP Synchronization Daemon</name>
  <description>
    This module includes an LDAP synchronization daemon based on the OpenDJ
    LDAP SDK.
  </description>
  <packaging>jar</packaging>
  <dependencies>
    <dependency>
      <groupId>org.forgerock.opendj</groupId>
      <artifactId>opendj-ldap-sdk</artifactId>
      <version>${project.version}</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.forgerock.opendj</groupId>
      <artifactId>opendj-build-tools</artifactId>
      <version>${project.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <!--
      <plugin>
        <groupId>org.forgerock.commons</groupId>
        <artifactId>i18n-maven-plugin</artifactId>
        <executions>
          <execution>
            <phase>generate-sources</phase>
            <goals>
              <goal>generate-messages</goal>
            </goals>
            <configuration>
              <messageFiles>
                <messageFile>com/forgerock/opendj/sync/sync.properties</messageFile>
              </messageFiles>
            </configuration>
          </execution>
        </executions>
      </plugin>
      -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-checkstyle-plugin</artifactId>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <appendAssemblyId>false</appendAssemblyId>
              <descriptors>
                <descriptor>src/main/assembly/descriptor.xml</descriptor>
              </descriptors>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <reporting>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-project-info-reports-plugin</artifactId>
        <reportSets>
          <reportSet>
            <reports>
              <report>mailing-list</report>
              <report>issue-tracking</report>
              <report>license</report>
              <report>scm</report>
              <report>cim</report>
              <report>distribution-management</report>
            </reports>
          </reportSet>
        </reportSets>
      </plugin>
    </plugins>
  </reporting>
</project>
opendj3/opendj-ldap-sync/src/main/assembly/bat/ldapsync.bat
New file
@@ -0,0 +1,33 @@
@echo off
rem CDDL HEADER START
rem
rem The contents of this file are subject to the terms of the
rem Common Development and Distribution License, Version 1.0 only
rem (the "License").  You may not use this file except in compliance
rem with the License.
rem
rem You can obtain a copy of the license at
rem trunk/opendj3/legal-notices/CDDLv1_0.txt
rem or http://forgerock.org/license/CDDLv1.0.html.
rem See the License for the specific language governing permissions
rem and limitations under the License.
rem
rem When distributing Covered Code, include this CDDL HEADER in each
rem file and include the License file at
rem trunk/opendj3/legal-notices/CDDLv1_0.txt.  If applicable,
rem add the following below this CDDL HEADER, with the fields enclosed
rem by brackets "[]" replaced with your own identifying information:
rem      Portions Copyright [yyyy] [name of copyright owner]
rem
rem CDDL HEADER END
rem
rem
rem      Copyright 2011 ForgeRock AS.
setlocal
set OPENDJ_INVOKE_CLASS="com.forgerock.opendj.sync.Main"
set SCRIPT_NAME=ldapsync
for %%i in (%~sf0) do call "%%~dPsi\..\lib\_client-script.bat" %*
opendj3/opendj-ldap-sync/src/main/assembly/bin/ldapsync
New file
@@ -0,0 +1,37 @@
#!/bin/sh
#
# 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
# trunk/opendj3/legal-notices/CDDLv1_0.txt
# or http://forgerock.org/license/CDDLv1.0.html.
# 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
# trunk/opendj3/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
#
#
#      Copyright 2011 ForgeRock AS.
# This script may be used to perform LDAP search operations.
OPENDJ_INVOKE_CLASS="com.forgerock.opendj.sync.Main"
export OPENDJ_INVOKE_CLASS
SCRIPT_NAME="ldapsync"
export SCRIPT_NAME
SCRIPT_DIR=`dirname "${0}"`
"${SCRIPT_DIR}/../lib/_client-script.sh" "${@}"
opendj3/opendj-ldap-sync/src/main/assembly/descriptor.xml
New file
@@ -0,0 +1,99 @@
<?xml version="1.0"?>
<!--
 ! 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
 ! trunk/opendj3/legal-notices/CDDLv1_0.txt
 ! or http://forgerock.org/license/CDDLv1.0.html.
 ! 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
 ! trunk/opendj3/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
 !
 !      Copyright 2011 ForgeRock AS
 !
 -->
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
                      http://maven.apache.org/xsd/assembly-1.1.2.xsd">
  <id>opendj-ldap-sync</id>
  <formats>
    <format>zip</format>
  </formats>
  <fileSets>
    <fileSet>
      <directory>${project.basedir}</directory>
      <outputDirectory>/</outputDirectory>
      <directoryMode>755</directoryMode>
      <fileMode>644</fileMode>
      <includes>
        <include>README</include>
        <include>LICENSE</include>
        <include>NOTICE</include>
      </includes>
    </fileSet>
    <fileSet>
      <directory>${project.parent.parent.basedir}/legal-notices</directory>
      <outputDirectory>legal-notices</outputDirectory>
      <directoryMode>0755</directoryMode>
      <fileMode>0644</fileMode>
    </fileSet>
  <fileSet>
    <directory>${project.parent.parent.basedir}</directory>
    <outputDirectory>/</outputDirectory>
    <directoryMode>755</directoryMode>
    <fileMode>644</fileMode>
    <includes>
      <include>*.png</include>
    </includes>
  </fileSet>
    <fileSet>
      <directory>src/main/assembly/bin</directory>
      <outputDirectory>bin</outputDirectory>
      <directoryMode>0755</directoryMode>
      <fileMode>0755</fileMode>
      <lineEnding>unix</lineEnding>
    </fileSet>
    <fileSet>
      <directory>src/main/assembly/bat</directory>
      <outputDirectory>bat</outputDirectory>
      <directoryMode>0755</directoryMode>
      <fileMode>0644</fileMode>
      <lineEnding>dos</lineEnding>
    </fileSet>
    <fileSet>
      <directory>src/main/assembly/libbin</directory>
      <outputDirectory>lib</outputDirectory>
      <directoryMode>0755</directoryMode>
      <fileMode>0755</fileMode>
      <lineEnding>unix</lineEnding>
    </fileSet>
    <fileSet>
      <directory>src/main/assembly/libbat</directory>
      <outputDirectory>lib</outputDirectory>
      <directoryMode>0755</directoryMode>
      <fileMode>0644</fileMode>
      <lineEnding>dos</lineEnding>
    </fileSet>
  </fileSets>
  <dependencySets>
    <dependencySet>
      <outputDirectory>lib</outputDirectory>
      <directoryMode>0755</directoryMode>
      <fileMode>0644</fileMode>
    </dependencySet>
  </dependencySets>
</assembly>
opendj3/opendj-ldap-sync/src/main/assembly/libbat/_client-script.bat
New file
@@ -0,0 +1,53 @@
@echo off
rem CDDL HEADER START
rem
rem The contents of this file are subject to the terms of the
rem Common Development and Distribution License, Version 1.0 only
rem (the "License").  You may not use this file except in compliance
rem with the License.
rem
rem You can obtain a copy of the license at
rem trunk/opendj3/legal-notices/CDDLv1_0.txt
rem or http://forgerock.org/license/CDDLv1.0.html.
rem See the License for the specific language governing permissions
rem and limitations under the License.
rem
rem When distributing Covered Code, include this CDDL HEADER in each
rem file and include the License file at
rem trunk/opendj3/legal-notices/CDDLv1_0.txt.  If applicable,
rem add the following below this CDDL HEADER, with the fields enclosed
rem by brackets "[]" replaced with your own identifying information:
rem      Portions Copyright [yyyy] [name of copyright owner]
rem
rem CDDL HEADER END
rem
rem
rem      Copyright 2006-2009 Sun Microsystems, Inc.
rem This script is used to invoke various client-side processes.  It should not
rem be invoked directly by end users.
setlocal
for %%i in (%~sf0) do set DIR_HOME=%%~dPsi..
set INSTALL_ROOT=%DIR_HOME%
if "%NO_CHECK%" == "" set NO_CHECK=true
if "%OPENDJ_INVOKE_CLASS%" == "" goto noInvokeClass
goto launchCommand
:noInvokeClass
echo Error:  OPENDJ_INVOKE_CLASS environment variable is not set.
pause
goto end
:launchCommand
set SCRIPT_UTIL_CMD=set-full-environment
call "%INSTALL_ROOT%\lib\_script-util.bat" $*
if NOT %errorlevel% == 0 exit /B %errorlevel%
"%OPENDJ_JAVA_BIN%" %OPENDJ_JAVA_ARGS% %SCRIPT_NAME_ARG% %OPENDJ_INVOKE_CLASS% %*
:end
opendj3/opendj-ldap-sync/src/main/assembly/libbat/_script-util.bat
New file
@@ -0,0 +1,201 @@
@echo off
rem CDDL HEADER START
rem
rem The contents of this file are subject to the terms of the
rem Common Development and Distribution License, Version 1.0 only
rem (the "License").  You may not use this file except in compliance
rem with the License.
rem
rem You can obtain a copy of the license at
rem trunk/opendj3/legal-notices/CDDLv1_0.txt
rem or http://forgerock.org/license/CDDLv1.0.html.
rem See the License for the specific language governing permissions
rem and limitations under the License.
rem
rem When distributing Covered Code, include this CDDL HEADER in each
rem file and include the License file at
rem trunk/opendj3/legal-notices/CDDLv1_0.txt.  If applicable,
rem add the following below this CDDL HEADER, with the fields enclosed
rem by brackets "[]" replaced with your own identifying information:
rem      Portions Copyright [yyyy] [name of copyright owner]
rem
rem CDDL HEADER END
rem
rem
rem      Copyright 2008-2009 Sun Microsystems, Inc.
set SET_JAVA_HOME_AND_ARGS_DONE=false
set SET_ENVIRONMENT_VARS_DONE=false
set SET_CLASSPATH_DONE=false
if "%INSTALL_ROOT%" == "" goto setInstanceRoot
:scriptBegin
if "%SCRIPT_UTIL_CMD%" == "set-full-environment-and-test-java" goto setFullEnvironmentAndTestJava
if "%SCRIPT_UTIL_CMD%" == "set-full-environment" goto setFullEnvironment
if "%SCRIPT_UTIL_CMD%" == "set-java-home-and-args" goto setJavaHomeAndArgs
if "%SCRIPT_UTIL_CMD%" == "set_environment_vars" goto setEnvironmentVars
if "%SCRIPT_UTIL_CMD%" == "test-java" goto testJava
if "%SCRIPT_UTIL_CMD%" == "set-classpath" goto setClassPath
goto prepareCheck
:setInstanceRoot
setlocal
for %%i in (%~sf0) do set DIR_HOME=%%~dPsi..
set INSTALL_ROOT=%DIR_HOME%
set CUR_DIR=%~dp0
cd /d %INSTALL_ROOT%
cd /d %INSTANCE_DIR%
set INSTANCE_ROOT=%CD%
cd /d %CUR_DIR%
goto scriptBegin
:setClassPath
if "%SET_CLASSPATH_DONE%" == "true" goto prepareCheck
FOR %%x in ("%INSTALL_ROOT%\lib\*.jar") DO call "%INSTALL_ROOT%\lib\setcp.bat" %%x
if "%INSTALL_ROOT%" == "%INSTANCE_ROOT%"goto setClassPathDone
FOR %%x in ("%INSTANCE_ROOT%\lib\*.jar") DO call "%INSTANCE_ROOT%\lib\setcp.bat" %%x
FOR %%x in ("%INSTALL_ROOT%\resources\*.jar") DO call "%INSTALL_ROOT%\lib\setcp.bat" %%x
set CLASSPATH=%INSTANCE_ROOT%\classes;%CLASSPATH%
:setClassPathDone
set SET_CLASSPATH_DONE=true
goto scriptBegin
:setFullEnvironment
if "%SET_JAVA_HOME_AND_ARGS_DONE%" == "false" goto setJavaHomeAndArgs
if "%SET_CLASSPATH_DONE%" == "false" goto setClassPath
if "%SET_ENVIRONMENT_VARS_DONE%" == "false" goto setEnvironmentVars
goto prepareCheck
:setFullEnvironmentAndTestJava
if "%SET_JAVA_HOME_AND_ARGS_DONE%" == "false" goto setJavaHomeAndArgs
if "%SET_CLASSPATH_DONE%" == "false" goto setClassPath
if "%SET_ENVIRONMENT_VARS_DONE%" == "false" goto setEnvironmentVars
goto testJava
:setJavaHomeAndArgs
if "%SET_JAVA_HOME_AND_ARGS_DONE%" == "true" goto prepareCheck
if not exist "%INSTANCE_ROOT%\lib\set-java-home.bat" goto checkEnvJavaArgs
call "%INSTANCE_ROOT%\lib\set-java-home.bat"
if "%OPENDJ_JAVA_BIN%" == "" goto checkEnvJavaArgs
:endJavaHomeAndArgs
set SET_JAVA_HOME_AND_ARGS_DONE=true
goto scriptBegin
:checkEnvJavaArgs
if "%OPENDJ_JAVA_BIN%" == "" goto checkOpenDJJavaHome
if not exist "%OPENDJ_JAVA_BIN%" goto checkOpenDJJavaHome
goto endJavaHomeAndArgs
:checkOpenDJJavaHome
if "%OPENDJ_JAVA_HOME%" == "" goto checkJavaBin
if not exist "%OPENDJ_JAVA_HOME%\bin\java.exe" goto checkJavaBin
set OPENDJ_JAVA_BIN=%OPENDJ_JAVA_HOME%\bin\java.exe
goto endJavaHomeAndArgs
:checkJavaBin
if "%JAVA_BIN%" == "" goto checkJavaHome
if not exist "%JAVA_BIN%" goto checkJavaHome
set OPENDJ_JAVA_BIN=%JAVA_BIN%
goto endJavaHomeAndArgs
:checkJavaHome
if "%JAVA_HOME%" == "" goto checkJavaPath
if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaFound
set OPENDJ_JAVA_BIN=%JAVA_HOME%\bin\java.exe
goto endJavaHomeAndArgs
:checkJavaPath
java.exe -version > NUL 2>&1
if not %errorlevel% == 0 goto noJavaFound
set OPENDJ_JAVA_BIN=java.exe
goto endJavaHomeAndArgs
:noJavaFound
echo ERROR:  Could not find a valid Java binary to be used.
echo You must specify the path to a valid Java 5.0 or higher version.
echo The procedure to follow is:
echo 1. Delete the file %INSTANCE_ROOT%\lib\set-java-home.bat if it exists.
echo 2. Set the environment variable OPENDJ_JAVA_HOME to the root of a valid
echo Java 5.0 installation.
echo If you want to have specific Java settings for each command line you must
echo follow the steps 3 and 4.
echo 3. Edit the properties file specifying the Java binary and the Java arguments
echo for each command line.  The Java properties file is located in:
echo %INSTANCE_ROOT%\config\java.properties.
echo 4. Run the command-line %INSTALL_ROOT%\bat\dsjavaproperties.bat
pause
exit /B 1
:setEnvironmentVars
if %SET_ENVIRONMENT_VARS_DONE% == "true" goto prepareCheck
set PATH=%SystemRoot%;%PATH%
set SCRIPT_NAME_ARG=-Dcom.forgerock.opendj.ldap.tools.scriptName=%SCRIPT_NAME%
set SET_ENVIRONMENT_VARS_DONE=true
goto scriptBegin
:noValidJavaHome
if NOT "%OPENDJ_JAVA_ARGS%" == "" goto noValidHomeWithArgs
echo ERROR:  The detected Java version could not be used.  The detected
echo Java binary is:
echo %OPENDJ_JAVA_BIN%
echo You must specify the path to a valid Java 5.0 or higher version.
echo The procedure to follow is:
echo 1. Delete the file %INSTANCE_ROOT%\lib\set-java-home.bat if it exists.
echo 2. Set the environment variable OPENDJ_JAVA_HOME to the root of a valid
echo Java 5.0 installation.
echo If you want to have specific Java settings for each command line you must
echo follow the steps 3 and 4.
echo 3. Edit the properties file specifying the Java binary and the Java arguments
echo for each command line.  The Java properties file is located in:
echo %INSTANCE_ROOT%\config\java.properties.
echo 4. Run the command-line %INSTALL_ROOT%\bat\dsjavaproperties.bat
pause
exit /B 1
:notSupportedJavaHome
rem We get here when the java version is 5 (or up) but not supported.  We run
rem InstallDS again to see a localized message.
"%OPENDJ_JAVA_BIN%" %OPENDJ_JAVA_ARGS% org.opendj.server.tools.InstallDS -t
pause
exit /B 1
:noValidHomeWithArgs
echo ERROR:  The detected Java version could not be used with the set of Java
echo arguments %OPENDJ_JAVA_ARGS%.
echo The detected Java binary is:
echo %OPENDJ_JAVA_BIN%
echo You must specify the path to a valid Java 5.0 or higher version.
echo The procedure to follow is:
echo 1. Delete the file %INSTANCE_ROOT%\lib\set-java-home.bat if it exists.
echo 2. Set the environment variable OPENDJ_JAVA_HOME to the root of a valid
echo Java 5.0 installation.
echo If you want to have specific Java settings for each command line you must
echo follow the steps 3 and 4.
echo 3. Edit the properties file specifying the Java binary and the Java arguments
echo for each command line.  The Java properties file is located in:
echo %INSTANCE_ROOT%\config\java.properties.
echo 4. Run the command-line %INSTALL_ROOT%\bat\dsjavaproperties.bat
pause
exit /B 1
:isVersionOrHelp
if [%1] == [] goto check
if [%1] == [--help] goto end
if [%1] == [-H] goto end
if [%1] == [--version] goto end
if [%1] == [-V] goto end
if [%1] == [--fullversion] goto end
if [%1] == [-F] goto end
shift
goto isVersionOrHelp
:prepareCheck
rem Perform check unless it is specified not to do it
if "%NO_CHECK%" == ""  set NO_CHECK=false
goto isVersionOrHelp
:end
exit /B 0
opendj3/opendj-ldap-sync/src/main/assembly/libbat/setcp.bat
New file
@@ -0,0 +1,40 @@
rem CDDL HEADER START
rem
rem The contents of this file are subject to the terms of the
rem Common Development and Distribution License, Version 1.0 only
rem (the "License").  You may not use this file except in compliance
rem with the License.
rem
rem You can obtain a copy of the license at
rem trunk/opendj3/legal-notices/CDDLv1_0.txt
rem or http://forgerock.org/license/CDDLv1.0.html.
rem See the License for the specific language governing permissions
rem and limitations under the License.
rem
rem When distributing Covered Code, include this CDDL HEADER in each
rem file and include the License file at
rem trunk/opendj3/legal-notices/CDDLv1_0.txt.  If applicable,
rem add the following below this CDDL HEADER, with the fields enclosed
rem by brackets "[]" replaced with your own identifying information:
rem      Portions Copyright [yyyy] [name of copyright owner]
rem
rem CDDL HEADER END
rem
rem
rem      Copyright 2006-2008 Sun Microsystems, Inc.
set CLASSPATHCOMPONENT=%1
if ""%1""=="""" goto gotAllArgs
shift
:argCheck
if ""%1""=="""" goto gotAllArgs
set CLASSPATHCOMPONENT=%CLASSPATHCOMPONENT% %1
shift
goto argCheck
:gotAllArgs
set CLASSPATH=%CLASSPATHCOMPONENT%;%CLASSPATH%
opendj3/opendj-ldap-sync/src/main/assembly/libbin/_client-script.sh
New file
@@ -0,0 +1,65 @@
#!/bin/sh
#
# 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
# trunk/opendj3/legal-notices/CDDLv1_0.txt
# or http://forgerock.org/license/CDDLv1.0.html.
# 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
# trunk/opendj3/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
#
#
#      Copyright 2006-2008 Sun Microsystems, Inc.
# This script is used to invoke various client-side processes.  It should not
# be invoked directly by end users.
if test -z "${OPENDJ_INVOKE_CLASS}"
then
  echo "ERROR:  OPENDJ_INVOKE_CLASS environment variable is not set."
  exit 1
fi
# Capture the current working directory so that we can change to it later.
# Then capture the location of this script and the Directory Server install
# root so that we can use them to create appropriate paths.
WORKING_DIR=`pwd`
cd "`dirname "${0}"`"
SCRIPT_DIR=`pwd`
cd ..
INSTALL_ROOT=`pwd`
export INSTALL_ROOT
cd "${WORKING_DIR}"
# Set environment variables
SCRIPT_UTIL_CMD=set-full-environment
export SCRIPT_UTIL_CMD
.  "${INSTALL_ROOT}/lib/_script-util.sh"
RETURN_CODE=$?
if test ${RETURN_CODE} -ne 0
then
  exit ${RETURN_CODE}
fi
# Launch the appropriate client utility.
"${OPENDJ_JAVA_BIN}" ${OPENDJ_JAVA_ARGS} ${SCRIPT_NAME_ARG} "${OPENDJ_INVOKE_CLASS}" "${@}"
opendj3/opendj-ldap-sync/src/main/assembly/libbin/_script-util.sh
New file
@@ -0,0 +1,130 @@
#!/bin/sh
#
# 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
# trunk/opendj3/legal-notices/CDDLv1_0.txt
# or http://forgerock.org/license/CDDLv1.0.html.
# 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
# trunk/opendj3/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
#
#
#      Copyright 2008-2009 Sun Microsystems, Inc.
#
# function that sets the java home
#
set_java_home_and_args() {
  if test -f "${INSTANCE_ROOT}/lib/set-java-home"
  then
    . "${INSTANCE_ROOT}/lib/set-java-home"
  fi
  if test -z "${OPENDJ_JAVA_BIN}"
  then
    if test -z "${OPENDJ_JAVA_HOME}"
    then
      if test -z "${JAVA_BIN}"
      then
        if test -z "${JAVA_HOME}"
        then
          OPENDJ_JAVA_BIN=`which java 2> /dev/null`
          if test ${?} -eq 0
          then
            export OPENDJ_JAVA_BIN
          else
            echo "Please set OPENDJ_JAVA_HOME to the root of a Java 5 (or later) installation"
            echo "or edit the java.properties file and then run the dsjavaproperties script to"
            echo "specify the Java version to be used"
            exit 1
          fi
        else
          OPENDJ_JAVA_BIN="${JAVA_HOME}/bin/java"
          export OPENDJ_JAVA_BIN
        fi
      else
        OPENDJ_JAVA_BIN="${JAVA_BIN}"
        export OPENDJ_JAVA_BIN
      fi
    else
      OPENDJ_JAVA_BIN="${OPENDJ_JAVA_HOME}/bin/java"
      export OPENDJ_JAVA_BIN
    fi
  fi
}
# Explicitly set the PATH, LD_LIBRARY_PATH, LD_PRELOAD, and other important
# system environment variables for security and compatibility reasons.
set_environment_vars() {
  PATH=/bin:/usr/bin
  LD_LIBRARY_PATH=
  LD_LIBRARY_PATH_32=
  LD_LIBRARY_PATH_64=
  LD_PRELOAD=
  LD_PRELOAD_32=
  LD_PRELOAD_64=
  export PATH LD_LIBRARY_PATH LD_LIBRARY_PATH_32 LD_LIBRARY_PATH_64 \
       LD_PRELOAD LD_PRELOAD_32 LD_PRELOAD_64
  SCRIPT_NAME_ARG=-Dcom.forgerock.opendj.ldap.tools.scriptName=${SCRIPT_NAME}
    export SCRIPT_NAME_ARG
}
# Configure the appropriate CLASSPATH.
set_classpath() {
  CLASSPATH=${INSTANCE_ROOT}/classes
  for JAR in ${INSTALL_ROOT}/lib/*.jar
  do
    CLASSPATH=${CLASSPATH}:${JAR}
  done
  if [ "${INSTALL_ROOT}" != "${INSTANCE_ROOT}" ]
  then
    for JAR in ${INSTANCE_ROOT}/lib/*.jar
    do
      CLASSPATH=${CLASSPATH}:${JAR}
    done
  fi
  export CLASSPATH
}
if test "${INSTALL_ROOT}" = ""
then
  # Capture the current working directory so that we can change to it later.
  # Then capture the location of this script and the Directory Server instance
  # root so that we can use them to create appropriate paths.
  WORKING_DIR=`pwd`
  cd "`dirname "${0}"`"
  cd ..
  INSTALL_ROOT=`pwd`
  cd "${WORKING_DIR}"
fi
if test "${SCRIPT_UTIL_CMD}" = "set-full-environment"
then
  set_java_home_and_args
  set_environment_vars
  set_classpath
elif test "${SCRIPT_UTIL_CMD}" = "set-java-home-and-args"
then
  set_java_home_and_args
elif test "${SCRIPT_UTIL_CMD}" = "set-environment-vars"
then
  set_environment_vars
elif test "${SCRIPT_UTIL_CMD}" = "set-classpath"
then
  set_classpath
fi
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/Main.java
New file
@@ -0,0 +1,54 @@
/*
 * 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
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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
 * trunk/opendj3/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
 *
 *      Copyright 2011 ForgeRock AS
 */
package org.forgerock.opendj.sync;
/**
 * LDAP synchronization application.
 */
public final class Main
{
  /**
   * Application entry point.
   *
   * @param args
   *          Command line arguments.
   */
  public static void main(final String[] args)
  {
    // TODO:
  }
  private Main()
  {
    // Prevent instantiation.
  }
}
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/ChangeRecordContext.java
New file
@@ -0,0 +1,138 @@
/*
 * 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
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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
 * trunk/opendj3/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
 *
 *      Copyright 2011 ForgeRock AS
 */
package org.forgerock.opendj.sync.filters;
import java.util.Date;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.Entries;
import org.forgerock.opendj.ldap.Entry;
/**
 * The context associated with a change record to be filtered. The context
 * provides access to meta data associated with changes as they are processed,
 * including but not limited to:
 * <ul>
 * <li>The change number
 * <li>The CSN, if available
 * <li>The entry's unique ID, if available
 * <li>The name of the user who performed the change, if available
 * </ul>
 */
public final class ChangeRecordContext
{
  private final Entry entry;
  /**
   * Creates a new change record context using the provided change log entry.
   *
   * @param entry
   *          The change log entry.
   */
  ChangeRecordContext(final Entry entry)
  {
    this.entry = Entries.unmodifiableEntry(entry);
  }
  /**
   * Returns the change cookie contained in the change log entry, or
   * {@code null} if it is not present.
   *
   * @return The change cookie contained in the change log entry, or
   *         {@code null} if it is not present.
   */
  public String getChangeCookie()
  {
    // TODO
    return null;
  }
  /**
   * Returns an unmodifiable view of the underlying change log entry.
   *
   * @return An unmodifiable view of the underlying change log entry.
   */
  public Entry getChangeEntry()
  {
    return entry;
  }
  /**
   * Returns the change initiators name contained in the change log entry, or
   * {@code null} if it is not present.
   *
   * @return The change initiators name contained in the change log entry, or
   *         {@code null} if it is not present.
   */
  public DN getChangeInitiatorsName()
  {
    // TODO
    return null;
  }
  /**
   * Returns the change number contained in the change log entry, or {@code -1}
   * if it is not present.
   *
   * @return The change number contained in the change log entry, or {@code -1}
   *         if it is not present.
   */
  public long getChangeNumber()
  {
    // TODO
    return 0L;
  }
  /**
   * Returns the change time contained in the change log entry, or {@code null}
   * if it is not present.
   *
   * @return The change time contained in the change log entry, or {@code null}
   *         if it is not present.
   */
  public Date getChangeTime()
  {
    // TODO
    return null;
  }
}
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Filter.java
New file
@@ -0,0 +1,107 @@
/*
 * 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
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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
 * trunk/opendj3/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
 *
 *      Copyright 2011 ForgeRock AS
 */
package org.forgerock.opendj.sync.filters;
import java.io.Closeable;
import org.forgerock.opendj.ldap.requests.AddRequest;
import org.forgerock.opendj.ldap.requests.DeleteRequest;
import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
/**
 * A change record filter. Transforms may modify the content of the provided
 * change record.
 */
public interface Filter extends Closeable
{
  /**
   * Release any resources associated with this filter. This method is called
   * during application termination.
   */
  @Override
  void close();
  /**
   * Transforms the provided add request.
   *
   * @param context
   *          Additional information associated with the change record.
   * @param change
   *          The add request to be filtered or modified.
   * @return The result of the filter.
   */
  FilterResult filterChangeRecord(ChangeRecordContext context, AddRequest change);
  /**
   * Transforms the provided delete request.
   *
   * @param context
   *          Additional information associated with the change record.
   * @param change
   *          The delete request to be filtered or modified.
   * @return The result of the filter.
   */
  FilterResult filterChangeRecord(ChangeRecordContext context,
      DeleteRequest change);
  /**
   * Transforms the provided modify DN request.
   *
   * @param context
   *          Additional information associated with the change record.
   * @param change
   *          The modify DN request to be filtered or modified.
   * @return The result of the filter.
   */
  FilterResult filterChangeRecord(ChangeRecordContext context,
      ModifyDNRequest change);
  /**
   * Transforms the provided modify request.
   *
   * @param context
   *          Additional information associated with the change record.
   * @param change
   *          The modify request to be filtered or modified.
   * @return The result of the filter.
   */
  FilterResult filterChangeRecord(ChangeRecordContext context,
      ModifyRequest change);
}
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/FilterResult.java
New file
@@ -0,0 +1,267 @@
/*
 * 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
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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
 * trunk/opendj3/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
 *
 *      Copyright 2011 ForgeRock AS
 */
package org.forgerock.opendj.sync.filters;
import org.forgerock.i18n.LocalizableException;
import org.forgerock.i18n.LocalizableMessage;
/**
 * The result of processing a change record in a {@code Filter}.
 */
public final class FilterResult
{
  /**
   * The set of possible actions that a {@code Filter} may return in order to
   * indicate how change record processing should continue.
   */
  public enum Action
  {
    /**
     * Indicates that the change record was processed successfully by the
     * filter, and it should now be processed by any remaining filters.
     */
    NEXT,
    /**
     * Indicates that the change record was processed successfully by the
     * filter, but it should not be processed by any remaining filters.
     */
    STOP,
    /**
     * Indicates that the change record could not be processed by the filter due
     * to a non-fatal error, and it should not be processed by any remaining
     * filters. However, subsequent change records can still be processed.
     */
    FAIL,
    /**
     * Indicates that a fatal error occurred and it will not be possible to
     * process any more change records.
     */
    FATAL;
  }
  /**
   * Returns a filter result whose action is {@link Action#FAIL} and which has
   * the specified cause.
   *
   * @param cause
   *          The exception which caused processing of the change record to
   *          stop.
   * @return A filter result indicating that processing of the change record
   *         should stop due to an error.
   */
  public static FilterResult fail(final Throwable cause)
  {
    return new FilterResult(Action.FAIL, null, cause);
  }
  /**
   * Returns a filter result whose action is {@link Action#FATAL} and which has
   * the specified cause.
   *
   * @param cause
   *          The exception which caused the filter chain to fail.
   * @return A filter result indicating that the filter chain has failed and no
   *         more change records can be processed.
   */
  public static FilterResult fatal(final Throwable cause)
  {
    return new FilterResult(Action.FATAL, null, cause);
  }
  /**
   * Returns a filter result whose action is {@link Action#STOP} and which has
   * no cause or message.
   *
   * @return A filter result indicating that processing of the change record
   *         should stop.
   */
  public static FilterResult stop()
  {
    return stop(null);
  }
  /**
   * Returns a filter result whose action is {@link Action#STOP} and which has
   * the specified message, but no cause.
   *
   * @param message
   *          A message explaining why processing of the change record should
   *          stop.
   * @return A filter result indicating that processing of the change record
   *         should stop.
   */
  public static FilterResult stop(final LocalizableMessage message)
  {
    if (message == null)
    {
      return STOP;
    }
    else
    {
      return new FilterResult(Action.STOP, message, null);
    }
  }
  private final Action action;
  private final LocalizableMessage message;
  private final Throwable cause;
  private static final FilterResult NEXT = new FilterResult(Action.NEXT, null,
      null);
  private static final FilterResult STOP = new FilterResult(Action.STOP, null,
      null);
  /**
   * Returns a filter result whose action is {@link Action#NEXT} and which has
   * no cause or message.
   *
   * @return A filter result indicating that processing of the change record
   *         should continue.
   */
  public static FilterResult next()
  {
    return NEXT;
  }
  private FilterResult(final Action action, final LocalizableMessage message,
      final Throwable cause)
  {
    this.action = action;
    this.cause = cause;
    if (message != null)
    {
      this.message = message;
    }
    else if (cause != null)
    {
      if (cause instanceof LocalizableException)
      {
        this.message = ((LocalizableException) cause).getMessageObject();
      }
      else
      {
        this.message = LocalizableMessage.raw("%s", cause.getMessage());
      }
    }
    else
    {
      this.message = null;
    }
  }
  /**
   * Returns the action associated with this filter result.
   *
   * @return The action associated with this filter result.
   */
  public Action getAction()
  {
    return action;
  }
  /**
   * Returns the exception which caused processing to be stopped.
   *
   * @return The exception which caused processing to be stopped, may be
   *         {@code null}.
   */
  public Throwable getCause()
  {
    return cause;
  }
  /**
   * Returns the optional localizable message describing why processing has
   * stopped.
   *
   * @return The localizable message describing why processing has stopped, may
   *         be {@code null}.
   */
  public LocalizableMessage getMessage()
  {
    return message;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String toString()
  {
    final StringBuilder builder = new StringBuilder();
    builder.append("FilterResult(");
    builder.append(action);
    if (message != null)
    {
      builder.append(',');
      builder.append(message);
    }
    if (cause != null)
    {
      builder.append(',');
      builder.append(cause);
    }
    builder.append(')');
    return builder.toString();
  }
}
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Matchers.java
New file
@@ -0,0 +1,910 @@
/*
 * 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
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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
 * trunk/opendj3/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
 *
 *      Copyright 2011 ForgeRock AS
 */
package org.forgerock.opendj.sync.filters;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.requests.AddRequest;
import org.forgerock.opendj.ldap.requests.DeleteRequest;
import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldif.ChangeRecord;
import org.forgerock.opendj.sync.filters.FilterResult.Action;
/**
 * Factory methods for constructing common types of matching filters. Matchers
 * are logical filters which can be used to construct conditional
 * transformations. Furthermore, matchers implement boolean logic where
 * {@code true} is indicated by the filter action {@link Action#NEXT} and
 * {@code false} is indicated by the filter action {@link Action#STOP}.
 */
public final class Matchers
{
  private static final class AndMatcher implements Filter
  {
    private final Filter[] subFilters;
    private AndMatcher(final Filter[] subFilters)
    {
      this.subFilters = subFilters;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
      for (final Filter filter : subFilters)
      {
        filter.close();
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      for (final Filter subFilter : subFilters)
      {
        final FilterResult result = subFilter.filterChangeRecord(context,
            change);
        if (result.getAction() != Action.NEXT)
        {
          return result;
        }
      }
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      for (final Filter subFilter : subFilters)
      {
        final FilterResult result = subFilter.filterChangeRecord(context,
            change);
        if (result.getAction() != Action.NEXT)
        {
          return result;
        }
      }
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      for (final Filter subFilter : subFilters)
      {
        final FilterResult result = subFilter.filterChangeRecord(context,
            change);
        if (result.getAction() != Action.NEXT)
        {
          return result;
        }
      }
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      for (final Filter subFilter : subFilters)
      {
        final FilterResult result = subFilter.filterChangeRecord(context,
            change);
        if (result.getAction() != Action.NEXT)
        {
          return result;
        }
      }
      return FilterResult.next();
    }
  }
  private static final class ChangeInitiatorInScopeMatcher implements Filter
  {
    private final DN dn;
    private final SearchScope scope;
    private ChangeInitiatorInScopeMatcher(final DN dn, final SearchScope scope)
    {
      this.dn = dn;
      this.scope = scope;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
      // Nothing to do.
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      return matchesScope(change);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      return matchesScope(change);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      return matchesScope(change);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      return matchesScope(change);
    }
    private FilterResult matchesScope(final ChangeRecord change)
    {
      if (change.getName().isInScopeOf(dn, scope))
      {
        return FilterResult.next();
      }
      else
      {
        return FilterResult.stop();
      }
    }
  }
  private static final class ImpliesMatcher implements Filter
  {
    private final Filter condition;
    private final Filter transformation;
    private ImpliesMatcher(final Filter condition, final Filter transformation)
    {
      this.condition = condition;
      this.transformation = transformation;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
      condition.close();
      transformation.close();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      final FilterResult result = condition.filterChangeRecord(context, change);
      if (result.getAction() == Action.NEXT)
      {
        return transformation.filterChangeRecord(context, change);
      }
      else
      {
        return result;
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      final FilterResult result = condition.filterChangeRecord(context, change);
      if (result.getAction() == Action.NEXT)
      {
        return transformation.filterChangeRecord(context, change);
      }
      else
      {
        return result;
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      final FilterResult result = condition.filterChangeRecord(context, change);
      if (result.getAction() == Action.NEXT)
      {
        return transformation.filterChangeRecord(context, change);
      }
      else
      {
        return result;
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      final FilterResult result = condition.filterChangeRecord(context, change);
      if (result.getAction() == Action.NEXT)
      {
        return transformation.filterChangeRecord(context, change);
      }
      else
      {
        return result;
      }
    }
  }
  private static final class NotMatcher implements Filter
  {
    private final Filter subFilter;
    private NotMatcher(final Filter subFilter)
    {
      this.subFilter = subFilter;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
      subFilter.close();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      return transformResult(subFilter.filterChangeRecord(context, change));
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      return transformResult(subFilter.filterChangeRecord(context, change));
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      return transformResult(subFilter.filterChangeRecord(context, change));
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      return transformResult(subFilter.filterChangeRecord(context, change));
    }
    private FilterResult transformResult(final FilterResult result)
    {
      switch (result.getAction())
      {
      case NEXT:
        return FilterResult.stop();
      case STOP:
        return FilterResult.next();
      default:
        return result;
      }
    }
  }
  private static final class OrMatcher implements Filter
  {
    private final Filter[] subFilters;
    private OrMatcher(final Filter[] subFilters)
    {
      this.subFilters = subFilters;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
      for (final Filter filter : subFilters)
      {
        filter.close();
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      for (final Filter subFilter : subFilters)
      {
        final FilterResult result = subFilter.filterChangeRecord(context,
            change);
        if (result.getAction() != Action.STOP)
        {
          return result;
        }
      }
      return FilterResult.stop();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      for (final Filter subFilter : subFilters)
      {
        final FilterResult result = subFilter.filterChangeRecord(context,
            change);
        if (result.getAction() != Action.STOP)
        {
          return result;
        }
      }
      return FilterResult.stop();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      for (final Filter subFilter : subFilters)
      {
        final FilterResult result = subFilter.filterChangeRecord(context,
            change);
        if (result.getAction() != Action.STOP)
        {
          return result;
        }
      }
      return FilterResult.stop();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      for (final Filter subFilter : subFilters)
      {
        final FilterResult result = subFilter.filterChangeRecord(context,
            change);
        if (result.getAction() != Action.STOP)
        {
          return result;
        }
      }
      return FilterResult.stop();
    }
  }
  private static final class TargetInScopeMatcher implements Filter
  {
    private final DN dn;
    private final SearchScope scope;
    private TargetInScopeMatcher(final DN dn, final SearchScope scope)
    {
      this.dn = dn;
      this.scope = scope;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
      // Nothing to do.
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      return matchesScope(change);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      return matchesScope(change);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      return matchesScope(change);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      return matchesScope(change);
    }
    private FilterResult matchesScope(final ChangeRecord change)
    {
      if (change.getName().isInScopeOf(dn, scope))
      {
        return FilterResult.next();
      }
      else
      {
        return FilterResult.stop();
      }
    }
  }
  private static final Filter TRUE = new Filter()
  {
    @Override
    public void close()
    {
      // Nothing to do.
    }
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      return FilterResult.next();
    }
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      return FilterResult.next();
    }
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      return FilterResult.next();
    }
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      return FilterResult.next();
    }
  };
  private static final Filter FALSE = new Filter()
  {
    @Override
    public void close()
    {
      // Nothing to do.
    }
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      return FilterResult.stop();
    }
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      return FilterResult.stop();
    }
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      return FilterResult.stop();
    }
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      return FilterResult.stop();
    }
  };
  /**
   * Returns a matcher which always evaluates to {@code false}.
   *
   * @return A matcher which always evaluates to {@code false}.
   */
  public static Filter alwaysFalse()
  {
    return FALSE;
  }
  /**
   * Returns a matcher which always evaluates to {@code true}.
   *
   * @return A matcher which always evaluates to {@code true}.
   */
  public static Filter alwaysTrue()
  {
    return TRUE;
  }
  /**
   * Returns a matcher which evaluates to {@code true} if and only if all of the
   * provided matchers evaluate to {@code true}. This method evaluates the
   * matchers in the order provided and stops as soon as one evaluates to
   * {@code false}.
   *
   * @param matchers
   *          The matchers whose results must all evaluate to {@code true} in
   *          order for the returned matcher to evaluate to {@code true}.
   * @return A matcher which evaluates to {@code true} if and only if all of the
   *         provided matchers evaluate to {@code true}.
   */
  public static Filter and(final Filter... matchers)
  {
    return new AndMatcher(matchers);
  }
  /**
   * Returns a matcher which will only evaluate a transformation if a condition
   * evaluates to {@code true}. This method can be used to construct conditional
   * if...then... style logic. Note that the returned matcher will evaluate to
   * {@code true} if the condition evaluated to {@code false}.
   *
   * @param condition
   *          The condition matcher which must evaluate to {@code true} in order
   *          for the transformation to be evaluated.
   * @param transformation
   *          The transformation which will only be evaluated if the condition
   *          evaluates to {@code true}.
   * @return A matcher which will only evaluate a transformation if a condition
   *         evaluates to {@code true}.
   */
  public static Filter implies(final Filter condition,
      final Filter transformation)
  {
    return new ImpliesMatcher(condition, transformation);
  }
  /**
   * Returns a matcher which evaluates to {@code true} if and only if the name
   * of the entity which performed the change exactly matches the provided DN.
   *
   * @param dn
   *          The name of the change initiator.
   * @return A matcher which evaluates to {@code true} if and only if the name
   *         of the entity which performed the change exactly matches the
   *         provided DN.
   */
  public static Filter initiatorIsEqualTo(final DN dn)
  {
    return new ChangeInitiatorInScopeMatcher(dn, SearchScope.BASE_OBJECT);
  }
  /**
   * Returns a matcher which evaluates to {@code true} if and only if the name
   * of the entity which performed the change matches the provided base DN and
   * search scope.
   *
   * @param baseDN
   *          The base DN.
   * @param scope
   *          The search scope.
   * @return A matcher which evaluates to {@code true} if and only if the name
   *         of the entity which performed the change matches the provided base
   *         DN and search scope.
   */
  public static Filter initiatorMatchesBaseAndScope(final DN baseDN,
      final SearchScope scope)
  {
    return new ChangeInitiatorInScopeMatcher(baseDN, scope);
  }
  /**
   * Returns a matcher which evaluates to {@code true} if the provided matcher
   * evaluates to {@code false}, and vice versa.
   *
   * @param matcher
   *          The matcher whose result is to be inverted.
   * @return A matcher which evaluates to {@code true} if the provided matcher
   *         evaluates to {@code false}, and vice versa.
   */
  public static Filter not(final Filter matcher)
  {
    return new NotMatcher(matcher);
  }
  /**
   * Returns a matcher which evaluates to {@code false} if and only if all of
   * the provided matchers evaluate to {@code false}. This method evaluates the
   * matchers in the order provided and stops as soon as one evaluates to
   * {@code true}.
   *
   * @param matchers
   *          The matchers whose results must all evaluate to {@code false} in
   *          order for the returned matcher to evaluate to {@code false}.
   * @return A matcher which evaluates to {@code false} if and only if all of
   *         the provided matchers evaluate to {@code false}.
   */
  public static Filter or(final Filter... matchers)
  {
    return new OrMatcher(matchers);
  }
  /**
   * Returns a matcher which evaluates to {@code true} if and only if the name
   * of the entry targeted by the change record matches the provided base DN and
   * search scope.
   *
   * @param baseDN
   *          The base DN.
   * @param scope
   *          The search scope.
   * @return A matcher which evaluates to {@code true} if and only if the name
   *         of the entry targeted by the change record matches the provided
   *         base DN and search scope.
   */
  public static Filter targetMatchesBaseAndScope(final DN baseDN,
      final SearchScope scope)
  {
    return new TargetInScopeMatcher(baseDN, scope);
  }
  private Matchers()
  {
    // Prevent instantiation.
  }
}
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Transforms.java
New file
@@ -0,0 +1,657 @@
/*
 * 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
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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
 * trunk/opendj3/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
 *
 *      Copyright 2011 ForgeRock AS
 */
package org.forgerock.opendj.sync.filters;
import java.io.IOException;
import java.util.Iterator;
import java.util.ListIterator;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.*;
import org.forgerock.opendj.ldap.requests.AddRequest;
import org.forgerock.opendj.ldap.requests.DeleteRequest;
import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldif.ChangeRecordWriter;
/**
 * Factory methods for constructing common types of transformation filters.
 */
public final class Transforms
{
  private static final class AlwaysStopTransform implements Filter
  {
    private final FilterResult result;
    private AlwaysStopTransform(final LocalizableMessage message)
    {
      this.result = FilterResult.stop(message);
    }
    @Override
    public void close()
    {
      // Nothing to do.
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      return result;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      return result;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      return result;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      return result;
    }
  }
  private static final class ChangeRecordWriterTransform implements Filter
  {
    private final ChangeRecordWriter writer;
    private ChangeRecordWriterTransform(final ChangeRecordWriter writer)
    {
      this.writer = writer;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
      try
      {
        writer.close();
      }
      catch (final IOException e)
      {
        // FIXME: this could occur while flushing. Log the error?
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      try
      {
        writer.writeChangeRecord(change);
        return FilterResult.next();
      }
      catch (final IOException e)
      {
        return FilterResult.fatal(e);
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      try
      {
        writer.writeChangeRecord(change);
        return FilterResult.next();
      }
      catch (final IOException e)
      {
        return FilterResult.fatal(e);
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      try
      {
        writer.writeChangeRecord(change);
        return FilterResult.next();
      }
      catch (final IOException e)
      {
        return FilterResult.fatal(e);
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      try
      {
        writer.writeChangeRecord(change);
        return FilterResult.next();
      }
      catch (final IOException e)
      {
        return FilterResult.fatal(e);
      }
    }
  }
  private static final class RemoveAttributeTransform implements Filter
  {
    private final AttributeDescription name;
    private final boolean includeSubtypes;
    private RemoveAttributeTransform(final AttributeDescription name,
        final boolean includeSubtypes)
    {
      this.name = name;
      this.includeSubtypes = includeSubtypes;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
      // Nothing to do.
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      if (includeSubtypes)
      {
        final Iterator<Attribute> i = change.getAllAttributes(name).iterator();
        while (i.hasNext())
        {
          i.next();
          i.remove();
        }
      }
      else
      {
        change.removeAttribute(name);
      }
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      final Iterator<Modification> i = change.getModifications().iterator();
      while (i.hasNext())
      {
        final Modification modification = i.next();
        final Attribute attribute = modification.getAttribute();
        if (includeSubtypes)
        {
          if (attribute.getAttributeDescription().isSubTypeOf(name))
          {
            i.remove();
          }
        }
        else
        {
          if (attribute.getAttributeDescription().equals(name))
          {
            i.remove();
          }
        }
      }
      return FilterResult.next();
    }
  }
  private static final class RenameAttributeTransform implements Filter
  {
    // TODO: do we want to rename attributes in the DN?
    private final AttributeDescription from;
    private final AttributeDescription to;
    private RenameAttributeTransform(final AttributeDescription from,
        final AttributeDescription to)
    {
      this.from = from;
      this.to = to;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
      // Nothing to do.
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      final Attribute attribute = change.getAttribute(from);
      if (attribute != null)
      {
        change.removeAttribute(from);
        change.addAttribute(Attributes.renameAttribute(attribute, to));
      }
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      final ListIterator<Modification> i = change.getModifications()
          .listIterator();
      while (i.hasNext())
      {
        final Modification modification = i.next();
        final Attribute attribute = modification.getAttribute();
        if (attribute.getAttributeDescription().equals(from))
        {
          i.set(new Modification(modification.getModificationType(), Attributes
              .renameAttribute(attribute, to)));
        }
      }
      return FilterResult.next();
    }
  }
  private static final class RenameEntryTransform implements Filter
  {
    private final DN from;
    private final DN to;
    private RenameEntryTransform(final DN from, final DN to)
    {
      this.from = from;
      this.to = to;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
      // Nothing to do.
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final AddRequest change)
    {
      change.setName(change.getName().rename(from, to));
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final DeleteRequest change)
    {
      change.setName(change.getName().rename(from, to));
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyDNRequest change)
    {
      change.setName(change.getName().rename(from, to));
      return FilterResult.next();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public FilterResult filterChangeRecord(final ChangeRecordContext context,
        final ModifyRequest change)
    {
      change.setName(change.getName().rename(from, to));
      return FilterResult.next();
    }
  }
  private static final Filter ALWAYS_STOP = new AlwaysStopTransform(null);
  /**
   * Returns a transformation which always drops changes. This transformation
   * can be combined with matches in order to selectively drop certain changes.
   *
   * @return A transformation which always drops changes.
   */
  public static Filter alwaysStop()
  {
    return ALWAYS_STOP;
  }
  /**
   * Returns a transformation which always drops changes. This transformation
   * can be combined with matches in order to selectively drop certain changes.
   *
   * @param reason
   *          The reason why the change is being dropped.
   * @return A transformation which always drops changes.
   */
  public static Filter alwaysStop(final LocalizableMessage reason)
  {
    return new AlwaysStopTransform(reason);
  }
  /**
   * Returns a transformation which writers change records to the provided
   * writer.
   *
   * @param writer
   *          The change record writer.
   * @return A transformation which writers change records to the provided
   *         writer.
   */
  public static Filter changeRecordWriter(final ChangeRecordWriter writer)
  {
    return new ChangeRecordWriterTransform(writer);
  }
  /**
   * Returns a transformation which will remove the named attribute from Add and
   * Modify operations if it is present. Note that only the named attribute will
   * be removed and not its sub-types.
   *
   * @param name
   *          The name of the attribute to be removed.
   * @return A transformation which will remove the named attribute from Add and
   *         Modify operations if it is present.
   */
  public static Filter removeAttribute(final AttributeDescription name)
  {
    return new RemoveAttributeTransform(name, false);
  }
  /**
   * Returns a transformation which will remove the named attribute and its
   * sub-types from Add and Modify operations if it is present.
   *
   * @param name
   *          The name of the attribute and sub-types to be removed.
   * @return A transformation which will remove the named attribute and its
   *         sub-types from Add and Modify operations if it is present.
   */
  public static Filter removeAttributeAndSubtypes(
      final AttributeDescription name)
  {
    return new RemoveAttributeTransform(name, true);
  }
  /**
   * Returns a transformation which will rename attributes contained in Add and
   * Modify operations.
   *
   * @param from
   *          The name of the attribute to be renamed.
   * @param to
   *          The new name of the renamed attribute.
   * @return A transformation which will rename attributes contained in Add and
   *         Modify operations.
   */
  public static Filter renameAttribute(final AttributeDescription from,
      final AttributeDescription to)
  {
    return new RenameAttributeTransform(from, to);
  }
  /**
   * Returns a transformation which will rename the operation target DN.
   *
   * @param from
   *          The source base DN.
   * @param to
   *          The target base DN.
   * @return A transformation which will rename the operation target DN.
   */
  public static Filter renameEntry(final DN from, final DN to)
  {
    return new RenameEntryTransform(from, to);
  }
  /**
   * Returns a transformation which will delegate transformation to the provided
   * Groovy script.
   *
   * @return A transformation which will delegate transformation to the provided
   *         Groovy script.
   */
  public static Filter transformUsingGroovy()
  {
    // TODO:
    return null;
  }
  private Transforms()
  {
    // Prevent instantiation.
  }
}
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/package-info.java
New file
@@ -0,0 +1,34 @@
/*
 * 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
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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
 * trunk/opendj3/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
 *
 *
 *      Copyright 2011 ForgeRock AS.
 */
/**
 * LDAP synchronization daemon core implementation classes.
 */
package org.forgerock.opendj.sync.filters;
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/package-info.java
New file
@@ -0,0 +1,37 @@
/*
 * 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
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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
 * trunk/opendj3/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
 *
 *
 *      Copyright 2011 ForgeRock AS.
 */
/**
 * An LDAP synchronization daemon which can be used synchronize changes from
 * a source directory to a destination directory. The daemon reads the source
 * directory's change log and forwards changes to the destination directory,
 * while possibly applying filters and transformations.
 */
package org.forgerock.opendj.sync;
opendj3/pom.xml
@@ -95,6 +95,7 @@
    <module>opendj-build-tools</module>
    <module>opendj-ldap-sdk</module>
    <module>opendj-ldap-toolkit</module>
    <module>opendj-ldap-sync</module>
    <module>opendj-ldap-sdk-examples</module>
  </modules>
  <properties>