View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.provisioning.java;
20  
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Optional;
26  import java.util.Set;
27  import java.util.stream.Stream;
28  import org.apache.commons.lang3.tuple.Pair;
29  import org.apache.syncope.common.lib.to.Item;
30  import org.apache.syncope.common.lib.to.Provision;
31  import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
32  import org.apache.syncope.core.persistence.api.entity.Any;
33  import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
34  import org.apache.syncope.core.persistence.api.entity.ExternalResource;
35  import org.apache.syncope.core.persistence.api.entity.Membership;
36  import org.apache.syncope.core.persistence.api.entity.VirSchema;
37  import org.apache.syncope.core.provisioning.api.ConnectorManager;
38  import org.apache.syncope.core.provisioning.api.VirAttrHandler;
39  import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
40  import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheKey;
41  import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
42  import org.apache.syncope.core.provisioning.java.pushpull.OutboundMatcher;
43  import org.identityconnectors.framework.common.objects.Attribute;
44  import org.identityconnectors.framework.common.objects.ConnectorObject;
45  import org.slf4j.Logger;
46  import org.slf4j.LoggerFactory;
47  import org.springframework.transaction.annotation.Transactional;
48  
49  @Transactional(readOnly = true)
50  public class DefaultVirAttrHandler implements VirAttrHandler {
51  
52      protected static final Logger LOG = LoggerFactory.getLogger(VirAttrHandler.class);
53  
54      protected final ConnectorManager connectorManager;
55  
56      protected final VirAttrCache virAttrCache;
57  
58      protected final OutboundMatcher outboundMatcher;
59  
60      protected final AnyUtilsFactory anyUtilsFactory;
61  
62      public DefaultVirAttrHandler(
63              final ConnectorManager connectorManager,
64              final VirAttrCache virAttrCache,
65              final OutboundMatcher outboundMatcher,
66              final AnyUtilsFactory anyUtilsFactory) {
67  
68          this.connectorManager = connectorManager;
69          this.virAttrCache = virAttrCache;
70          this.outboundMatcher = outboundMatcher;
71          this.anyUtilsFactory = anyUtilsFactory;
72      }
73  
74      @Override
75      public void setValues(final Any<?> any, final ConnectorObject connObj) {
76          if (any == null) {
77              LOG.debug("Null any passed, ignoring");
78              return;
79          }
80  
81          AllowedSchemas<VirSchema> schemas =
82                  anyUtilsFactory.getInstance(any).dao().findAllowedSchemas(any, VirSchema.class);
83          Stream.concat(
84                  schemas.getForSelf().stream(),
85                  schemas.getForMemberships().values().stream().flatMap(Set::stream)).forEach(schema -> {
86  
87              VirAttrCacheKey cacheKey = new VirAttrCacheKey(any.getType().getKey(), any.getKey(), schema.getKey());
88  
89              Attribute attr = connObj.getAttributeByName(schema.getExtAttrName());
90              if (attr == null) {
91                  virAttrCache.expire(cacheKey);
92                  LOG.debug("Evicted from cache: {}", cacheKey);
93              } else {
94                  VirAttrCacheValue cacheValue = new VirAttrCacheValue(attr.getValue());
95                  virAttrCache.put(cacheKey, cacheValue);
96                  LOG.debug("Set in cache: {}={}", cacheKey, cacheValue);
97              }
98          });
99      }
100 
101     protected Map<VirSchema, List<String>> getValues(final Any<?> any, final Set<VirSchema> schemas) {
102         Set<ExternalResource> resources = anyUtilsFactory.getInstance(any).getAllResources(any);
103 
104         Map<VirSchema, List<String>> result = new HashMap<>();
105 
106         Map<Pair<ExternalResource, Provision>, Set<VirSchema>> toRead = new HashMap<>();
107 
108         schemas.stream().filter(schema -> resources.contains(schema.getResource())).forEach(schema -> {
109             VirAttrCacheKey cacheKey = new VirAttrCacheKey(any.getType().getKey(), any.getKey(), schema.getKey());
110             VirAttrCacheValue cacheValue = virAttrCache.get(cacheKey);
111 
112             if (cacheValue != null) {
113                 LOG.debug("Found in cache: {}={}", cacheKey, cacheValue);
114                 result.put(schema, cacheValue.getValues());
115             } else if (schema.getAnyType().equals(any.getType())) {
116                 schema.getResource().getProvisionByAnyType(schema.getAnyType().getKey()).ifPresent(provision -> {
117                     Set<VirSchema> schemasToRead = toRead.get(Pair.of(schema.getResource(), provision));
118                     if (schemasToRead == null) {
119                         schemasToRead = new HashSet<>();
120                         toRead.put(Pair.of(schema.getResource(), provision), schemasToRead);
121                     }
122                     schemasToRead.add(schema);
123                 });
124             }
125         });
126 
127         toRead.forEach((pair, schemasToRead) -> {
128             LOG.debug("About to read from {}: {}", pair, schemasToRead);
129 
130             outboundMatcher.match(
131                     connectorManager.getConnector(pair.getLeft()),
132                     any,
133                     pair.getLeft(),
134                     pair.getRight(),
135                     Optional.empty(),
136                     schemasToRead.stream().map(VirSchema::asLinkingMappingItem).toArray(Item[]::new)).
137                     forEach(connObj -> schemasToRead.forEach(schema -> {
138 
139                 Attribute attr = connObj.getAttributeByName(schema.getExtAttrName());
140                 if (attr != null) {
141                     VirAttrCacheKey cacheKey =
142                             new VirAttrCacheKey(any.getType().getKey(), any.getKey(), schema.getKey());
143                     VirAttrCacheValue cacheValue = virAttrCache.put(cacheKey, new VirAttrCacheValue(attr.getValue()));
144                     LOG.debug("Set in cache: {}={}", cacheKey, cacheValue);
145 
146                     result.put(schema, cacheValue.getValues());
147                 }
148             }));
149         });
150 
151         return result;
152     }
153 
154     @Override
155     public List<String> getValues(final Any<?> any, final VirSchema schema) {
156         if (!anyUtilsFactory.getInstance(any).dao().
157                 findAllowedSchemas(any, VirSchema.class).forSelfContains(schema)) {
158 
159             LOG.debug("{} not allowed for {}", schema, any);
160             return List.of();
161         }
162 
163         List<String> result = getValues(any, Set.of(schema)).get(schema);
164         return result == null ? List.of() : result;
165     }
166 
167     @Override
168     public List<String> getValues(final Any<?> any, final Membership<?> membership, final VirSchema schema) {
169         if (!anyUtilsFactory.getInstance(any).dao().
170                 findAllowedSchemas(any, VirSchema.class).getForMembership(membership.getRightEnd()).contains(schema)) {
171 
172             LOG.debug("{} not allowed for {}", schema, any);
173             return List.of();
174         }
175 
176         List<String> result = getValues(any, Set.of(schema)).get(schema);
177         return result == null ? List.of() : result;
178     }
179 
180     @Override
181     public Map<VirSchema, List<String>> getValues(final Any<?> any) {
182         return getValues(
183                 any,
184                 anyUtilsFactory.getInstance(any).dao().findAllowedSchemas(any, VirSchema.class).getForSelf());
185     }
186 
187     @Override
188     public Map<VirSchema, List<String>> getValues(final Any<?> any, final Membership<?> membership) {
189         return getValues(
190                 any,
191                 anyUtilsFactory.getInstance(any).dao().findAllowedSchemas(any, VirSchema.class).
192                         getForMembership(membership.getRightEnd()));
193     }
194 }