001package com.pingidentity.sync.destination;
002
003import com.unboundid.directory.sdk.common.types.LogSeverity;
004import com.unboundid.directory.sdk.sync.api.SyncDestination;
005import com.unboundid.directory.sdk.sync.config.SyncDestinationConfig;
006import com.unboundid.directory.sdk.sync.types.EndpointException;
007import com.unboundid.directory.sdk.sync.types.SyncOperation;
008import com.unboundid.directory.sdk.sync.types.SyncServerContext;
009import com.unboundid.ldap.sdk.*;
010import com.unboundid.util.args.*;
011
012import java.text.SimpleDateFormat;
013import java.util.ArrayList;
014import java.util.Date;
015import java.util.List;
016
017public class LDAPWithWriteback extends SyncDestination {
018    private static final String ARG_NAME_EXTERNAL_SERVER = "external-server";
019    public static final String ARG_NAME_MIN_CX = "min-connections";
020    private static final String ARG_NAME_MAX_CX = "max-connections";
021    public static final String ARG_CREATION_ATTRIBUTE_NAME = "creation-attribute-name";
022    public static final String ARG_UPDATE_ATTRIBUTE_NAME = "update-attribute-name";
023    private static final String ATTACHMENT_ID = "connection";
024    private LDAPConnectionPool ldapConnectionPool;
025    private SyncServerContext serverContext;
026    private String creationAttributeName;
027    private String updateAttributeName;
028
029    @Override
030    public String getExtensionName() {
031        return "LDAPWithWriteback";
032    }
033
034    @Override
035    public String[] getExtensionDescription() {
036        return new String[]{"LDAP Destination with write-back to the source"};
037    }
038
039    @Override
040    public void defineConfigArguments(ArgumentParser parser) throws ArgumentException {
041        StringArgument externalServerArg = new StringArgument(null, ARG_NAME_EXTERNAL_SERVER, true, 1,
042                "{external-server}", "The name of the external server to issue requests to.");
043        parser.addArgument(externalServerArg);
044        IntegerArgument minConnectionsArg = new IntegerArgument(null, ARG_NAME_MIN_CX, false, 1, "{min-connections}", "The minimum number of connection to maintain in the pool (default: 1)", 1);
045        parser.addArgument(minConnectionsArg);
046        IntegerArgument maxConnectionsArg = new IntegerArgument(null, ARG_NAME_MAX_CX, false, 1, "{max-connections}", "The maximum number of connection to maintain in the pool (default: 10)", 10);
047        parser.addArgument(maxConnectionsArg);
048        StringArgument creationAttributeNameArg = new StringArgument(null, ARG_CREATION_ATTRIBUTE_NAME, true, 1, "{attribute-name}", "The attribute name to write back to upon successful creation at the destination");
049        creationAttributeNameArg.addValueValidator(new AttributeNameArgumentValueValidator());
050        parser.addArgument(creationAttributeNameArg);
051        StringArgument updateAttributeNameArg = new StringArgument(null, ARG_UPDATE_ATTRIBUTE_NAME, true, 1, "{attribute-name}", "The attribute name to write back to upon successful update at the destination");
052        creationAttributeNameArg.addValueValidator(new AttributeNameArgumentValueValidator());
053        parser.addArgument(updateAttributeNameArg);
054    }
055
056    @Override
057    public void initializeSyncDestination(SyncServerContext serverContext, SyncDestinationConfig config, ArgumentParser parser) throws EndpointException {
058        this.serverContext = serverContext;
059        try {
060            LDAPConnection ldapConnection = serverContext.getLDAPExternalServerConnection(parser.getStringArgument(ARG_NAME_EXTERNAL_SERVER).getValue(), null);
061            Integer minCx = parser.getIntegerArgument(ARG_NAME_MIN_CX).getValue();
062            Integer maxCx = parser.getIntegerArgument(ARG_NAME_MAX_CX).getValue();
063            ldapConnectionPool = new LDAPConnectionPool(ldapConnection, minCx, maxCx);
064            creationAttributeName = parser.getStringArgument(ARG_CREATION_ATTRIBUTE_NAME).getValue();
065            updateAttributeName = parser.getStringArgument(ARG_UPDATE_ATTRIBUTE_NAME).getValue();
066        } catch (LDAPException e) {
067            l(e.getDiagnosticMessage());
068            throw new EndpointException(e);
069        }
070    }
071
072    @Override
073    public String getCurrentEndpointURL() {
074        return null;
075    }
076
077    @Override
078    public void createEntry(Entry entry, SyncOperation syncOperation) throws EndpointException {
079        try {
080            LDAPInterface connection = (LDAPInterface) syncOperation.getAttachment(ATTACHMENT_ID);
081            LDAPResult addResult = ldapConnectionPool.add(entry);
082            if (ResultCode.SUCCESS.equals(addResult.getResultCode()) && connection != null) {
083                Modification modification = new Modification(ModificationType.REPLACE, creationAttributeName, new SimpleDateFormat("yyyyMMdd-HHmmss.SSS").format(new Date()));
084                LDAPResult writebackResult = connection.modify(syncOperation.getSourceEntry().getDN(), modification);
085                l( "Writeback: " + writebackResult.getDiagnosticMessage());
086            }
087        } catch (LDAPException e) {
088            l(e.getDiagnosticMessage());
089            throw new EndpointException(e);
090        }
091    }
092
093    @Override
094    public void modifyEntry(Entry entry, List<Modification> modifications, SyncOperation syncOperation) throws EndpointException {
095        try {
096            LDAPInterface connection = (LDAPInterface) syncOperation.getAttachment(ATTACHMENT_ID);
097            LDAPResult modifyResult = ldapConnectionPool.modify(entry.getDN(), modifications);
098            l(modifyResult.getDiagnosticMessage());
099            if (ResultCode.SUCCESS.equals(modifyResult.getResultCode()) && connection != null) {
100                Modification modification = new Modification(ModificationType.REPLACE, updateAttributeName, new SimpleDateFormat("yyyyMMdd-HHmmss.SSS").format(new Date()));
101                LDAPResult writebackResult = connection.modify(syncOperation.getSourceEntry().getDN(), modification);
102                l("Write-back: " + writebackResult.getDiagnosticMessage());
103            }
104        } catch (LDAPException e) {
105            l(e.getDiagnosticMessage());
106            throw new EndpointException(e);
107        }
108    }
109
110    @Override
111    public void deleteEntry(Entry entry, SyncOperation syncOperation) throws EndpointException {
112        try {
113            LDAPResult deleteResult = ldapConnectionPool.delete(entry.getDN());
114            l(deleteResult.getDiagnosticMessage());
115        } catch (LDAPException e) {
116            l(e.getDiagnosticMessage());
117            throw new EndpointException(e);
118        }
119    }
120
121    @Override
122    public List<Entry> fetchEntry(Entry destEntryMappedFromSrc, SyncOperation syncOperation) throws EndpointException {
123        List<Entry> result = new ArrayList<>();
124        LDAPInterface connection = (LDAPInterface) syncOperation.getAttachment(ATTACHMENT_ID);
125        if (connection != null) {
126            try {
127                SearchResultEntry entry = connection.getEntry(destEntryMappedFromSrc.getDN());
128                if ( entry != null ) {
129                    l("Found entry: " + entry.getDN());
130                    result.add(entry);
131                }
132            } catch (LDAPException e) {
133                l(e.getDiagnosticMessage());
134                throw new EndpointException(e);
135            }
136        }
137        return result;
138    }
139
140    private void l(String s){
141        System.out.println(s);
142        serverContext.logMessage(LogSeverity.INFO, s);
143    }
144}