1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 }