blob: 8fe2fe4cec752ca0db2e1bc75f6ecdad87a7aeef [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.syncope.core.logic;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.Attr;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.ConnObjectTO;
import org.apache.syncope.common.lib.to.EntityTO;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.to.ReconStatus;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.MatchType;
import org.apache.syncope.common.rest.api.beans.CSVPullSpec;
import org.apache.syncope.core.persistence.api.dao.AnyDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
import org.apache.syncope.core.provisioning.api.MappingManager;
import org.apache.syncope.core.provisioning.api.VirAttrHandler;
import org.apache.syncope.common.lib.to.ProvisioningReport;
import org.apache.syncope.common.lib.types.AnyEntitlement;
import org.apache.syncope.common.lib.types.IdMEntitlement;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.syncope.common.rest.api.beans.AbstractCSVSpec;
import org.apache.syncope.common.rest.api.beans.CSVPushSpec;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.provisioning.api.ConnectorManager;
import org.apache.syncope.core.provisioning.api.pushpull.ConstantReconFilterBuilder;
import org.apache.syncope.core.provisioning.api.pushpull.KeyValueReconFilterBuilder;
import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePullExecutor;
import org.apache.syncope.core.provisioning.java.pushpull.stream.CSVStreamConnector;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePushExecutor;
import org.apache.syncope.core.provisioning.api.pushpull.stream.SyncopeStreamPullExecutor;
import org.apache.syncope.core.provisioning.java.pushpull.InboundMatcher;
import org.apache.syncope.core.provisioning.java.pushpull.OutboundMatcher;
import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.ConnectorObject;
import org.apache.syncope.core.provisioning.api.pushpull.stream.SyncopeStreamPushExecutor;
import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
import org.apache.syncope.core.provisioning.java.pushpull.SinglePullJobDelegate;
import org.apache.syncope.core.provisioning.java.pushpull.SinglePushJobDelegate;
import org.apache.syncope.core.provisioning.java.pushpull.stream.StreamPullJobDelegate;
import org.apache.syncope.core.provisioning.java.pushpull.stream.StreamPushJobDelegate;
import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.SearchResult;
import org.identityconnectors.framework.common.objects.SyncDeltaBuilder;
import org.identityconnectors.framework.common.objects.SyncDeltaType;
import org.identityconnectors.framework.common.objects.SyncToken;
import org.identityconnectors.framework.common.objects.Uid;
import org.identityconnectors.framework.common.objects.filter.Filter;
import org.identityconnectors.framework.spi.SearchResultsHandler;
import org.quartz.JobExecutionException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.transaction.annotation.Transactional;
public class ReconciliationLogic extends AbstractTransactionalLogic<EntityTO> {
protected final AnyUtilsFactory anyUtilsFactory;
protected final AnyTypeDAO anyTypeDAO;
protected final ExternalResourceDAO resourceDAO;
protected final RealmDAO realmDAO;
protected final PlainSchemaDAO plainSchemaDAO;
protected final DerSchemaDAO derSchemaDAO;
protected final VirSchemaDAO virSchemaDAO;
protected final AnySearchDAO anySearchDAO;
protected final VirAttrHandler virAttrHandler;
protected final MappingManager mappingManager;
protected final InboundMatcher inboundMatcher;
protected final OutboundMatcher outboundMatcher;
protected final ConnectorManager connectorManager;
public ReconciliationLogic(
final AnyUtilsFactory anyUtilsFactory,
final AnyTypeDAO anyTypeDAO,
final ExternalResourceDAO resourceDAO,
final RealmDAO realmDAO,
final PlainSchemaDAO plainSchemaDAO,
final DerSchemaDAO derSchemaDAO,
final VirSchemaDAO virSchemaDAO,
final AnySearchDAO anySearchDAO,
final VirAttrHandler virAttrHandler,
final MappingManager mappingManager,
final InboundMatcher inboundMatcher,
final OutboundMatcher outboundMatcher,
final ConnectorManager connectorManager) {
this.anyUtilsFactory = anyUtilsFactory;
this.anyTypeDAO = anyTypeDAO;
this.resourceDAO = resourceDAO;
this.realmDAO = realmDAO;
this.plainSchemaDAO = plainSchemaDAO;
this.derSchemaDAO = derSchemaDAO;
this.virSchemaDAO = virSchemaDAO;
this.anySearchDAO = anySearchDAO;
this.virAttrHandler = virAttrHandler;
this.mappingManager = mappingManager;
this.inboundMatcher = inboundMatcher;
this.outboundMatcher = outboundMatcher;
this.connectorManager = connectorManager;
}
protected Provision getProvision(final String anyTypeKey, final String resourceKey) {
AnyType anyType = anyTypeDAO.find(anyTypeKey);
if (anyType == null) {
throw new NotFoundException("AnyType '" + anyTypeKey + "'");
}
ExternalResource resource = resourceDAO.find(resourceKey);
if (resource == null) {
throw new NotFoundException("Resource '" + resourceKey + "'");
}
Provision provision = resource.getProvision(anyType).
orElseThrow(() -> new NotFoundException(
"Provision for " + anyType + " on Resource '" + resourceKey + "'"));
if (provision.getMapping() == null) {
throw new NotFoundException("Mapping for " + anyType + " on Resource '" + resourceKey + "'");
}
return provision;
}
protected ConnObjectTO getOnSyncope(
final MappingItem connObjectKeyItem,
final String connObjectKeyValue,
final Set<Attribute> attrs) {
ConnObjectTO connObjectTO = ConnObjectUtils.getConnObjectTO(null, attrs);
connObjectTO.getAttrs().add(new Attr.Builder(connObjectKeyItem.getExtAttrName()).
value(connObjectKeyValue).build());
connObjectTO.getAttrs().add(new Attr.Builder(Uid.NAME).
value(connObjectKeyValue).build());
return connObjectTO;
}
protected ConnObjectTO getOnSyncope(
final Any<?> any,
final MappingItem connObjectKeyItem,
final Provision provision) {
Pair<String, Set<Attribute>> prepared = mappingManager.prepareAttrsFromAny(
any, null, false, true, provision);
return getOnSyncope(connObjectKeyItem, prepared.getLeft(), prepared.getRight());
}
protected ConnObjectTO getOnSyncope(
final LinkedAccount account,
final MappingItem connObjectKeyItem,
final Provision provision) {
Set<Attribute> attrs = mappingManager.prepareAttrsFromLinkedAccount(
account.getOwner(), account, null, false, provision);
return getOnSyncope(connObjectKeyItem, account.getConnObjectKeyValue(), attrs);
}
protected Any<?> getAny(final Provision provision, final String anyKey) {
AnyDAO<Any<?>> dao = anyUtilsFactory.getInstance(provision.getAnyType().getKind()).dao();
Any<?> any = SyncopeConstants.UUID_PATTERN.matcher(anyKey).matches()
? dao.authFind(anyKey)
: dao.authFind(dao.findKey(anyKey));
if (any == null) {
throw new NotFoundException(provision.getAnyType().getKey() + " '" + anyKey + "'");
}
return any;
}
@PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')")
public ReconStatus status(
final String anyTypeKey,
final String resourceKey,
final String anyKey,
final Set<String> moreAttrsToGet) {
Provision provision = getProvision(anyTypeKey, resourceKey);
MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision).
orElseThrow(() -> new NotFoundException(
"ConnObjectKey for " + provision.getAnyType().getKey()
+ " on resource '" + provision.getResource().getKey() + "'"));
Any<?> any = getAny(provision, anyKey);
ReconStatus status = new ReconStatus();
status.setMatchType(MatchType.ANY);
status.setAnyTypeKind(any.getType().getKind());
status.setAnyKey(any.getKey());
status.setRealm(any.getRealm().getFullPath());
status.setOnSyncope(getOnSyncope(any, connObjectKeyItem, provision));
List<ConnectorObject> connObjs = outboundMatcher.match(connectorManager.getConnector(
provision.getResource()), any, provision, Optional.of(moreAttrsToGet.toArray(new String[] {})));
if (!connObjs.isEmpty()) {
status.setOnResource(ConnObjectUtils.getConnObjectTO(
outboundMatcher.getFIQL(connObjs.get(0), provision), connObjs.get(0).getAttributes()));
if (connObjs.size() > 1) {
LOG.warn("Expected single match, found {}", connObjs);
} else {
virAttrHandler.setValues(any, connObjs.get(0));
}
}
return status;
}
protected SyncDeltaBuilder syncDeltaBuilder(
final Provision provision,
final Filter filter,
final Set<String> moreAttrsToGet) {
Stream<MappingItem> mapItems = Stream.concat(
provision.getMapping().getItems().stream(),
virSchemaDAO.findByProvision(provision).stream().map(VirSchema::asLinkingMappingItem));
OperationOptions options = MappingUtils.buildOperationOptions(mapItems, moreAttrsToGet.toArray(new String[0]));
SyncDeltaBuilder syncDeltaBuilder = new SyncDeltaBuilder().
setToken(new SyncToken("")).
setDeltaType(SyncDeltaType.CREATE_OR_UPDATE).
setObjectClass(provision.getObjectClass());
connectorManager.getConnector(provision.getResource()).
search(provision.getObjectClass(), filter, new SearchResultsHandler() {
@Override
public boolean handle(final ConnectorObject connObj) {
syncDeltaBuilder.setObject(connObj);
return false;
}
@Override
public void handleResult(final SearchResult sr) {
// do nothing
}
}, 1, null, List.of(), options);
return syncDeltaBuilder;
}
@PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')")
public ReconStatus status(
final String anyTypeKey,
final String resourceKey,
final Filter filter,
final Set<String> moreAttrsToGet) {
Provision provision = getProvision(anyTypeKey, resourceKey);
SyncDeltaBuilder syncDeltaBuilder = syncDeltaBuilder(provision, filter, moreAttrsToGet);
ReconStatus status = new ReconStatus();
if (syncDeltaBuilder.getObject() != null) {
MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision).
orElseThrow(() -> new NotFoundException(
"ConnObjectKey for " + provision.getAnyType().getKey()
+ " on resource '" + provision.getResource().getKey() + "'"));
inboundMatcher.match(syncDeltaBuilder.build(), provision).stream().findFirst().ifPresent(match -> {
if (match.getAny() != null) {
status.setMatchType(MatchType.ANY);
status.setAnyTypeKind(match.getAny().getType().getKind());
status.setAnyKey(match.getAny().getKey());
status.setRealm(match.getAny().getRealm().getFullPath());
status.setOnSyncope(getOnSyncope(match.getAny(), connObjectKeyItem, provision));
} else if (match.getLinkedAccount() != null) {
status.setMatchType(MatchType.LINKED_ACCOUNT);
status.setAnyTypeKind(AnyTypeKind.USER);
status.setAnyKey(match.getLinkedAccount().getOwner().getKey());
status.setRealm(match.getLinkedAccount().getOwner().getRealm().getFullPath());
status.setOnSyncope(getOnSyncope(match.getLinkedAccount(), connObjectKeyItem, provision));
}
});
status.setOnResource(ConnObjectUtils.getConnObjectTO(
outboundMatcher.getFIQL(syncDeltaBuilder.getObject(), provision),
syncDeltaBuilder.getObject().getAttributes()));
if (status.getMatchType() == MatchType.ANY && StringUtils.isNotBlank(status.getAnyKey())) {
virAttrHandler.setValues(getAny(provision, status.getAnyKey()), syncDeltaBuilder.getObject());
}
}
return status;
}
protected SyncopeSinglePushExecutor singlePushExecutor() {
return (SyncopeSinglePushExecutor) ApplicationContextProvider.getBeanFactory().
createBean(SinglePushJobDelegate.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.TASK_EXECUTE + "')")
public List<ProvisioningReport> push(
final String anyTypeKey,
final String resourceKey,
final String anyKey,
final PushTaskTO pushTask) {
Provision provision = getProvision(anyTypeKey, resourceKey);
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
List<ProvisioningReport> results = new ArrayList<>();
try {
results.addAll(singlePushExecutor().push(
provision,
connectorManager.getConnector(provision.getResource()),
getAny(provision, anyKey),
pushTask,
AuthContextUtils.getUsername()));
if (!results.isEmpty() && results.get(0).getStatus() == ProvisioningReport.Status.FAILURE) {
sce.getElements().add(results.get(0).getMessage());
}
} catch (JobExecutionException e) {
sce.getElements().add(e.getMessage());
}
if (!sce.isEmpty()) {
throw sce;
}
return results;
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.TASK_EXECUTE + "')")
public List<ProvisioningReport> push(
final String anyTypeKey,
final String resourceKey,
final Filter filter,
final Set<String> moreAttrsToGet,
final PushTaskTO pushTask) {
Provision provision = getProvision(anyTypeKey, resourceKey);
SyncDeltaBuilder syncDeltaBuilder = syncDeltaBuilder(provision, filter, moreAttrsToGet);
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
List<ProvisioningReport> results = new ArrayList<>();
if (syncDeltaBuilder.getObject() != null) {
inboundMatcher.match(syncDeltaBuilder.build(), provision).stream().findFirst().ifPresent(match -> {
try {
if (match.getMatchTarget() == MatchType.ANY) {
results.addAll(singlePushExecutor().push(
provision,
connectorManager.getConnector(provision.getResource()),
match.getAny(),
pushTask,
AuthContextUtils.getUsername()));
if (!results.isEmpty() && results.get(0).getStatus() == ProvisioningReport.Status.FAILURE) {
sce.getElements().add(results.get(0).getMessage());
}
} else {
ProvisioningReport result = singlePushExecutor().push(
provision,
connectorManager.getConnector(provision.getResource()),
match.getLinkedAccount(),
pushTask,
AuthContextUtils.getUsername());
if (result.getStatus() == ProvisioningReport.Status.FAILURE) {
sce.getElements().add(result.getMessage());
} else {
results.add(result);
}
}
} catch (JobExecutionException e) {
sce.getElements().add(e.getMessage());
}
});
}
if (!sce.isEmpty()) {
throw sce;
}
return results;
}
protected List<ProvisioningReport> pull(
final Provision provision,
final ReconFilterBuilder reconFilterBuilder,
final Set<String> moreAttrsToGet,
final PullTaskTO pullTask) {
if (pullTask.getDestinationRealm() == null || realmDAO.findByFullPath(pullTask.getDestinationRealm()) == null) {
throw new NotFoundException("Realm " + pullTask.getDestinationRealm());
}
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
List<ProvisioningReport> results = new ArrayList<>();
try {
SyncopeSinglePullExecutor executor =
(SyncopeSinglePullExecutor) ApplicationContextProvider.getBeanFactory().
createBean(SinglePullJobDelegate.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
results.addAll(executor.pull(
provision,
connectorManager.getConnector(provision.getResource()),
reconFilterBuilder,
moreAttrsToGet,
pullTask));
if (!results.isEmpty() && results.get(0).getStatus() == ProvisioningReport.Status.FAILURE) {
sce.getElements().add(results.get(0).getMessage());
}
} catch (JobExecutionException e) {
sce.getElements().add(e.getMessage());
}
if (!sce.isEmpty()) {
throw sce;
}
return results;
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.TASK_EXECUTE + "')")
@Transactional(noRollbackFor = SyncopeClientException.class)
public List<ProvisioningReport> pull(
final String anyTypeKey,
final String resourceKey,
final String anyKey,
final Set<String> moreAttrsToGet,
final PullTaskTO pullTask) {
Provision provision = getProvision(anyTypeKey, resourceKey);
Any<?> any = getAny(provision, anyKey);
if (provision.getMapping().getConnObjectKeyItem().isEmpty()) {
throw new NotFoundException(
"ConnObjectKey cannot be determined for mapping " + provision.getMapping().getKey());
}
String connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, provision).
orElseThrow(() -> new NotFoundException(
"ConnObjectKey for " + provision.getAnyType().getKey()
+ " on resource '" + provision.getResource().getKey() + "'"));
return pull(
provision,
new KeyValueReconFilterBuilder(
provision.getMapping().getConnObjectKeyItem().get().getExtAttrName(), connObjectKeyValue),
moreAttrsToGet,
pullTask);
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.TASK_EXECUTE + "')")
@Transactional(noRollbackFor = SyncopeClientException.class)
public List<ProvisioningReport> pull(
final String anyTypeKey,
final String resourceKey,
final Filter filter,
final Set<String> moreAttrsToGet,
final PullTaskTO pullTask) {
Provision provision = getProvision(anyTypeKey, resourceKey);
return pull(
provision,
new ConstantReconFilterBuilder(filter),
moreAttrsToGet,
pullTask);
}
protected CsvSchema.Builder csvSchema(final AbstractCSVSpec spec) {
CsvSchema.Builder schemaBuilder = new CsvSchema.Builder().setUseHeader(true).
setColumnSeparator(spec.getColumnSeparator()).
setArrayElementSeparator(spec.getArrayElementSeparator()).
setQuoteChar(spec.getQuoteChar()).
setLineSeparator(spec.getLineSeparator()).
setNullValue(spec.getNullValue()).
setAllowComments(spec.isAllowComments());
if (spec.getEscapeChar() != null) {
schemaBuilder.setEscapeChar(spec.getEscapeChar());
}
return schemaBuilder;
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.TASK_EXECUTE + "')")
public List<ProvisioningReport> push(
final SearchCond searchCond,
final int page,
final int size,
final List<OrderByClause> orderBy,
final String realm,
final CSVPushSpec spec,
final OutputStream os) {
AnyType anyType = anyTypeDAO.find(spec.getAnyTypeKey());
if (anyType == null) {
throw new NotFoundException("AnyType '" + spec.getAnyTypeKey() + "'");
}
AnyUtils anyUtils = anyUtilsFactory.getInstance(anyType.getKind());
String entitlement;
switch (anyType.getKind()) {
case GROUP:
entitlement = IdRepoEntitlement.GROUP_SEARCH;
break;
case ANY_OBJECT:
entitlement = AnyEntitlement.SEARCH.getFor(anyType.getKey());
break;
case USER:
default:
entitlement = IdRepoEntitlement.USER_SEARCH;
}
Set<String> adminRealms = RealmUtils.getEffective(AuthContextUtils.getAuthorizations().get(entitlement), realm);
SearchCond effectiveCond = searchCond == null ? anyUtils.dao().getAllMatchingCond() : searchCond;
List<Any<?>> matching;
if (spec.getIgnorePaging()) {
matching = new ArrayList<>();
int count = anySearchDAO.count(adminRealms, effectiveCond, anyType.getKind());
int pages = (count / AnyDAO.DEFAULT_PAGE_SIZE) + 1;
for (int p = 1; p <= pages; p++) {
matching.addAll(anySearchDAO.search(adminRealms, effectiveCond,
p, AnyDAO.DEFAULT_PAGE_SIZE, orderBy, anyType.getKind()));
}
} else {
matching = anySearchDAO.search(adminRealms, effectiveCond, page, size, orderBy, anyType.getKind());
}
List<String> columns = new ArrayList<>();
spec.getFields().forEach(item -> {
if (anyUtils.getField(item) == null) {
LOG.warn("Ignoring invalid field {}", item);
} else {
columns.add(item);
}
});
spec.getPlainAttrs().forEach(item -> {
if (plainSchemaDAO.find(item) == null) {
LOG.warn("Ignoring invalid plain schema {}", item);
} else {
columns.add(item);
}
});
spec.getDerAttrs().forEach(item -> {
if (derSchemaDAO.find(item) == null) {
LOG.warn("Ignoring invalid derived schema {}", item);
} else {
columns.add(item);
}
});
spec.getVirAttrs().forEach(item -> {
if (virSchemaDAO.find(item) == null) {
LOG.warn("Ignoring invalid virtual schema {}", item);
} else {
columns.add(item);
}
});
PushTaskTO pushTask = new PushTaskTO();
pushTask.setMatchingRule(spec.getMatchingRule());
pushTask.setUnmatchingRule(spec.getUnmatchingRule());
pushTask.getActions().addAll(spec.getProvisioningActions());
try (CSVStreamConnector connector = new CSVStreamConnector(
null,
spec.getArrayElementSeparator(),
csvSchema(spec),
null,
os,
columns.toArray(new String[columns.size()]))) {
SyncopeStreamPushExecutor executor =
(SyncopeStreamPushExecutor) ApplicationContextProvider.getBeanFactory().
createBean(StreamPushJobDelegate.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
return executor.push(
anyType,
matching,
columns,
connector,
spec.getPropagationActions(),
pushTask,
AuthContextUtils.getUsername());
} catch (Exception e) {
LOG.error("Could not push to stream", e);
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
sce.getElements().add(e.getMessage());
throw sce;
}
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.TASK_EXECUTE + "')")
@Transactional(noRollbackFor = SyncopeClientException.class)
public List<ProvisioningReport> pull(final CSVPullSpec spec, final InputStream csv) {
AnyType anyType = anyTypeDAO.find(spec.getAnyTypeKey());
if (anyType == null) {
throw new NotFoundException("AnyType '" + spec.getAnyTypeKey() + "'");
}
if (realmDAO.findByFullPath(spec.getDestinationRealm()) == null) {
throw new NotFoundException("Realm " + spec.getDestinationRealm());
}
PullTaskTO pullTask = new PullTaskTO();
pullTask.setDestinationRealm(spec.getDestinationRealm());
pullTask.setRemediation(spec.isRemediation());
pullTask.setMatchingRule(spec.getMatchingRule());
pullTask.setUnmatchingRule(spec.getUnmatchingRule());
pullTask.getActions().addAll(spec.getProvisioningActions());
try (CSVStreamConnector connector = new CSVStreamConnector(
spec.getKeyColumn(),
spec.getArrayElementSeparator(),
csvSchema(spec),
csv,
null)) {
List<String> columns = connector.getColumns(spec);
if (!columns.contains(spec.getKeyColumn())) {
throw new NotFoundException("Key column '" + spec.getKeyColumn() + "'");
}
SyncopeStreamPullExecutor executor =
(SyncopeStreamPullExecutor) ApplicationContextProvider.getBeanFactory().
createBean(StreamPullJobDelegate.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
return executor.pull(anyType,
spec.getKeyColumn(),
columns,
spec.getConflictResolutionAction(),
spec.getPullCorrelationRule(),
connector,
pullTask);
} catch (NotFoundException e) {
throw e;
} catch (Exception e) {
LOG.error("Could not pull from stream", e);
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
sce.getElements().add(e.getMessage());
throw sce;
}
}
@Override
protected EntityTO resolveReference(final Method method, final Object... os)
throws UnresolvedReferenceException {
throw new UnresolvedReferenceException();
}
}