001package com.pingidentity.ds.plugin;
002
003import com.unboundid.directory.sdk.common.operation.UpdatableAddRequest;
004import com.unboundid.directory.sdk.common.operation.UpdatableAddResult;
005import com.unboundid.directory.sdk.common.types.ActiveOperationContext;
006import com.unboundid.directory.sdk.common.types.UpdatableEntry;
007import com.unboundid.directory.sdk.ds.api.Plugin;
008import com.unboundid.directory.sdk.ds.config.PluginConfig;
009import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
010import com.unboundid.directory.sdk.ds.types.PreParsePluginResult;
011import com.unboundid.ldap.sdk.*;
012import com.unboundid.util.args.*;
013
014import java.util.concurrent.atomic.AtomicLong;
015
016public class UniqueMod7IDGenerator extends Plugin {
017
018    public static final String ARG_NAME_ATTRIBUTE_NAME = "attribute-name";
019    public static final String ARG_NAME_EXTERNAL_SERVER = "external-server";
020    public static final String ARG_NAME_MIN_CX = "min-connections";
021    private static final String ARG_NAME_MAX_CX = "max-connections";
022    private static final String ARG_NAME_SEED = "seed";
023    public static final String ARG_NAME_BASE = "base";
024    public static final String ARG_NAME_SCOPE = "scope";
025    public static final String ARG_NAME_FILTER_ATTRIBUTE = "filter-attribute";
026    public static final String ARG_NAME_MAX_RETRIES = "max-retries";
027
028
029    private String attributeName;
030    private LDAPConnectionPool ldapConnectionPool;
031    private Integer seed;
032    private DN base;
033    private SearchScope scope;
034    private String filterAttr;
035    private AtomicLong id;
036    private Integer maxRetries;
037
038    @Override
039    public String getExtensionName() {
040        return "Unique mod7 UID Generator";
041    }
042
043    @Override
044    public String[] getExtensionDescription() {
045        return new String[] {"generates a unique mod7 uid attribute value"};
046    }
047
048    @Override
049    public void defineConfigArguments(ArgumentParser parser) throws ArgumentException {
050        StringArgument attributeNameArg = new StringArgument(null, ARG_NAME_ATTRIBUTE_NAME,false,1,"{attribute-name}","the name of the attribute (default: uid)","uid");
051        parser.addArgument(attributeNameArg);
052        StringArgument externalServerArgument = new StringArgument(null, ARG_NAME_EXTERNAL_SERVER, false, 1,
053                "{external-server}", "The name of the external server to issue the persistent search request to.");
054        parser.addArgument(externalServerArgument);
055        IntegerArgument minConnections = new IntegerArgument(null, ARG_NAME_MIN_CX,false,1,"{min-connections}","The minimum number of connection to maintain in the pool (default: 1)",1);
056        parser.addArgument(minConnections);
057        IntegerArgument maxConnections = new IntegerArgument(null, ARG_NAME_MAX_CX,false,1,"{max-connections}","The maximum number of connection to maintain in the pool (default: 10)",10);
058        parser.addArgument(maxConnections);
059        IntegerArgument seedArg = new IntegerArgument(null, ARG_NAME_SEED,false,1,"{seed}","The seed to use for generation",89000000);
060        parser.addArgument(seedArg);
061        DNArgument baseArg = new DNArgument(null, ARG_NAME_BASE,false,1,"{base}","The base to issue searches against", DN.NULL_DN);
062        parser.addArgument(baseArg);
063        ScopeArgument scopeArg = new ScopeArgument(null, ARG_NAME_SCOPE,false,"{scope}","The scope to use to locate entries (default: sub)", SearchScope.SUB);
064        parser.addArgument(scopeArg);
065        StringArgument filterArg=new StringArgument(null, ARG_NAME_FILTER_ATTRIBUTE,false,1,"{filter-attribute}","The filter attribute to use to locate entries (default: uid )","uid");
066        parser.addArgument(filterArg);
067        IntegerArgument retriesArg = new IntegerArgument(null, ARG_NAME_MAX_RETRIES,false,1,"{max-retries}","Maximum number of retries when looking up an entry",10);
068        parser.addArgument(retriesArg);
069    }
070
071    @Override
072    public void initializePlugin(DirectoryServerContext serverContext, PluginConfig config, ArgumentParser parser) throws LDAPException {
073        attributeName = parser.getStringArgument(ARG_NAME_ATTRIBUTE_NAME).getValue();
074
075
076        LDAPConnection ldapConnection = serverContext.getLDAPExternalServerConnection(parser.getStringArgument(ARG_NAME_EXTERNAL_SERVER).getValue(), null);
077        Integer minCx = parser.getIntegerArgument(ARG_NAME_MIN_CX).getValue();
078        Integer maxCx = parser.getIntegerArgument(ARG_NAME_MAX_CX).getValue();
079        ldapConnectionPool = new LDAPConnectionPool(ldapConnection,minCx,maxCx);
080        seed= parser.getIntegerArgument(ARG_NAME_SEED).getValue();
081        base = parser.getDNArgument(ARG_NAME_BASE).getValue();
082        scope = parser.getScopeArgument(ARG_NAME_SCOPE).getValue();
083        filterAttr = parser.getStringArgument(ARG_NAME_FILTER_ATTRIBUTE).getValue();
084        id = new AtomicLong(seed);
085        maxRetries = parser.getIntegerArgument(ARG_NAME_MAX_RETRIES).getValue();
086    }
087
088    private synchronized String generateValue(){
089        String result = null;
090        Integer retries = 0;
091        while (retries<maxRetries){
092            try {
093                SearchResult searchResult = ldapConnectionPool.search(base.toString(), scope, filterAttr+"="+id.incrementAndGet(), "1.1");
094                if ( ResultCode.SUCCESS.equals(searchResult.getResultCode()) && searchResult.getEntryCount() == 0 ) {
095                    result = String.format("%d",id.addAndGet(id.get() % 7 ));
096                    break;
097                }
098            } catch (LDAPSearchException e) {
099                retries++;
100            }
101        }
102        return result;
103    }
104
105    @Override
106    public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableAddRequest request, UpdatableAddResult result) {
107        UpdatableEntry entry = request.getEntry();
108        entry.removeAttribute(attributeName);
109        entry.addAttribute(new Attribute( attributeName,generateValue()));
110        return PreParsePluginResult.SUCCESS;
111    }
112}