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.Collection;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.Locale;
25 import java.util.Map;
26 import java.util.Optional;
27 import java.util.Set;
28 import org.apache.syncope.common.lib.to.ConnInstanceTO;
29 import org.apache.syncope.common.lib.types.ConnConfProperty;
30 import org.apache.syncope.common.lib.types.ConnectorCapability;
31 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
32 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
33 import org.apache.syncope.core.persistence.api.entity.ConnInstance;
34 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
35 import org.apache.syncope.core.persistence.api.entity.ExternalResource;
36 import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
37 import org.apache.syncope.core.provisioning.api.Connector;
38 import org.apache.syncope.core.provisioning.api.ConnectorManager;
39 import org.apache.syncope.core.provisioning.api.data.ConnInstanceDataBinder;
40 import org.apache.syncope.core.provisioning.api.utils.ConnPoolConfUtils;
41 import org.apache.syncope.core.spring.ApplicationContextProvider;
42 import org.apache.syncope.core.spring.security.AuthContextUtils;
43 import org.identityconnectors.common.l10n.CurrentLocale;
44 import org.identityconnectors.framework.api.ConnectorFacadeFactory;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.transaction.annotation.Transactional;
48
49 public class DefaultConnectorManager implements ConnectorManager {
50
51 protected static final Logger LOG = LoggerFactory.getLogger(ConnectorManager.class);
52
53 protected static String getBeanName(final ExternalResource resource) {
54 return String.format("connInstance-%s-%S-%s",
55 AuthContextUtils.getDomain(), resource.getConnector().getKey(), resource.getKey());
56 }
57
58 protected final ConnIdBundleManager connIdBundleManager;
59
60 protected final RealmDAO realmDAO;
61
62 protected final ExternalResourceDAO resourceDAO;
63
64 protected final ConnInstanceDataBinder connInstanceDataBinder;
65
66 protected final AsyncConnectorFacade asyncFacade;
67
68 protected final EntityFactory entityFactory;
69
70 public DefaultConnectorManager(
71 final ConnIdBundleManager connIdBundleManager,
72 final RealmDAO realmDAO,
73 final ExternalResourceDAO resourceDAO,
74 final ConnInstanceDataBinder connInstanceDataBinder,
75 final AsyncConnectorFacade asyncFacade,
76 final EntityFactory entityFactory) {
77
78 this.connIdBundleManager = connIdBundleManager;
79 this.realmDAO = realmDAO;
80 this.resourceDAO = resourceDAO;
81 this.connInstanceDataBinder = connInstanceDataBinder;
82 this.asyncFacade = asyncFacade;
83 this.entityFactory = entityFactory;
84 }
85
86 @Override
87 public Optional<Connector> readConnector(final ExternalResource resource) {
88 return Optional.ofNullable((Connector) ApplicationContextProvider.getBeanFactory().
89 getSingleton(getBeanName(resource)));
90 }
91
92 @Override
93 public Connector getConnector(final ExternalResource resource) {
94
95 return readConnector(resource).orElseGet(() -> {
96 registerConnector(resource);
97 return (Connector) ApplicationContextProvider.getBeanFactory().getSingleton(getBeanName(resource));
98 });
99 }
100
101 @Override
102 public ConnInstance buildConnInstanceOverride(
103 final ConnInstanceTO connInstance,
104 final Collection<ConnConfProperty> confOverride,
105 final Optional<Collection<ConnectorCapability>> capabilitiesOverride) {
106
107 ConnInstance override = entityFactory.newEntity(ConnInstance.class);
108 override.setAdminRealm(realmDAO.findByFullPath(connInstance.getAdminRealm()));
109 override.setConnectorName(connInstance.getConnectorName());
110 override.setDisplayName(connInstance.getDisplayName());
111 override.setBundleName(connInstance.getBundleName());
112 override.setVersion(connInstance.getVersion());
113 override.setLocation(connInstance.getLocation());
114 override.setConf(connInstance.getConf());
115 override.getCapabilities().addAll(connInstance.getCapabilities());
116 override.setConnRequestTimeout(connInstance.getConnRequestTimeout());
117
118 Map<String, ConnConfProperty> overridable = new HashMap<>();
119 Set<ConnConfProperty> conf = new HashSet<>();
120
121 override.getConf().forEach(prop -> {
122 if (prop.isOverridable()) {
123 overridable.put(prop.getSchema().getName(), prop);
124 } else {
125 conf.add(prop);
126 }
127 });
128
129
130 confOverride.stream().
131 filter(prop -> overridable.containsKey(prop.getSchema().getName()) && !prop.getValues().isEmpty()).
132 forEach(prop -> {
133 conf.add(prop);
134 overridable.remove(prop.getSchema().getName());
135 });
136
137
138 conf.addAll(overridable.values());
139
140 override.setConf(conf);
141
142
143 capabilitiesOverride.ifPresent(capabilities -> {
144 override.getCapabilities().clear();
145 override.getCapabilities().addAll(capabilities);
146 });
147
148 if (connInstance.getPoolConf() != null) {
149 override.setPoolConf(
150 ConnPoolConfUtils.getConnPoolConf(connInstance.getPoolConf(), entityFactory.newConnPoolConf()));
151 }
152
153 return override;
154 }
155
156 @Override
157 public Connector createConnector(final ConnInstance connInstance) {
158 return new ConnectorFacadeProxy(connInstance, asyncFacade);
159 }
160
161 @Override
162 public void registerConnector(final ExternalResource resource) {
163 String beanName = getBeanName(resource);
164
165 if (ApplicationContextProvider.getBeanFactory().containsSingleton(beanName)) {
166 unregisterConnector(beanName);
167 }
168
169 ConnInstance connInstance = buildConnInstanceOverride(
170 connInstanceDataBinder.getConnInstanceTO(resource.getConnector()),
171 resource.getConfOverride(),
172 resource.isOverrideCapabilities() ? Optional.of(resource.getCapabilitiesOverride()) : Optional.empty());
173 Connector connector = createConnector(connInstance);
174 LOG.debug("Connector to be registered: {}", connector);
175
176 ApplicationContextProvider.getBeanFactory().registerSingleton(beanName, connector);
177 LOG.debug("Successfully registered bean {}", beanName);
178 }
179
180 protected void unregisterConnector(final String id) {
181 ApplicationContextProvider.getBeanFactory().destroySingleton(id);
182 }
183
184 @Override
185 public void unregisterConnector(final ExternalResource resource) {
186 String beanName = getBeanName(resource);
187 if (ApplicationContextProvider.getBeanFactory().containsSingleton(beanName)) {
188 unregisterConnector(beanName);
189 }
190 }
191
192 @Transactional(readOnly = true)
193 @Override
194 public void load() {
195
196 CurrentLocale.set(Locale.ENGLISH);
197
198
199 connIdBundleManager.getConnManagers();
200
201
202 int connectors = 0;
203 for (ExternalResource resource : resourceDAO.findAll()) {
204 LOG.info("Registering resource-connector pair {}-{}", resource, resource.getConnector());
205 try {
206 registerConnector(resource);
207
208 connectors++;
209 } catch (Exception e) {
210 LOG.error("While registering resource-connector pair {}-{}", resource, resource.getConnector(), e);
211 }
212 }
213
214 LOG.info("Done loading {} connectors", connectors);
215 }
216
217 @Transactional(readOnly = true)
218 @Override
219 public void unload() {
220 int connectors = 0;
221 for (ExternalResource resource : resourceDAO.findAll()) {
222 String beanName = getBeanName(resource);
223 if (ApplicationContextProvider.getBeanFactory().containsSingleton(beanName)) {
224 LOG.info("Unegistering resource-connector pair {}-{}", resource, resource.getConnector());
225
226 getConnector(resource).dispose();
227 unregisterConnector(beanName);
228
229 connectors++;
230 }
231 }
232
233 LOG.info("Done unloading {} connectors", connectors);
234
235 ConnectorFacadeFactory.getInstance().dispose();
236 connIdBundleManager.resetConnManagers();
237 LOG.info("All connector resources disposed");
238 }
239 }