From 886a64b8c1ddc854958bbac92cc9b76d91d3fe26 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Mon, 05 Dec 2011 17:54:22 +0000
Subject: [PATCH] OPENDJ-370: Implement an example Sun DSEE -> OpenDJ change log based synchronization daemon.
---
opendj3/opendj-ldap-sync/src/main/assembly/libbat/_script-util.bat | 201 +++
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Matchers.java | 910 +++++++++++++++++
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/FilterResult.java | 267 +++++
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/Main.java | 54 +
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/package-info.java | 34
opendj3/opendj-ldap-sync/pom.xml | 127 ++
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Transforms.java | 657 ++++++++++++
opendj3/opendj-ldap-sync/src/main/assembly/libbat/_client-script.bat | 53 +
opendj3/pom.xml | 1
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Filter.java | 107 ++
opendj3/opendj-ldap-sync/src/main/assembly/libbat/setcp.bat | 40
opendj3/opendj-ldap-sync/src/main/assembly/descriptor.xml | 99 +
opendj3/opendj-ldap-sync/README | 14
opendj3/opendj-ldap-sync/src/main/assembly/bat/ldapsync.bat | 33
opendj3/opendj-ldap-sync/src/main/assembly/bin/ldapsync | 37
opendj3/opendj-ldap-sync/src/main/assembly/libbin/_client-script.sh | 65 +
opendj3/opendj-ldap-sync/src/main/assembly/libbin/_script-util.sh | 130 ++
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/ChangeRecordContext.java | 138 ++
opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/package-info.java | 37
19 files changed, 3,004 insertions(+), 0 deletions(-)
diff --git a/opendj3/opendj-ldap-sync/README b/opendj3/opendj-ldap-sync/README
new file mode 100644
index 0000000..c3a63a1
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/README
@@ -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.
diff --git a/opendj3/opendj-ldap-sync/pom.xml b/opendj3/opendj-ldap-sync/pom.xml
new file mode 100644
index 0000000..2065144
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/pom.xml
@@ -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>
diff --git a/opendj3/opendj-ldap-sync/src/main/assembly/bat/ldapsync.bat b/opendj3/opendj-ldap-sync/src/main/assembly/bat/ldapsync.bat
new file mode 100755
index 0000000..0a00d8c
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/assembly/bat/ldapsync.bat
@@ -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" %*
+
diff --git a/opendj3/opendj-ldap-sync/src/main/assembly/bin/ldapsync b/opendj3/opendj-ldap-sync/src/main/assembly/bin/ldapsync
new file mode 100644
index 0000000..86decf3
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/assembly/bin/ldapsync
@@ -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" "${@}"
diff --git a/opendj3/opendj-ldap-sync/src/main/assembly/descriptor.xml b/opendj3/opendj-ldap-sync/src/main/assembly/descriptor.xml
new file mode 100644
index 0000000..638c4eb
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/assembly/descriptor.xml
@@ -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>
diff --git a/opendj3/opendj-ldap-sync/src/main/assembly/libbat/_client-script.bat b/opendj3/opendj-ldap-sync/src/main/assembly/libbat/_client-script.bat
new file mode 100755
index 0000000..8cc2431
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/assembly/libbat/_client-script.bat
@@ -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
+
diff --git a/opendj3/opendj-ldap-sync/src/main/assembly/libbat/_script-util.bat b/opendj3/opendj-ldap-sync/src/main/assembly/libbat/_script-util.bat
new file mode 100755
index 0000000..739a7b0
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/assembly/libbat/_script-util.bat
@@ -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
diff --git a/opendj3/opendj-ldap-sync/src/main/assembly/libbat/setcp.bat b/opendj3/opendj-ldap-sync/src/main/assembly/libbat/setcp.bat
new file mode 100755
index 0000000..4a3fd8f
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/assembly/libbat/setcp.bat
@@ -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%
+
+
diff --git a/opendj3/opendj-ldap-sync/src/main/assembly/libbin/_client-script.sh b/opendj3/opendj-ldap-sync/src/main/assembly/libbin/_client-script.sh
new file mode 100755
index 0000000..c010f3a
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/assembly/libbin/_client-script.sh
@@ -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}" "${@}"
diff --git a/opendj3/opendj-ldap-sync/src/main/assembly/libbin/_script-util.sh b/opendj3/opendj-ldap-sync/src/main/assembly/libbin/_script-util.sh
new file mode 100755
index 0000000..18e27bd
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/assembly/libbin/_script-util.sh
@@ -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
+
diff --git a/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/Main.java b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/Main.java
new file mode 100644
index 0000000..be8363c
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/Main.java
@@ -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.
+ }
+
+}
diff --git a/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/ChangeRecordContext.java b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/ChangeRecordContext.java
new file mode 100644
index 0000000..cef0cdd
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/ChangeRecordContext.java
@@ -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;
+ }
+}
diff --git a/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Filter.java b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Filter.java
new file mode 100644
index 0000000..7d4f4ac
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Filter.java
@@ -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);
+}
diff --git a/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/FilterResult.java b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/FilterResult.java
new file mode 100644
index 0000000..4ae54cb
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/FilterResult.java
@@ -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();
+ }
+
+}
diff --git a/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Matchers.java b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Matchers.java
new file mode 100644
index 0000000..c577365
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Matchers.java
@@ -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.
+ }
+
+}
diff --git a/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Transforms.java b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Transforms.java
new file mode 100644
index 0000000..ad10087
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/Transforms.java
@@ -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.
+ }
+}
diff --git a/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/package-info.java b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/package-info.java
new file mode 100755
index 0000000..0808cb5
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/filters/package-info.java
@@ -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;
+
+
+
diff --git a/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/package-info.java b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/package-info.java
new file mode 100755
index 0000000..363cfc1
--- /dev/null
+++ b/opendj3/opendj-ldap-sync/src/main/java/org/forgerock/opendj/sync/package-info.java
@@ -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;
+
+
+
diff --git a/opendj3/pom.xml b/opendj3/pom.xml
index 1424c85..bfe24ac 100644
--- a/opendj3/pom.xml
+++ b/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>
--
Gitblit v1.10.0