001/* 002 * Copyright 2016 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.contentio.synchronize.impl; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.avalon.framework.activity.Initializable; 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.configuration.Configuration; 026import org.apache.avalon.framework.configuration.ConfigurationException; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.commons.lang.StringUtils; 030import org.slf4j.Logger; 031 032import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollection; 033import org.ametys.runtime.i18n.I18nizableText; 034 035/** 036 * Implementation of {@link SynchronizableContentsCollection} to be synchronized with a LDAP data source 037 */ 038public class LDAPSynchronizableContentsCollection extends AbstractDataSourceSynchronizableContentsCollection implements Component, Initializable 039{ 040 private static final String __PARAM_LDAP_SCOPE = "scope"; 041 private static final String __PARAM_LDAP_RELATIVE_DN = "peopleDN"; 042 private static final String __PARAM_LDAP_FILTER = "baseFilter"; 043 044 private static final int __DEFAULT_PAGE_SIZE = 1000; 045 046 /** The page size */ 047 protected int _pageSize; 048 049 /** The helper for LDAP connection */ 050 protected LDAPCollectionHelper _ldapHelper; 051 052 @Override 053 public void service(ServiceManager serviceManager) throws ServiceException 054 { 055 super.service(serviceManager); 056 _ldapHelper = (LDAPCollectionHelper) serviceManager.lookup(LDAPCollectionHelper.ROLE); 057 } 058 059 @Override 060 public void initialize() throws Exception 061 { 062 _ldapHelper._delayedInitialize(getDataSourceId()); 063 } 064 065 @Override 066 protected void configureDataSource(Configuration configuration) throws ConfigurationException 067 { 068 super.configureDataSource(configuration); 069 _pageSize = configuration.getChild("pageSize").getValueAsInteger(__DEFAULT_PAGE_SIZE); 070 } 071 072 @Override 073 protected Map<String, Map<String, Object>> internalSearch(Map<String, Object> searchParameters, int offset, int limit, List<Object> sort, Logger logger) 074 { 075 // Sort is ignored in LDAP request 076 077 Map<String, List<String>> mapping = getMapping(); 078 Map<String, Map<String, Object>> results = new HashMap<>(); 079 080 String idField = getIdField(); 081 List<String> remoteKeys = mapping.get(idField); 082 if (remoteKeys != null && remoteKeys.size() > 0) 083 { 084 // Filter from search parameters 085 String filter = getFilter(); 086 List<String> filters = new ArrayList<>(); 087 if (StringUtils.isNotEmpty(filter)) 088 { 089 filters.add(filter); 090 } 091 if (searchParameters != null) 092 { 093 for (String parameterName : searchParameters.keySet()) 094 { 095 filters.add(parameterName + "=" + searchParameters.get(parameterName)); 096 } 097 } 098 String filtersReduced = filters.stream().filter(StringUtils::isNotEmpty).map(s -> "(" + s + ")").reduce("", (s1, s2) -> s1 + s2); 099 if (!filtersReduced.isEmpty()) 100 { 101 filtersReduced = "(&" + filtersReduced + ")"; 102 } 103 104 results = _ldapHelper.search(getId(), _pageSize, getRelativeDN(), filtersReduced, getSearchScope(), offset, limit, mapping, remoteKeys.get(0), logger); 105 106 for (Map<String, Object> result : results.values()) 107 { 108 Object sccValues = result.get(remoteKeys.get(0)); 109 result.put(SCC_UNIQUE_ID, sccValues instanceof List<?> ? ((List<?>) sccValues).get(0) : sccValues); 110 } 111 112 _nbError = _ldapHelper.getNbErrors(); 113 _hasGlobalError = _ldapHelper.hasGlobalError(); 114 } 115 else 116 { 117 _nbError = 1; 118 logger.error("Missing LDAP attribute in mapping for field '{}' holding the unique identifier", idField); 119 } 120 121 return results; 122 } 123 124 /** 125 * Get the scope for LDAP search 126 * @return The scope 127 */ 128 protected String getSearchScope() 129 { 130 return (String) getParameterValues().get(__PARAM_LDAP_SCOPE); 131 } 132 133 /** 134 * Get the LDAP filter 135 * @return the filter 136 */ 137 protected String getFilter() 138 { 139 return (String) getParameterValues().get(__PARAM_LDAP_FILTER); 140 } 141 142 /** 143 * Get the LDAP relative DN 144 * @return the relative DN 145 */ 146 protected String getRelativeDN() 147 { 148 return (String) getParameterValues().get(__PARAM_LDAP_RELATIVE_DN); 149 } 150 151 @Override 152 protected void configureSearchModel() 153 { 154 for (String columnOrCriteria : _columnsAndCriteria) 155 { 156 _searchModelConfiguration.addCriterion(columnOrCriteria); 157 _searchModelConfiguration.addColumn(columnOrCriteria, new I18nizableText(columnOrCriteria), false); 158 } 159 } 160 161 @Override 162 protected Map<String, Map<String, List<Object>>> getRemoteValues(Map<String, Object> searchParameters, Logger logger) 163 { 164 Map<String, Map<String, List<Object>>> organizedResults = super.getRemoteValues(searchParameters, logger); 165 _ldapHelper.transformTypedAttributes(organizedResults, getContentType(), getMapping().keySet()); 166 return organizedResults; 167 } 168}