Java tutorial
/* * Copyright (c) 2014 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.evolveum.openicf.lotus; import com.evolveum.openicf.lotus.util.DominoUtils; import com.evolveum.openicf.lotus.util.RegistrationBuilder; import lotus.domino.*; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.identityconnectors.common.logging.Log; import org.identityconnectors.common.security.GuardedString; import org.identityconnectors.framework.common.exceptions.AlreadyExistsException; import org.identityconnectors.framework.common.exceptions.ConnectorException; import org.identityconnectors.framework.common.exceptions.UnknownUidException; import org.identityconnectors.framework.common.objects.*; import org.identityconnectors.framework.common.objects.Name; import org.identityconnectors.framework.common.objects.filter.ContainsFilter; import org.identityconnectors.framework.common.objects.filter.EqualsFilter; import org.identityconnectors.framework.common.objects.filter.Filter; import org.identityconnectors.framework.common.objects.filter.FilterTranslator; import org.identityconnectors.framework.spi.Configuration; import org.identityconnectors.framework.spi.Connector; import org.identityconnectors.framework.spi.ConnectorClass; import org.identityconnectors.framework.spi.PoolableConnector; import org.identityconnectors.framework.spi.operations.*; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.evolveum.openicf.lotus.DominoAccountAttribute.*; import static com.evolveum.openicf.lotus.DominoGroupAttribute.*; import static com.evolveum.openicf.lotus.DominoOperationOption.*; import static com.evolveum.openicf.lotus.util.DominoUtils.*; /** * Documentation: * http://publib.boulder.ibm.com/infocenter/domhelp/v8r0/index.jsp?topic=%2Fcom.ibm.designer.domino.main.doc%2FH_JAVA_NOTES_CLASSES_JAVA.html */ @ConnectorClass(displayNameKey = "UI_CONNECTOR_NAME", configurationClass = DominoConfiguration.class) public class DominoConnector implements PoolableConnector, CreateOp, SchemaOp, TestOp, DeleteOp, UpdateAttributeValuesOp, SearchOp<String> { private static final Log LOG = Log.getLog(DominoConnector.class); private static enum Update { ADD, REMOVE, REPLACE } private static final String PREFIX_ROAMING = "roaming/"; private static final String PREFIX_MAIL = "mail\\"; private static final String RENAME_NO_CHANGE = "*"; private static final String NEW_HOME_SERVER_MAIL_PATH = "mail"; private static final Pattern GET_QUERY; static { GET_QUERY = Pattern.compile("\\(NoteID=\"([a-zA-Z0-9]+)\"\\)"); } private DominoConfiguration config; private DominoConnection connection; public DominoConfiguration getConfiguration() { return config; } public void checkAlive() { LOG.info("checkAlive::start"); if (connection != null) { LOG.ok("Checking if domino connection is alive."); connection.checkAlive(); } else { LOG.ok("Creating new domino connection."); connection = new DominoConnection(this.config); } LOG.info("checkAlive::finish"); } public void init(Configuration config) { LOG.info("init::start"); Validate.notNull(config, "Configuration must not be null."); Validate.isTrue(config instanceof DominoConfiguration, "Configuration must be instance of '" + DominoConfiguration.class.getName() + "', but it's instance of '" + config.getClass().getName() + "'."); this.config = (DominoConfiguration) config; this.connection = new DominoConnection(this.config); LOG.info("init::finish"); } public void dispose() { LOG.info("dispose::start"); if (connection != null) { connection.dispose(); } LOG.info("dispose::finish"); } public void test() { LOG.info("test::start"); config.validate(); connection.checkAlive(); LOG.info("test::finish"); } public Schema schema() { LOG.info("schema::start"); SchemaBuilder schema = new SchemaBuilder(DominoConnector.class); //account Set<AttributeInfo> attributes = createAttributes(DominoAccountAttribute.class); schema.defineObjectClass(ObjectClass.ACCOUNT_NAME, attributes); //group attributes = createAttributes(DominoGroupAttribute.class); ObjectClassInfoBuilder objectClassInfo = new ObjectClassInfoBuilder(); objectClassInfo.setType(ObjectClass.GROUP_NAME); objectClassInfo.addAllAttributeInfo(attributes); ObjectClassInfo group = objectClassInfo.build(); schema.defineObjectClass(group); for (DominoOperationOption option : DominoOperationOption.values()) { schema.defineOperationOption(option.getInfo()); } schema.clearSupportedOptionsByOperation(); schema.addSupportedOperationOption(CreateOp.class, DominoOperationOption.SYNCH_INTERNET_PASSWORD.getInfo()); schema.addSupportedOperationOption(CreateOp.class, DominoOperationOption.MAIL_OWNER_ACCESS.getInfo()); schema.addSupportedOperationOption(DeleteOp.class, DominoOperationOption.MAIL_FILE_ACTION.getInfo()); schema.addSupportedOperationOption(DeleteOp.class, DominoOperationOption.DELETE_WINDOWS_USER.getInfo()); Schema retVal = schema.build(); LOG.info("schema::finish"); return retVal; } private Set<AttributeInfo> createAttributes(Class<? extends DominoAttribute> type) { Set<AttributeInfo> infos = new HashSet<AttributeInfo>(); for (DominoAttribute attr : type.getEnumConstants()) { if (attr.getAttribute() != null) { infos.add(attr.getAttribute()); } else { infos.add(AttributeInfoBuilder.build(attr.getName(), attr.getType(), attr.getFlags())); } } return infos; } public FilterTranslator<String> createFilterTranslator(ObjectClass oclass, OperationOptions options) { LOG.info("createFilterTranslator::start"); LOG.ok("Parameters: oc: {0}, op: {1}", oclass, options); DominoFilterTranslator translator = new DominoFilterTranslator(connection, config, oclass); LOG.info("createFilterTranslator::finish"); return translator; } public void executeQuery(ObjectClass oclass, String query, ResultsHandler handler, OperationOptions options) { LOG.info("executeQuery::start"); LOG.ok("Parameters: oc: {0}, q: {1}, op: {2}", oclass, query, options); Validate.notNull(oclass, "Object class must not be null."); Validate.notNull(handler, "Results handler must not be null."); String realQuery = createRealQuery(oclass, query); try { Database userDatabase = connection.getUserDatabase(); Matcher matcher = null; if (query != null) { matcher = GET_QUERY.matcher(query); } if (query != null && matcher.matches()) { try { Document document = userDatabase.getDocumentByUNID(matcher.group(1)); Set<String> attributes = createAttributesToGet(oclass, options); ConnectorObject object = createConnectorObject(document, oclass, attributes); handler.handle(object); LOG.info("Search returned 1 object (get document by UNID)."); } catch (NotesException ex) { if (NotesError.NOTES_ERR_BAD_UNID != ex.id) { throw ex; } } } else { DocumentCollection collection = userDatabase.search(realQuery); Document document = collection.getFirstDocument(); int count = 0; Set<String> attributes = createAttributesToGet(oclass, options); while (document != null) { count++; ConnectorObject object = createConnectorObject(document, oclass, attributes); if (!handler.handle(object)) { break; } document = collection.getNextDocument(); } LOG.info("Search returned {0} objects.", count); } } catch (NotesException ex) { handleException(ex, "Couldn't execute query", LOG); } LOG.info("executeQuery::finish"); } private String createRealQuery(ObjectClass oclass, String query) { StringBuilder sb = new StringBuilder(); String form; if (ObjectClass.ACCOUNT.equals(oclass)) { form = DominoConstants.FORM_PERSON; } else if (ObjectClass.GROUP.equals(oclass)) { form = DominoConstants.FORM_GROUP; } else { throw new ConnectorException("Unknown object class '" + oclass + "'."); } sb.append("(form='").append(form).append("')"); if (StringUtils.isNotEmpty(query)) { sb.append("&").append(query); } return sb.toString(); } /** * @param document represents real object on Domino (target system) * @param oclass connector object type (account, group, etc.) * @param attrToGet attributes to be returned in {@link org.identityconnectors.framework.common.objects.ConnectorObject} * @return * @throws lotus.domino.NotesException */ private ConnectorObject createConnectorObject(Document document, ObjectClass oclass, Set<String> attrToGet) throws NotesException { if (document == null) { return null; } ConnectorObjectBuilder object = new ConnectorObjectBuilder(); String fullNameValue = null; for (Item item : (Vector<Item>) document.getItems()) { String name = item.getName(); if (!attrToGet.contains(name) && !isNameAttribute(oclass, name)) { // unknown attribute or API is not asking for this attribute continue; } List<Object> values = createAttributeValues(item); if (isNameAttribute(oclass, name)) { String objectName = fullNameValue = getFirstValueString(values); if (ObjectClass.ACCOUNT.equals(oclass)) { if (objectName != null) { objectName = getAbbreviated(connection, objectName); Attribute attr = build(CERTIFIER_ORG_HIERARCHY, getOrgFromName(connection, objectName)); object.addAttribute(attr); attr = build(ORG_UNIT, getOrgUnit(connection, objectName)); object.addAttribute(attr); } else { objectName = document.getItemValueString(LAST_NAME.getName()); } } else if (ObjectClass.GROUP.equals(oclass) && objectName != null) { object.addAttribute(build(DISPLAY_NAME, objectName)); objectName = getGroupFullName(item.getValues()); values.clear(); values.add(objectName); object.setUid(objectName); } object.setName(objectName); } if (values.isEmpty()) { continue; } //handle groups and members if (ObjectClass.ACCOUNT.equals(oclass)) { if (MAIL_FILE.getName().equals(name) && (isAttrToGet(attrToGet, MAIL_QUOTA_SIZE_LIMIT) || isAttrToGet(attrToGet, MAIL_QUOTA_WARNING_THRESHOLD))) { String mailDbName = values.size() > 0 ? item.getValueString() : null; addMailQuotaAttributes(object, mailDbName, attrToGet); } } else if (ObjectClass.GROUP.equals(oclass)) { if (MEMBERS.getName().equals(name) && (isAttrToGet(attrToGet, MEMBER_GROUPS) || isAttrToGet(attrToGet, MEMBER_PEOPLE))) { //handle group members addGroupMemberPeople(object, values, attrToGet); } } if (isAttrToGet(attrToGet, name)) { //simply add attribute to connector object DominoAccountAttribute accAttr = DominoAccountAttribute.getAttribute(name); if (GuardedString.class.equals(accAttr.getType())) { String guarded = (String) values.get(0); object.addAttribute(AttributeBuilder.build(name, new GuardedString(guarded.toCharArray()))); } else { object.addAttribute(AttributeBuilder.build(name, values)); } } } String uid = getGuid(document.getUniversalID()); if (ObjectClass.ACCOUNT.equals(oclass)) { object.setUid(uid); Item chkItem = document.getFirstItem(CHECK_PASSWORD.getName()); boolean enabled = chkItem == null || !Integer.toString(AdministrationProcess.PWD_CHK_LOCKOUT).equals(chkItem.getText()); object.addAttribute(AttributeBuilder.buildEnabled(enabled)); if (isAttrToGet(attrToGet, GROUP_LIST) && fullNameValue != null) { addUsersToGroupList(object, fullNameValue); } } else if (ObjectClass.GROUP.equals(oclass)) { object.addAttribute(build(DominoGroupAttribute.OBJECT_GUID, uid)); } if (document.getLastModified() != null) { DominoAttribute attr = ObjectClass.ACCOUNT.equals(oclass) ? DominoAccountAttribute.LAST_MODIFIED : DominoGroupAttribute.LAST_MODIFIED; object.addAttribute(AttributeBuilder.build(attr.getName(), Long.valueOf(document.getLastModified().toJavaDate().getTime()))); } return object.build(); } private void addUsersToGroupList(ConnectorObjectBuilder object, String fullName) throws NotesException { List<String> groups = getGroupList(fullName); AttributeBuilder attr = new AttributeBuilder(); attr.setName(GROUP_LIST.getName()); for (String group : groups) { String displayName = getGroupDisplayName(group); if (isDenyGroup(displayName)) { object.addAttribute(new Attribute[] { AttributeBuilder.buildEnabled(false) }); } else { attr.addValue(displayName); } } if (attr.getValue() == null || attr.getValue().isEmpty()) { return; } object.addAttribute(attr.build()); } private boolean isDenyGroup(String displayName) throws NotesException { DocumentCollection collection = null; try { EqualsFilter filter = new EqualsFilter(build(LIST_NAME, displayName)); collection = getDocumentCollection(DominoConstants.FORM_GROUP, filter); Document group = collection.getFirstDocument(); if (group != null) { String value = group.getItemValueString(GROUP_TYPE.getName()); recycleQuietly(group); if ("3".equals(value)) { return true; } } } finally { recycleQuietly(collection); } return false; } private List<String> getGroupList(String fullName) throws NotesException { List<String> groups = new ArrayList<String>(); ContainsFilter filter = new ContainsFilter(build(MEMBERS, fullName)); DocumentCollection collection = null; try { collection = getDocumentCollection(DominoConstants.FORM_GROUP, filter); Document document = collection.getFirstDocument(); while (document != null) { groups.add(document.getItemValueString(LIST_NAME.getName())); recycleQuietly(document); document = collection.getNextDocument(); } } finally { recycleQuietly(collection); } return groups; } private String getGroupFullName(List<String> values) { if (values == null) { return null; } return StringUtils.join(values, ";"); } private void addMailQuotaAttributes(ConnectorObjectBuilder object, String mailDbname, Set<String> attrToGet) throws NotesException { LOG.info("Adding mail quota attributes for mail db {0}.", mailDbname); Session session = connection.getSession(); Database db = null; try { db = session.getDatabase(null, mailDbname, false); if (db == null) { return; } if (isAttrToGet(attrToGet, MAIL_QUOTA_SIZE_LIMIT)) { object.addAttribute(build(MAIL_QUOTA_SIZE_LIMIT, Integer.valueOf(db.getSizeQuota()))); } if (isAttrToGet(attrToGet, MAIL_QUOTA_WARNING_THRESHOLD)) { Number size = db.getSizeWarning(); object.addAttribute(build(MAIL_QUOTA_WARNING_THRESHOLD, size.intValue())); } } catch (NotesException ex) { if (ex.id == NotesError.NOTES_ERR_DBNOACCESS) { LOG.error("User {0} doesn't have rights to access DB quota limits for {1}, reason: {2}", config.getAdminName(), mailDbname, getExceptionMessage(ex)); return; } LOG.error(ex, "Couldn't get mail quota attributes for user, reason: {0}", getExceptionMessage(ex)); throw ex; } finally { recycleQuietly(db); } } private void addGroupMemberPeople(ConnectorObjectBuilder object, List<Object> values, Set<String> attrToGet) throws NotesException { List<String> groups = new ArrayList<String>(); List<String> peoples = new ArrayList<String>(); for (Object value : values) { String fullName = getCanonical(connection, value.toString()); if (isAttrToGet(attrToGet, MEMBER_GROUPS) && checkIfGroupExists(fullName)) { groups.add(fullName); } if (isAttrToGet(attrToGet, MEMBER_PEOPLE) && checkIfUserExist(fullName)) { peoples.add(fullName); } } if (isAttrToGet(attrToGet, MEMBER_GROUPS)) { object.addAttribute(build(MEMBER_GROUPS, groups.toArray())); } if (isAttrToGet(attrToGet, MEMBER_PEOPLE)) { object.addAttribute(build(MEMBER_PEOPLE, peoples.toArray())); } } private List<Object> createAttributeValues(Item item) throws NotesException { List<Object> values = new ArrayList<Object>(); String name = item.getName(); for (Object value : item.getValues()) { if (PASSWORD_CHANGE_INTERVAL.getName().equals(name) || PASSWORD_GRACE_PERIOD.getName().equals(name) || ROAM_CLEAN_PER.getName().equals(name)) { values.add(((Double) value).intValue()); } else if (ROAM_CLEAN_SETTING.getName().equals(name)) { values.add(Integer.valueOf((String) value)); } else if (MAIL_SERVER.getName().equals(name) || MEMBERS.getName().equals(name)) { String abbreviated = DominoUtils.getAbbreviated(connection, (String) value); values.add(abbreviated); } else if (value instanceof DateTime) { //translating to long (time in millis) DateTime dateTime = (DateTime) value; values.add(dateTime.toJavaDate().getTime()); } else if (value instanceof Number) { values.add(value); } else if (value != null) { values.add(value.toString()); } else { values.add(null); } } return values; } private static boolean isNameAttribute(ObjectClass oclass, String name) { if (oclass == null || name == null) { return false; } if (ObjectClass.ACCOUNT.equals(oclass) && DominoAccountAttribute.FULL_NAME.getName().equals(name)) { return true; } if (ObjectClass.GROUP.equals(oclass) && DominoGroupAttribute.LIST_NAME.getName().equals(name)) { return true; } return false; } public Uid create(ObjectClass oclass, Set<Attribute> attrs, OperationOptions options) { LOG.info("create::start"); LOG.ok("Parameters: oc: {0}, a: {1}, op: {2}", oclass, attrs, options); Validate.notNull(oclass, "Object class must not be null."); Validate.notNull(attrs, "Attributes must not be null."); Uid uid; try { Map<String, Attribute> attributes = new HashMap<String, Attribute>(AttributeUtil.toMap(attrs)); if (ObjectClass.ACCOUNT.equals(oclass)) { uid = createAccount(attributes, options); } else if (ObjectClass.GROUP.equals(oclass)) { uid = createGroup(attributes, options); } else { LOG.ok("Unknown object class '{0}'.", oclass); throw new IllegalArgumentException("Unknown object class '" + oclass + "'."); } } catch (NotesException ex) { handleException(ex, "Couldn't create " + oclass.getObjectClassValue(), LOG); return null; } LOG.info("create::finish"); return uid; } private Uid createAccount(Map<String, Attribute> attrs, OperationOptions options) throws NotesException { LOG.ok("Creating account."); Name fullNameAttr = (Name) attrs.remove(Name.NAME); String fullNameNormalized = normalizeSpaces(fullNameAttr.getNameValue()); String fullName = getCanonical(connection, fullNameNormalized); LOG.ok("Full name {0}, checking if user exists.", fullName); if (checkIfUserExist(fullName)) { throw new AlreadyExistsException("User '" + fullName + "' already exists."); } String firstName = getAttributeValue(attrs, FIRST_NAME); String middleInitial = getAttributeValue(attrs, MIDDLE_INITIAL); String lastName = getAttributeValue(attrs, LAST_NAME); String idFile = getAttributeValue(attrs, ID_FILE); String mailFile = getAttributeValue(attrs, MAIL_FILE); if (StringUtils.isEmpty(mailFile)) { StringBuilder sb = new StringBuilder(); sb.append(PREFIX_MAIL); sb.append(StringUtils.isNotEmpty(firstName) ? firstName.toLowerCase() : ""); sb.append(StringUtils.isNotEmpty(lastName) ? lastName.toLowerCase() : ""); mailFile = sb.toString(); } String mailServer = getAttributeValue(attrs, MAIL_SERVER, String.class, config.getMailServer()); String forwardingAddress = getAttributeValue(attrs, FORWARDING_ADDRESS); String location = getAttributeValue(attrs, LOCATION); String comment = getAttributeValue(attrs, COMMENT); String certPw = decode(getAttributeValue(attrs, CREDENTIALS, GuardedString.class)); if (StringUtils.isEmpty(certPw)) { certPw = decode(config.getCertifierPassword()); } String userPw = decode(getAttributeValue(attrs, PASSWORD, GuardedString.class)); String orgUnit = getAttributeValue(attrs, ORG_UNIT); String mailTemplate = getAttributeValue(attrs, MAIL_TEMPLATE_NAME, String.class, config.getMailTemplateName()); Integer mailQuotaSize = getAttributeValue(attrs, MAIL_QUOTA_SIZE_LIMIT, Integer.class); Integer mailQuotaWThreshold = getAttributeValue(attrs, MAIL_QUOTA_WARNING_THRESHOLD, Integer.class); //roaming String roamRplSrvrs = getAttributeValue(attrs, ROAM_RPL_SRVRS); if (StringUtils.isEmpty(roamRplSrvrs) && StringUtils.isNotEmpty(config.getRoamRplSrvrs())) { Attribute roamRplSrvrsAttr = build(ROAM_RPL_SRVRS, config.getRoamRplSrvrs()); attrs.put(ROAM_RPL_SRVRS.getName(), roamRplSrvrsAttr); } String certifierOrgHierarchy = getAttributeValue(attrs, CERTIFIER_ORG_HIERARCHY); String altNameLang = getAttributeValue(attrs, ALT_FULL_NAME_LANGUAGE); String altName = getAttributeValue(attrs, ALT_FULL_NAME); if (StringUtils.isNotEmpty(altName)) { altName = getCanonical(connection, altName); } Registration registration = null; try { LOG.ok("Creating registration."); registration = createAndSetupRegistration(attrs, options, firstName, lastName, orgUnit, mailTemplate, mailQuotaSize, mailQuotaWThreshold, certPw); fullName = createFullName(connection, firstName, middleInitial, lastName, orgUnit, certifierOrgHierarchy); boolean added; if (config.getCreateMailDbInBackground() != null && config.getCreateMailDbInBackground()) { registration.setCreateMailDb(false); added = registration.registerNewUser(lastName, idFile, mailServer, firstName, middleInitial, certPw, location, comment, mailFile, forwardingAddress, userPw, altName, altNameLang); createMailDbInBackground(fullName, mailServer, mailFile, mailTemplate, certifierOrgHierarchy, mailQuotaSize, mailQuotaWThreshold); } else { added = registration.registerNewUser(lastName, idFile, mailServer, firstName, middleInitial, certPw, location, comment, mailFile, forwardingAddress, userPw, altName, altNameLang); } if (!added) { throw new ConnectorException("Couldn't create user '" + fullName + "'."); } return updateAccount(new Name(fullName), attrs); } finally { recycleQuietly(registration); } } private Registration createAndSetupRegistration(Map<String, Attribute> attrs, OperationOptions options, String firstName, String lastName, String orgUnit, String mailTemplate, Integer mailQuotaSize, Integer mailQuotaWThreshold, String certPw) throws NotesException { Vector<String> shortNameVector = getAttributeValue(attrs, SHORT_NAME, Vector.class, null, false); String shortName = null; if (shortNameVector != null && !shortNameVector.isEmpty()) { shortName = shortNameVector.get(0); } String policy = getAttributeValue(attrs, POLICY, String.class, config.getPolicy()); Integer defaultPasswordExp = getAttributeValue(attrs, DEFAULT_PASSWORD_EXP, Integer.class); Integer days = getDays(getAttributeValue(attrs, END_DATE, Long.class)); if (defaultPasswordExp == null) { if (days != null && days > 0L) { defaultPasswordExp = days; } else { defaultPasswordExp = config.getDefaultPasswordExp(); } } Vector altOrgUnit = getAttributeValue(attrs, ALT_ORG_UNIT, Vector.class); Vector mailReplicaServers = getAttributeValue(attrs, ROAM_RPL_SRVRS, Vector.class); Boolean northAmerican = getAttributeValue(attrs, NORTH_AMERICAN, Boolean.class, config.getNorthAmerican()); String certifierIdFile = getAttributeValue(attrs, CERTIFIER_ID_FILE, String.class, config.getCertifierIdFile()); String caCertifier = getAttributeValue(attrs, CA_CERTIFIER, String.class, config.getCaCertifierName()); if (config.getUseCAProcess() != null && config.getUseCAProcess()) { if (StringUtils.isEmpty(caCertifier)) { throw new ConnectorException( "Using CA process, but CA certifier name not defined (caCertifier attribute)."); } } else { if (StringUtils.isEmpty(certifierIdFile)) { throw new ConnectorException("Certifier ID file not defined."); } if (StringUtils.isEmpty(certPw)) { throw new ConnectorException("Cert. password (credentials) attribute not defined."); } } //roaming String roamSrvr = getAttributeValue(attrs, ROAM_SRVR, String.class, config.getRoamSrvr()); Integer roamCleanSetting = getAttributeValue(attrs, ROAM_CLEAN_SETTING, Integer.class, config.getRoamCleanSetting()); Integer roamCleanPer = getAttributeValue(attrs, ROAM_CLEAN_PER, Integer.class, config.getRoamCleanPer()); String roamSubDir = getAttributeValue(attrs, ROAM_SUBDIR, String.class, PREFIX_ROAMING + firstName + lastName); //groups validation Vector groups = getAttributeValue(attrs, GROUP_LIST, Vector.class); checkIfGroupsExist(groups); String internetAddress = getAttributeValue(attrs, INTERNET_ADDRESS); Boolean synchInternetPassword = getOperationOptionValue(options, SYNCH_INTERNET_PASSWORD, null); Integer mailOwnerAccess = getOperationOptionValue(options, MAIL_OWNER_ACCESS, config.getMailOwnerAccess()); LOG.ok("Creating registration."); Registration registration = connection.getSession().createRegistration(); RegistrationBuilder builder = new RegistrationBuilder(registration); builder.setCertifierName(caCertifier); builder.setPolicyName(policy); builder.setShortName(shortName); builder.setOrgUnit(orgUnit); builder.setAltOrgUnit(altOrgUnit); builder.setCertifierIDFile(certifierIdFile); builder.setMailTemplateName(mailTemplate); builder.setMailQuotaSizeLimit(mailQuotaSize); builder.setMailQuotaWarningThreshold(mailQuotaWThreshold); builder.setGroupList(groups); builder.setRoamingServer(roamSrvr); builder.setRoamingCleanupSetting(roamCleanSetting); builder.setRoamingCleanupPeriod(roamCleanPer); builder.setRoamingSubdir(roamSubDir); builder.setMailInternetAddress(internetAddress); builder.setSynchInternetPassword(synchInternetPassword); builder.setMailOwnerAccess(mailOwnerAccess); builder.setMailReplicaServers(mailReplicaServers); builder.setNorthAmerican(northAmerican); builder.setRegistrationLog(config.getRegistrationLog()); builder.setStoreIDInAddressBook(config.getStoreIDInAddressBook()); builder.setStoreIDInMailfile(config.getStoreIDInMailfile()); builder.setIDType(config.getRealIdType()); builder.setMailSystem(config.getMailSystem()); builder.setCreateMailDb(config.getCreateMailDb()); builder.setMinPasswordLength(config.getMinPasswordLength()); builder.setUpdateAddressBook(true); if (StringUtils.isNotEmpty(config.getMailACLManager())) { builder.setMailACLManager(config.getMailACLManager()); } builder.setMailACLManager("LocalDomainAdmins"); if (config.getCreateIdFile() != null && !config.getCreateIdFile()) { builder.setNoIDFile(true); builder.setCertifierName(config.getAdminName()); } DateTime expiration = connection.getSession().createDateTime("Today"); expiration.setNow(); expiration.adjustDay(defaultPasswordExp); builder.setExpiration(expiration); return registration; } private void checkIfGroupsExist(Vector<String> groups) throws NotesException { if (groups == null) { return; } for (String group : groups) { if (!checkIfGroupExists(group)) { throw new ConnectorException("Group '" + group + "' doesn't exists."); } } } private Document getUserByName(String name) throws NotesException { EqualsFilter filter = new EqualsFilter(new Name(name)); DocumentCollection collection = getDocumentCollection(DominoConstants.FORM_PERSON, filter); return collection != null ? collection.getFirstDocument() : null; } private Document getUserByUid(String uid) throws NotesException { return connection.getUserDatabase().getDocumentByUNID(uid); } private Document getGroup(String listName) throws NotesException { EqualsFilter filter = new EqualsFilter(build(LIST_NAME, listName)); DocumentCollection collection = getDocumentCollection(DominoConstants.FORM_GROUP, filter); return collection != null ? collection.getFirstDocument() : null; } private boolean checkIfGroupExists(String listName) throws NotesException { return getGroup(listName) != null; } private boolean checkIfUserExist(String fullName) throws NotesException { DocumentCollection collection = null; try { collection = getDocumentCollection(DominoConstants.FORM_PERSON, new EqualsFilter(new Name(fullName))); return collection != null && collection.getFirstDocument() != null; } finally { recycleQuietly(collection); } } private DocumentCollection getDocumentCollection(String form, Filter filter) throws NotesException { ObjectClass oclass = DominoConstants.FORM_PERSON.equals(form) ? ObjectClass.ACCOUNT : ObjectClass.GROUP; DominoFilterTranslator translator = new DominoFilterTranslator(connection, config, oclass); List<String> queries = translator.translate(filter); String query = queries.size() > 0 ? queries.get(0) : null; StringBuilder sb = new StringBuilder(); // returns value of specified field. @GetField("form")="Person" - "form" field value must be // equal to "Person" if we're looking for users. sb.append("(@GetField(\"form\") = \"").append(form).append("\")"); if (StringUtils.isNotEmpty(query)) { sb.append("&").append(query); } return connection.getUserDatabase().search(sb.toString()); } private void createMailDbInBackground(String fullName, String mailServer, String mailFile, String mailTemplate, String certifierOrgHierarchy, Integer mailQuotaSize, Integer mailQuotaWThreshold) { LOG.ok("Creating mail db in background for '{0}'", fullName); try { String adminNameCanonical = getCanonical(connection, config.getAdminName()); Session session = connection.getSession(); Database adminP = session.getDatabase(config.getRegistrationServer(), "admin4.nsf", false); Document request = adminP.createDocument(); request.appendItemValue("Form", "AdminRequest"); request.appendItemValue("FullName", adminNameCanonical); request.appendItemValue("ProxyAction", "24"); //create mail file request.appendItemValue("ProxyAuthor", adminNameCanonical); request.appendItemValue("ProxyCreateFullTextIndex", "0"); request.appendItemValue("ProxyDatabasePath", mailFile); request.appendItemValue("ProxyMailfileAccessLevel", "2"); request.appendItemValue("ProxyNameList", fullName); request.appendItemValue("ProxyOriginatingAuthor", adminNameCanonical); String originatingOrg = certifierOrgHierarchy != null ? certifierOrgHierarchy.replace("/", "") : null; request.appendItemValue("ProxyOriginatingOrganization", originatingOrg); request.appendItemValue("ProxyOverrideDefaultDatastore", "0"); request.appendItemValue("ProxyProcess", "Adminp"); String mailServerCanonical = getCanonical(connection, mailServer); request.appendItemValue("ProxyServer", mailServerCanonical); request.appendItemValue("ProxySourceServer", mailServerCanonical); if (mailTemplate == null) { mailTemplate = "mail85.ntf"; //default mail template } request.appendItemValue("ProxyTextItem1", mailTemplate); if (mailQuotaSize != null) { request.appendItemValue("ProxyNumItem1", mailQuotaSize); } if (mailQuotaWThreshold != null) { request.appendItemValue("ProxyNumItem2", mailQuotaWThreshold); } request.appendItemValue("Type", "AdminRequest"); Vector<Item> items = request.getItems(); for (Item item : items) { item.setSigned(true); } request.sign(); request.save(); } catch (NotesException ex) { handleException(ex, "Couldn't create mail db in background for user '" + fullName + "'", LOG); } } private Uid createGroup(Map<String, Attribute> attributes, OperationOptions options) throws NotesException { Name listNameAttribute = (Name) attributes.remove(Name.NAME); Vector members = getAttributeValue(attributes, MEMBERS, Vector.class); Vector memberGroups = getAttributeValue(attributes, MEMBER_GROUPS, Vector.class); Vector memberPeople = getAttributeValue(attributes, MEMBER_PEOPLE, Vector.class); attributes.remove(DISPLAY_NAME.getName()); if (listNameAttribute == null) { throw new ConnectorException("Missing attribute '" + Name.NAME + "'."); } String[] listNameArray = listNameAttribute.getNameValue().split(";"); Vector listName = new Vector(Arrays.asList(listNameArray)); String mainName = getGroupDisplayName(listNameAttribute.getNameValue()); if (checkIfGroupExists(mainName)) { LOG.ok("Group '{0}' already exists.", mainName); throw new AlreadyExistsException("Group '" + mainName + "' already exists."); } Document group = connection.getUserDatabase().createDocument(); for (Attribute attribute : attributes.values()) { group.replaceItemValue(attribute.getName(), getDominoValues(attribute)); } List<String> membersList = getGroupMembers(members, memberGroups, memberPeople); if (membersList.size() > 0) { group.replaceItemValue(MEMBERS.getName(), membersList); } group.replaceItemValue(DominoConstants.FORM, DominoConstants.FORM_GROUP); group.replaceItemValue(DominoConstants.TYPE, DominoConstants.FORM_GROUP); group.replaceItemValue(LIST_NAME.getName(), listName); if (!group.save()) { LOG.ok("Can't save group '{0}'.", mainName); throw new ConnectorException("Can't save group '" + mainName + "'."); } group = getGroup(mainName); return createGroupUid(group); } private Uid createGroupUid(Document group) throws NotesException { String uid = getGroupFullName(group.getItemValue(LIST_NAME.getName())); return new Uid(uid); } private List<String> getGroupMembers(Vector members, Vector memberGroups, Vector memberPeople) throws NotesException { List list = new ArrayList(); if (members == null && memberGroups != null) { list.addAll(memberGroups); } if (members == null && memberPeople != null) { list.addAll(memberPeople); } if (members != null) { list.addAll(members); } List<String> result = new ArrayList<String>(); for (Object member : list) { result.add(getCanonical(connection, (String) member)); } return result; } public Uid addAttributeValues(ObjectClass objclass, Uid uid, Set<Attribute> valuesToAdd, OperationOptions options) { return update(objclass, uid, valuesToAdd, options, Update.ADD); } public Uid removeAttributeValues(ObjectClass objclass, Uid uid, Set<Attribute> valuesToRemove, OperationOptions options) { return update(objclass, uid, valuesToRemove, options, Update.REMOVE); } public Uid update(ObjectClass objclass, Uid uid, Set<Attribute> replaceAttributes, OperationOptions options) { return update(objclass, uid, replaceAttributes, options, Update.REPLACE); } private Uid update(ObjectClass oclass, Uid uid, Set<Attribute> attrs, OperationOptions options, Update type) { LOG.info("update::start"); LOG.ok("Parameters: oc: {0}, uid: {1}, t: {2}, a: {3}, op: {4}", oclass, uid, type, attrs, options); try { Map<String, Attribute> attributes = new HashMap<String, Attribute>(AttributeUtil.toMap(attrs)); if (ObjectClass.ACCOUNT.equals(oclass)) { uid = updateAccount(uid, attributes, options, type); } else if (ObjectClass.GROUP.equals(oclass)) { uid = updateGroup(uid, attributes, options, type); } else { LOG.ok("Unknown object class '{0}'.", oclass); throw new IllegalArgumentException("Unknown object class '" + oclass + "'."); } } catch (NotesException ex) { handleException(ex, "Couldn't update " + oclass.getObjectClassValue() + ", uid: " + uid, LOG); } LOG.info("update::finish"); return uid; } private Uid updateAccount(Name name, Map<String, Attribute> attrs) { Uid uid = null; Document document = null; try { document = getUserByName(name.getNameValue()); if (document == null) { throw new ConnectorException("Document for account '" + name.getNameValue() + "' doesn't exist."); } uid = updateAccount(document, attrs, Update.REPLACE); } catch (NotesException ex) { handleException(ex, "Couldn't update user '" + name.getNameValue() + "'", LOG); } finally { recycleQuietly(document); } return uid; } private Uid updateAccount(Uid uid, Map<String, Attribute> attrs, OperationOptions options, Update type) throws NotesException { Document document = null; try { document = getUserByUid(getGuid(uid.getUidValue())); if (document == null) { throw new ConnectorException("Document with uid'" + uid.getUidValue() + "' doesn't exist."); } uid = updateAccount(document, attrs, type); } catch (NotesException ex) { handleException(ex, "Couldn't update user '" + getGuid(uid.getUidValue()) + "'", LOG); } finally { recycleQuietly(document); } return uid; } private Uid updateAccount(Document document, Map<String, Attribute> attrs, Update update) throws NotesException { Validate.notNull(document, "Document for update is null."); LOG.ok("updateAccount {0}", update); final Uid uid = new Uid(getGuid(document.getUniversalID())); if (attrs.isEmpty()) { return uid; } Vector fullNames = document.getItemValue(FULL_NAME.getName()); String fullName = getCanonical(connection, fullNames.get(0).toString()); String userHttpPw = decode(getAttributeValue(attrs, HTTP_PASSWORD, GuardedString.class)); if (userHttpPw != null) { attrs.put(HTTP_PASSWORD.getName(), build(HTTP_PASSWORD, userHttpPw)); } Integer pwdChangeInterval = getAttributeValue(attrs, PASSWORD_CHANGE_INTERVAL, Integer.class); Integer pwdGracePeriod = getAttributeValue(attrs, PASSWORD_GRACE_PERIOD, Integer.class); String currentPassword = decode(getAttributeValue(attrs, CURRENT_PASSWORD, GuardedString.class)); String newPassword = decode(getAttributeValue(attrs, PASSWORD, GuardedString.class)); List<String> denyGroups = getAttributeValue(attrs, DENY_GROUPS, Vector.class); if (denyGroups == null && config.getDisableDenyGroup() != null) { denyGroups = new Vector<String>(); denyGroups.add(config.getDisableDenyGroup()); } String idFile = getAttributeValue(attrs, ID_FILE); setPassword(fullName, currentPassword, newPassword, idFile); boolean changed = false; Integer roamCleanPer = getAttributeValue(attrs, ROAM_CLEAN_PER, Integer.class); if (roamCleanPer != null) { document.replaceItemValue(ROAM_CLEAN_PER.getName(), roamCleanPer); changed = true; } Integer roamCleanSetting = getAttributeValue(attrs, ROAM_CLEAN_SETTING, Integer.class); if (roamCleanSetting != null) { document.replaceItemValue(ROAM_CLEAN_SETTING.getName(), roamCleanSetting); changed = true; } Vector groups = getAttributeValue(attrs, GROUP_LIST, Vector.class); if (groups != null) { updateAccountGroupList(fullName, groups, update); } Boolean enable = getAttributeValue(attrs, ENABLE, Boolean.class); updateAccountSecurity(fullName, enable, denyGroups, pwdChangeInterval, pwdGracePeriod); Boolean recertify = getAttributeValue(attrs, RECERTIFY, Boolean.class); if (recertify != null && recertify) { AdministrationProcess adminProcess = connection.getAdministrationProcess(); adminProcess.recertifyUser(fullName); } Integer mailQuotaSize = getAttributeValue(attrs, MAIL_QUOTA_SIZE_LIMIT, Integer.class); Integer mailWarningThreshold = getAttributeValue(attrs, MAIL_QUOTA_WARNING_THRESHOLD, Integer.class); if (mailQuotaSize != null || mailWarningThreshold != null) { String mailDb = document.getItemValueString(MAIL_FILE.getName()); updateMailDbQuota(mailDb, mailQuotaSize, mailWarningThreshold); } updateAccountRenameUser(fullName, document, attrs); String mailServer = getAttributeValue(attrs, MAIL_SERVER); if (mailServer != null) { connection.getAdministrationProcess().moveMailUser(fullName, mailServer, NEW_HOME_SERVER_MAIL_PATH); } attrs.remove(CREDENTIALS.getName()); attrs.remove(NORTH_AMERICAN.getName()); for (Attribute attribute : attrs.values()) { Vector vector = new Vector(attribute.getValue()); document.replaceItemValue(attribute.getName(), vector); changed = true; } if (changed && !document.save()) { LOG.ok("Couldn't update account for {0}.", fullName); throw new ConnectorException("Couldn't update account '" + fullName + "'."); } return uid; } private void setPassword(String fullName, String currentPassword, String newPassword, String idFile) throws NotesException { if ((currentPassword != null && newPassword == null) || (currentPassword == null && newPassword != null)) { LOG.error("Missing password."); throw new ConnectorException("Missing password."); } // if (config.getUseIDVault() && newPassword != null) { // Session session = connection.getSession(); // session.resetUserPassword(null, fullName, newPassword); // // resetPasswordInIDVault(fullName, newPassword); // } else if (currentPassword != null && newPassword != null) { // if (idFile == null) { // throw new ConnectorException("ID file is not defined."); // } // // changeIdFilePassword(currentPassword, newPassword, idFile); // } if (config.getSyncInetPswd() && currentPassword != null && newPassword != null) { AdministrationProcess adminProcess = connection.getAdministrationProcess(); adminProcess.changeHTTPPassword(fullName, currentPassword, newPassword); } } private void resetPasswordInIDVault(String username, String newPassword) { //todo implement using JNI or using LN script } private void changeIdFilePassword(String currentPassword, String newPassword, String idFile) { //todo implement using JNI or using LN script } private void updateAccountGroupList(String name, List<String> newGroups, Update update) throws NotesException { List<String> oldGroups = getGroupList(name); if (newGroups != null && !Update.REMOVE.equals(update)) { Vector users = new Vector(); users.add(name); for (String newGroup : newGroups) { if (oldGroups == null || !oldGroups.contains(newGroup)) { if (!checkIfGroupExists(newGroup)) { LOG.error("Group {0} doesn't exist.", newGroup); throw new ConnectorException("Group '" + newGroup + "' doesn't exist."); } connection.getAdministrationProcess().addGroupMembers(newGroup, users); } if (oldGroups != null) { oldGroups.remove(newGroup); } } } if (oldGroups != null && !Update.ADD.equals(update)) { for (String oldGroup : oldGroups) { if (newGroups == null || !newGroups.contains(oldGroup) || !Update.REMOVE.equals(update)) { continue; } removeUserFromGroup(name, oldGroup); } } } private void updateAccountRenameUser(String fullName, Document doc, Map<String, Attribute> attrs) throws NotesException { String lastName = getAttributeValue(attrs, LAST_NAME); String firstName = getAttributeValue(attrs, FIRST_NAME); String middleInitial = getAttributeValue(attrs, MIDDLE_INITIAL); String orgUnit = getAttributeValue(attrs, ORG_UNIT); String altCn = getAttributeValue(attrs, ALT_FULL_NAME); String altOU = getAttributeValue(attrs, ALT_ORG_UNIT); String altLanguage = getAttributeValue(attrs, ALT_FULL_NAME_LANGUAGE); if (firstName == null && middleInitial == null && lastName == null && orgUnit == null && altCn == null && altOU == null && altLanguage == null) { return; } firstName = firstName != null ? firstName : RENAME_NO_CHANGE; middleInitial = middleInitial != null ? middleInitial : RENAME_NO_CHANGE; lastName = lastName != null ? lastName : RENAME_NO_CHANGE; orgUnit = orgUnit != null ? orgUnit : getOrgUnit(connection, fullName); altCn = altCn != null ? getCommon(this.connection, altCn) : RENAME_NO_CHANGE; altOU = altOU != null ? altOU : RENAME_NO_CHANGE; altLanguage = altLanguage != null ? altLanguage : getDefaultValueForRename(ALT_FULL_NAME_LANGUAGE, doc); LOG.ok("updateAccountRenameUser: fullName {0}, lastName {1}, firstName {2}, middleInitial {3}, orgUnit {4}.", fullName, lastName, firstName, middleInitial, orgUnit); connection.getAdministrationProcess().renameNotesUser(fullName, lastName, firstName, middleInitial, orgUnit, altCn, altOU, altLanguage, false); } private String getDefaultValueForRename(DominoAccountAttribute attr, Document doc) throws NotesException { String value = doc.getItemValueString(attr.getName()); if (value == null) { value = RENAME_NO_CHANGE; } return value; } private void updateMailDbQuota(String mailDb, Integer mailQuotaSize, Integer mailWarningThreshold) { if (mailDb != null) { return; } LOG.error("Quotas for mail db '" + mailDb + "' wont be changed, not yet implemented."); //todo implement through administration process or notes script or something... } private void updateAccountSecurity(String fullName, Boolean enabled, List<String> denyGroups, Integer pwdChangeInterval, Integer pwdGracePeriod) throws NotesException { LOG.ok("updateAccountSecurity for {0}, enabled {1}, denyGroups {2}, pwdChangeInterval {3}, pwdGracePeriod {4}", fullName, enabled, denyGroups, pwdChangeInterval, pwdGracePeriod); if (enabled != null) { updateAccountActivation(fullName, denyGroups, pwdChangeInterval, pwdGracePeriod, enabled); } if ((enabled != null && denyGroups != null && (pwdChangeInterval != null || pwdGracePeriod != null)) || (pwdChangeInterval != null) || pwdGracePeriod != null) { connection.getAdministrationProcess().setUserPasswordSettings(fullName, null, pwdChangeInterval, pwdGracePeriod, null); } } private void updateAccountActivation(String username, List<String> denyGroups, Integer pwdChIntervalInt, Integer pwdGracePeriodInt, boolean enabled) throws NotesException { AdministrationProcess adminProcess = connection.getAdministrationProcess(); if (denyGroups != null) { for (String group : denyGroups) { if (enabled) { removeUserFromGroup(username, group); } else { Vector users = new Vector(); users.add(username); adminProcess.addGroupMembers(group, users); } } } else { Integer pwdChk = enabled ? AdministrationProcess.PWD_CHK_DONTCHECKPASSWORD : AdministrationProcess.PWD_CHK_LOCKOUT; adminProcess.setUserPasswordSettings(username, pwdChk, pwdChIntervalInt, pwdGracePeriodInt, null); } } private void removeUserFromGroup(String usernameCanonical, String groupName) throws NotesException { LOG.ok("removeUserFromGroup: usernameCanonical {0}, groupName {1}", usernameCanonical, groupName); Document group = getGroup(groupName); if (group == null) { LOG.error("Invalid group name {0}.", groupName); throw new ConnectorException("Invalid group name '" + groupName + "'."); } Vector members = group.getItemValue(MEMBERS.getName()); if (members != null && members.remove(usernameCanonical)) { Map<String, Attribute> attrs = new HashMap<String, Attribute>(); attrs.put(MEMBERS.getName(), build(MEMBERS, members.toArray())); updateGroup(createGroupUid(group), attrs, null, Update.REPLACE); } } private Uid updateGroup(Uid uid, Map<String, Attribute> attrs, OperationOptions options, Update type) throws NotesException { LOG.ok("updateGroup {0}, attrs {1}, update {2}", uid, attrs, type); if (attrs.isEmpty()) { return uid; } attrs.remove(DISPLAY_NAME.getName()); Name nameAtt = (Name) attrs.remove(Name.NAME); String name = nameAtt != null ? nameAtt.getNameValue() : null; String listName = getAttributeValue(attrs, LIST_NAME); if (nameAtt != null && listName != null && name != null && !name.equals(listName)) { throw new IllegalArgumentException("Name doesn't equal list name attribute."); } String fullName = name != null ? name : listName; Document document = getGroup(uid.getUidValue()); if (document == null) { LOG.error("Invalid group uid {0}", uid); throw new ConnectorException("Invalid group uid '" + uid + "'."); } Vector members = getAttributeValue(attrs, MEMBERS, Vector.class); Vector memberGroups = getAttributeValue(attrs, MEMBER_GROUPS, Vector.class); Vector memberPeople = getAttributeValue(attrs, MEMBER_PEOPLE, Vector.class); for (Attribute attribute : attrs.values()) { document.replaceItemValue(attribute.getName(), getDominoValues(attribute)); } if (fullName != null) { String mainName = getGroupDisplayName(fullName); if (!mainName.equals(uid.getUidValue())) { Document existingGroup = getGroup(mainName); if ((existingGroup != null) && (!existingGroup.getUniversalID().equals(document.getUniversalID()))) { LOG.error("Group {0} already exists.", mainName); throw new AlreadyExistsException("Group '" + mainName + "' already exists."); } } document.replaceItemValue(LIST_NAME.getName(), new Vector(Arrays.asList(fullName.split(";")))); uid = new Uid(fullName); } List<String> membersList = getGroupMembers(members, memberGroups, memberPeople); document.replaceItemValue(MEMBERS.getName(), new Vector(membersList)); if (!document.save()) { LOG.error("Couldn't update group {0}.", fullName); throw new ConnectorException("Couldn't update group '" + fullName + "'."); } return uid; } public void delete(ObjectClass objClass, Uid uid, OperationOptions options) { try { if (ObjectClass.ACCOUNT.equals(objClass)) { deleteAccount(uid, options); } else if (ObjectClass.GROUP.equals(objClass)) { deleteGroup(uid, options); } else { LOG.ok("Unknown object class '{0}'.", objClass); throw new IllegalArgumentException("Unknown object class '" + objClass + "'."); } } catch (NotesException ex) { if (ex.id == NotesError.NOTES_ERR_BAD_UNID || ex.id == NotesError.NOTES_ERR_NOSUCH_GROUP) { throw new UnknownUidException(uid, objClass); } handleException(ex, "Couldn't delete " + objClass.getObjectClassValue() + " with uid " + uid, LOG); } } private void deleteAccount(Uid uid, OperationOptions options) throws NotesException { String unid = getGuid(uid.getUidValue()); Document document = connection.getUserDatabase().getDocumentByUNID(unid); if (document == null) { throw new ConnectorException("Invalid uid '" + uid + "'."); } String userName = (String) document.getItemValue(FULL_NAME.getName()).elementAt(0); Integer mailFileAction = getOperationOptionValue(options, MAIL_FILE_ACTION, config.getMailFileAction()); Boolean deleteWindowsUser = getOperationOptionValue(options, DELETE_WINDOWS_USER, false); AdministrationProcess adminProcess = connection.getAdministrationProcess(); adminProcess.deleteUser(userName, config.getImmediateDelete(), mailFileAction, config.getDeleteDenyGroup(), deleteWindowsUser.booleanValue()); } private void deleteGroup(Uid uid, OperationOptions options) throws NotesException { String groupName = getGroupDisplayName(uid.getUidValue()); AdministrationProcess adminProcess = connection.getAdministrationProcess(); adminProcess.deleteGroup(groupName, config.getImmediateDelete().booleanValue()); } }