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.pushpull;
20  
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Objects;
24  import java.util.Set;
25  import java.util.stream.Collectors;
26  import java.util.stream.Stream;
27  import org.apache.syncope.common.lib.to.Item;
28  import org.apache.syncope.common.lib.to.Provision;
29  import org.apache.syncope.common.lib.to.ProvisioningReport;
30  import org.apache.syncope.common.lib.to.PullTaskTO;
31  import org.apache.syncope.common.lib.types.ClientExceptionType;
32  import org.apache.syncope.common.lib.types.ConflictResolutionAction;
33  import org.apache.syncope.common.lib.types.MatchingRule;
34  import org.apache.syncope.common.lib.types.PullMode;
35  import org.apache.syncope.common.lib.types.TaskType;
36  import org.apache.syncope.common.lib.types.UnmatchingRule;
37  import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
38  import org.apache.syncope.core.persistence.api.dao.RealmDAO;
39  import org.apache.syncope.core.persistence.api.entity.AnyType;
40  import org.apache.syncope.core.persistence.api.entity.ExternalResource;
41  import org.apache.syncope.core.persistence.api.entity.VirSchema;
42  import org.apache.syncope.core.persistence.api.entity.task.AnyTemplatePullTask;
43  import org.apache.syncope.core.persistence.api.entity.task.PullTask;
44  import org.apache.syncope.core.provisioning.api.Connector;
45  import org.apache.syncope.core.provisioning.api.pushpull.GroupPullResultHandler;
46  import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
47  import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
48  import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
49  import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullResultHandler;
50  import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePullExecutor;
51  import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
52  import org.apache.syncope.core.provisioning.java.utils.TemplateUtils;
53  import org.identityconnectors.framework.common.objects.ObjectClass;
54  import org.quartz.JobExecutionException;
55  import org.springframework.beans.factory.annotation.Autowired;
56  
57  public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSinglePullExecutor {
58  
59      @Autowired
60      protected ImplementationDAO implementationDAO;
61  
62      @Autowired
63      protected RealmDAO realmDAO;
64  
65      @Override
66      public List<ProvisioningReport> pull(
67              final ExternalResource resource,
68              final Provision provision,
69              final Connector connector,
70              final ReconFilterBuilder reconFilterBuilder,
71              final Set<String> moreAttrsToGet,
72              final PullTaskTO pullTaskTO,
73              final String executor) throws JobExecutionException {
74  
75          LOG.debug("Executing pull on {}", resource);
76  
77          taskType = TaskType.PULL;
78          try {
79              task = entityFactory.newEntity(PullTask.class);
80              task.setResource(resource);
81              task.setMatchingRule(pullTaskTO.getMatchingRule() == null
82                      ? MatchingRule.UPDATE : pullTaskTO.getMatchingRule());
83              task.setUnmatchingRule(pullTaskTO.getUnmatchingRule() == null
84                      ? UnmatchingRule.PROVISION : pullTaskTO.getUnmatchingRule());
85              task.setPullMode(PullMode.FILTERED_RECONCILIATION);
86              task.setPerformCreate(pullTaskTO.isPerformCreate());
87              task.setPerformUpdate(pullTaskTO.isPerformUpdate());
88              task.setPerformDelete(pullTaskTO.isPerformDelete());
89              task.setSyncStatus(pullTaskTO.isSyncStatus());
90              task.setDestinationRealm(realmDAO.findByFullPath(pullTaskTO.getDestinationRealm()));
91              task.setRemediation(pullTaskTO.isRemediation());
92  
93              // validate JEXL expressions from templates and proceed if fine
94              TemplateUtils.check(pullTaskTO.getTemplates(), ClientExceptionType.InvalidPullTask);
95              pullTaskTO.getTemplates().forEach((type, template) -> {
96                  AnyType anyType = anyTypeDAO.find(type);
97                  if (anyType == null) {
98                      LOG.debug("Invalid AnyType {} specified, ignoring...", type);
99                  } else {
100                     AnyTemplatePullTask anyTemplate = task.getTemplate(anyType.getKey()).orElse(null);
101                     if (anyTemplate == null) {
102                         anyTemplate = entityFactory.newEntity(AnyTemplatePullTask.class);
103                         anyTemplate.setAnyType(anyType);
104                         anyTemplate.setPullTask(task);
105 
106                         task.add(anyTemplate);
107                     }
108                     anyTemplate.set(template);
109                 }
110             });
111 
112             profile = new ProvisioningProfile<>(connector, task);
113             profile.setDryRun(false);
114             profile.setConflictResolutionAction(ConflictResolutionAction.FIRSTMATCH);
115             profile.getActions().addAll(getPullActions(pullTaskTO.getActions().stream().
116                     map(implementationDAO::find).filter(Objects::nonNull).collect(Collectors.toList())));
117             profile.setExecutor(executor);
118 
119             for (PullActions action : profile.getActions()) {
120                 action.beforeAll(profile);
121             }
122 
123             AnyType anyType = anyTypeDAO.find(provision.getAnyType());
124 
125             SyncopePullResultHandler handler;
126             GroupPullResultHandler ghandler = buildGroupHandler();
127             switch (anyType.getKind()) {
128                 case USER:
129                     handler = buildUserHandler();
130                     break;
131 
132                 case GROUP:
133                     handler = ghandler;
134                     break;
135 
136                 case ANY_OBJECT:
137                 default:
138                     handler = buildAnyObjectHandler();
139             }
140             handler.setProfile(profile);
141 
142             // execute filtered pull
143             Set<String> matg = new HashSet<>(moreAttrsToGet);
144             profile.getActions().forEach(a -> matg.addAll(a.moreAttrsToGet(profile, provision)));
145 
146             Stream<Item> mapItems = Stream.concat(
147                     MappingUtils.getPullItems(provision.getMapping().getItems().stream()),
148                     virSchemaDAO.find(task.getResource().getKey(), anyType.getKey()).stream().
149                             map(VirSchema::asLinkingMappingItem));
150 
151             connector.filteredReconciliation(
152                     new ObjectClass(provision.getObjectClass()),
153                     reconFilterBuilder,
154                     handler,
155                     MappingUtils.buildOperationOptions(mapItems, matg.toArray(String[]::new)));
156 
157             try {
158                 setGroupOwners(ghandler);
159             } catch (Exception e) {
160                 LOG.error("While setting group owners", e);
161             }
162 
163             for (PullActions action : profile.getActions()) {
164                 action.afterAll(profile);
165             }
166 
167             return profile.getResults();
168         } catch (Exception e) {
169             throw e instanceof JobExecutionException
170                     ? (JobExecutionException) e
171                     : new JobExecutionException("While pulling from connector", e);
172         } finally {
173             setStatus(null);
174         }
175     }
176 }