blob: 5b230286680102d4885d35e4274e8ff13b780098 [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.provisioning.java.data;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.syncope.core.provisioning.api.data.TaskDataBinder;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.to.ProvisioningTaskTO;
import org.apache.syncope.common.lib.to.TaskTO;
import org.apache.syncope.common.lib.to.PropagationTaskTO;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.to.SchedTaskTO;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.to.ExecTO;
import org.apache.syncope.common.lib.to.NotificationTaskTO;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.IdRepoImplementationType;
import org.apache.syncope.common.lib.types.ImplementationEngine;
import org.apache.syncope.common.lib.types.JobType;
import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.TaskType;
import org.apache.syncope.common.lib.types.UnmatchingRule;
import org.apache.syncope.core.provisioning.java.utils.TemplateUtils;
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.TaskExecDAO;
import org.apache.syncope.core.persistence.api.entity.task.NotificationTask;
import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
import org.apache.syncope.core.persistence.api.entity.task.PushTask;
import org.apache.syncope.core.persistence.api.entity.task.SchedTask;
import org.apache.syncope.core.persistence.api.entity.task.Task;
import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
import org.apache.syncope.core.persistence.api.entity.task.TaskUtils;
import org.apache.syncope.core.provisioning.api.job.JobNamer;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.Entity;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.task.AnyTemplatePullTask;
import org.apache.syncope.core.persistence.api.entity.task.PullTask;
import org.apache.syncope.core.provisioning.java.pushpull.PushJobDelegate;
import org.apache.syncope.core.provisioning.java.pushpull.PullJobDelegate;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.apache.syncope.core.persistence.api.entity.task.PushTaskAnyFilter;
import org.apache.syncope.core.persistence.api.entity.task.TaskUtilsFactory;
public class TaskDataBinderImpl implements TaskDataBinder {
protected static final Logger LOG = LoggerFactory.getLogger(TaskDataBinder.class);
protected final RealmDAO realmDAO;
protected final ExternalResourceDAO resourceDAO;
protected final TaskExecDAO taskExecDAO;
protected final AnyTypeDAO anyTypeDAO;
protected final ImplementationDAO implementationDAO;
protected final EntityFactory entityFactory;
protected final SchedulerFactoryBean scheduler;
protected final TaskUtilsFactory taskUtilsFactory;
public TaskDataBinderImpl(
final RealmDAO realmDAO,
final ExternalResourceDAO resourceDAO,
final TaskExecDAO taskExecDAO,
final AnyTypeDAO anyTypeDAO,
final ImplementationDAO implementationDAO,
final EntityFactory entityFactory,
final SchedulerFactoryBean scheduler,
final TaskUtilsFactory taskUtilsFactory) {
this.realmDAO = realmDAO;
this.resourceDAO = resourceDAO;
this.taskExecDAO = taskExecDAO;
this.anyTypeDAO = anyTypeDAO;
this.implementationDAO = implementationDAO;
this.entityFactory = entityFactory;
this.scheduler = scheduler;
this.taskUtilsFactory = taskUtilsFactory;
}
protected void fill(final ProvisioningTask provisioningTask, final ProvisioningTaskTO provisioningTaskTO) {
if (provisioningTask instanceof PushTask && provisioningTaskTO instanceof PushTaskTO) {
PushTask pushTask = (PushTask) provisioningTask;
PushTaskTO pushTaskTO = (PushTaskTO) provisioningTaskTO;
Implementation jobDelegate = pushTaskTO.getJobDelegate() == null
? implementationDAO.findByType(IdRepoImplementationType.TASKJOB_DELEGATE).stream().
filter(impl -> PushJobDelegate.class.getName().equals(impl.getBody())).
findFirst().orElse(null)
: implementationDAO.find(pushTaskTO.getJobDelegate());
if (jobDelegate == null) {
jobDelegate = entityFactory.newEntity(Implementation.class);
jobDelegate.setKey(PushJobDelegate.class.getSimpleName());
jobDelegate.setEngine(ImplementationEngine.JAVA);
jobDelegate.setType(IdRepoImplementationType.TASKJOB_DELEGATE);
jobDelegate.setBody(PushJobDelegate.class.getName());
jobDelegate = implementationDAO.save(jobDelegate);
}
pushTask.setJobDelegate(jobDelegate);
pushTask.setSourceRealm(realmDAO.findByFullPath(pushTaskTO.getSourceRealm()));
pushTask.setMatchingRule(pushTaskTO.getMatchingRule() == null
? MatchingRule.LINK : pushTaskTO.getMatchingRule());
pushTask.setUnmatchingRule(pushTaskTO.getUnmatchingRule() == null
? UnmatchingRule.ASSIGN : pushTaskTO.getUnmatchingRule());
pushTaskTO.getFilters().forEach((type, fiql) -> {
AnyType anyType = anyTypeDAO.find(type);
if (anyType == null) {
LOG.debug("Invalid AnyType {} specified, ignoring...", type);
} else {
PushTaskAnyFilter filter = pushTask.getFilter(anyType).orElse(null);
if (filter == null) {
filter = entityFactory.newEntity(PushTaskAnyFilter.class);
filter.setAnyType(anyType);
filter.setPushTask(pushTask);
pushTask.add(filter);
}
filter.setFIQLCond(fiql);
}
});
// remove all filters not contained in the TO
pushTask.getFilters().
removeIf(anyFilter -> !pushTaskTO.getFilters().containsKey(anyFilter.getAnyType().getKey()));
} else if (provisioningTask instanceof PullTask && provisioningTaskTO instanceof PullTaskTO) {
PullTask pullTask = (PullTask) provisioningTask;
PullTaskTO pullTaskTO = (PullTaskTO) provisioningTaskTO;
Implementation jobDelegate = pullTaskTO.getJobDelegate() == null
? implementationDAO.findByType(IdRepoImplementationType.TASKJOB_DELEGATE).stream().
filter(impl -> PullJobDelegate.class.getName().equals(impl.getBody())).
findFirst().orElse(null)
: implementationDAO.find(pullTaskTO.getJobDelegate());
if (jobDelegate == null) {
jobDelegate = entityFactory.newEntity(Implementation.class);
jobDelegate.setKey(PullJobDelegate.class.getSimpleName());
jobDelegate.setEngine(ImplementationEngine.JAVA);
jobDelegate.setType(IdRepoImplementationType.TASKJOB_DELEGATE);
jobDelegate.setBody(PullJobDelegate.class.getName());
jobDelegate = implementationDAO.save(jobDelegate);
}
pullTask.setJobDelegate(jobDelegate);
pullTask.setPullMode(pullTaskTO.getPullMode());
if (pullTaskTO.getReconFilterBuilder() == null) {
pullTask.setReconFilterBuilder(null);
} else {
Implementation reconFilterBuilder = implementationDAO.find(pullTaskTO.getReconFilterBuilder());
if (reconFilterBuilder == null) {
LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...",
pullTaskTO.getReconFilterBuilder());
} else {
pullTask.setReconFilterBuilder(reconFilterBuilder);
}
}
pullTask.setDestinationRealm(realmDAO.findByFullPath(pullTaskTO.getDestinationRealm()));
pullTask.setMatchingRule(pullTaskTO.getMatchingRule() == null
? MatchingRule.UPDATE : pullTaskTO.getMatchingRule());
pullTask.setUnmatchingRule(pullTaskTO.getUnmatchingRule() == null
? UnmatchingRule.PROVISION : pullTaskTO.getUnmatchingRule());
// validate JEXL expressions from templates and proceed if fine
TemplateUtils.check(pullTaskTO.getTemplates(), ClientExceptionType.InvalidPullTask);
pullTaskTO.getTemplates().forEach((type, template) -> {
AnyType anyType = anyTypeDAO.find(type);
if (anyType == null) {
LOG.debug("Invalid AnyType {} specified, ignoring...", type);
} else {
AnyTemplatePullTask anyTemplate = pullTask.getTemplate(anyType).orElse(null);
if (anyTemplate == null) {
anyTemplate = entityFactory.newEntity(AnyTemplatePullTask.class);
anyTemplate.setAnyType(anyType);
anyTemplate.setPullTask(pullTask);
pullTask.add(anyTemplate);
}
anyTemplate.set(template);
}
});
// remove all templates not contained in the TO
pullTask.getTemplates().
removeIf(anyTemplate -> !pullTaskTO.getTemplates().containsKey(anyTemplate.getAnyType().getKey()));
pullTask.setRemediation(pullTaskTO.isRemediation());
}
// 3. fill the remaining fields
provisioningTask.setPerformCreate(provisioningTaskTO.isPerformCreate());
provisioningTask.setPerformUpdate(provisioningTaskTO.isPerformUpdate());
provisioningTask.setPerformDelete(provisioningTaskTO.isPerformDelete());
provisioningTask.setSyncStatus(provisioningTaskTO.isSyncStatus());
provisioningTaskTO.getActions().forEach(action -> {
Implementation implementation = implementationDAO.find(action);
if (implementation == null) {
LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", action);
} else {
provisioningTask.add(implementation);
}
});
// remove all implementations not contained in the TO
provisioningTask.getActions().removeIf(impl -> !provisioningTaskTO.getActions().contains(impl.getKey()));
}
@Override
public SchedTask createSchedTask(final SchedTaskTO taskTO, final TaskUtils taskUtils) {
Class<? extends TaskTO> taskTOClass = taskUtils.taskTOClass();
if (taskTOClass == null || !taskTOClass.equals(taskTO.getClass())) {
throw new IllegalArgumentException(String.format("Expected %s, found %s", taskTOClass, taskTO.getClass()));
}
SchedTask task = taskUtils.newTask();
task.setStartAt(taskTO.getStartAt());
task.setCronExpression(taskTO.getCronExpression());
task.setName(taskTO.getName());
task.setDescription(taskTO.getDescription());
task.setActive(taskTO.isActive());
if (taskUtils.getType() == TaskType.SCHEDULED) {
Implementation implementation = implementationDAO.find(taskTO.getJobDelegate());
if (implementation == null) {
throw new NotFoundException("Implementation " + taskTO.getJobDelegate());
}
task.setJobDelegate(implementation);
} else if (taskTO instanceof ProvisioningTaskTO) {
ProvisioningTaskTO provisioningTaskTO = (ProvisioningTaskTO) taskTO;
ExternalResource resource = resourceDAO.find(provisioningTaskTO.getResource());
if (resource == null) {
throw new NotFoundException("Resource " + provisioningTaskTO.getResource());
}
((ProvisioningTask) task).setResource(resource);
fill((ProvisioningTask) task, provisioningTaskTO);
}
return task;
}
@Override
public void updateSchedTask(final SchedTask task, final SchedTaskTO taskTO, final TaskUtils taskUtils) {
Class<? extends TaskTO> taskTOClass = taskUtils.taskTOClass();
if (taskTOClass == null || !taskTOClass.equals(taskTO.getClass())) {
throw new IllegalArgumentException(String.format("Expected %s, found %s", taskTOClass, taskTO.getClass()));
}
if (StringUtils.isBlank(taskTO.getName())) {
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
sce.getElements().add("name");
throw sce;
}
task.setName(taskTO.getName());
task.setDescription(taskTO.getDescription());
task.setCronExpression(taskTO.getCronExpression());
task.setActive(taskTO.isActive());
if (task instanceof ProvisioningTask) {
fill((ProvisioningTask) task, (ProvisioningTaskTO) taskTO);
}
}
@Override
public String buildRefDesc(final Task task) {
return taskUtilsFactory.getInstance(task).getType().name() + ' '
+ "Task "
+ task.getKey() + ' '
+ (task instanceof SchedTask
? SchedTask.class.cast(task).getName()
: task instanceof PropagationTask
? PropagationTask.class.cast(task).getConnObjectKey()
: StringUtils.EMPTY);
}
@Override
public ExecTO getExecTO(final TaskExec execution) {
ExecTO execTO = new ExecTO();
execTO.setKey(execution.getKey());
execTO.setStatus(execution.getStatus());
execTO.setMessage(execution.getMessage());
execTO.setStart(execution.getStart());
execTO.setEnd(execution.getEnd());
execTO.setExecutor(execution.getExecutor());
if (execution.getTask() != null && execution.getTask().getKey() != null) {
execTO.setJobType(JobType.TASK);
execTO.setRefKey(execution.getTask().getKey());
execTO.setRefDesc(buildRefDesc(execution.getTask()));
}
return execTO;
}
protected void fill(final SchedTaskTO schedTaskTO, final SchedTask schedTask) {
schedTaskTO.setName(schedTask.getName());
schedTaskTO.setDescription(schedTask.getDescription());
schedTaskTO.setCronExpression(schedTask.getCronExpression());
schedTaskTO.setActive(schedTask.isActive());
schedTaskTO.setLastExec(schedTaskTO.getStart());
String triggerName = JobNamer.getTriggerName(JobNamer.getJobKey(schedTask).getName());
try {
Trigger trigger = scheduler.getScheduler().getTrigger(new TriggerKey(triggerName, Scheduler.DEFAULT_GROUP));
if (trigger != null) {
schedTaskTO.setLastExec(trigger.getPreviousFireTime());
schedTaskTO.setNextExec(trigger.getNextFireTime());
}
} catch (SchedulerException e) {
LOG.warn("While trying to get to " + triggerName, e);
}
if (schedTaskTO instanceof ProvisioningTaskTO && schedTask instanceof ProvisioningTask) {
ProvisioningTaskTO provisioningTaskTO = (ProvisioningTaskTO) schedTaskTO;
ProvisioningTask provisioningTask = (ProvisioningTask) schedTask;
provisioningTaskTO.setResource(provisioningTask.getResource().getKey());
provisioningTaskTO.getActions().addAll(
provisioningTask.getActions().stream().map(Entity::getKey).collect(Collectors.toList()));
provisioningTaskTO.setPerformCreate(provisioningTask.isPerformCreate());
provisioningTaskTO.setPerformUpdate(provisioningTask.isPerformUpdate());
provisioningTaskTO.setPerformDelete(provisioningTask.isPerformDelete());
provisioningTaskTO.setSyncStatus(provisioningTask.isSyncStatus());
}
}
@Override
public <T extends TaskTO> T getTaskTO(final Task task, final TaskUtils taskUtils, final boolean details) {
T taskTO = taskUtils.newTaskTO();
taskTO.setKey(task.getKey());
TaskExec latestExec = taskExecDAO.findLatestStarted(task);
if (latestExec == null) {
taskTO.setLatestExecStatus(StringUtils.EMPTY);
} else {
taskTO.setLatestExecStatus(latestExec.getStatus());
taskTO.setStart(latestExec.getStart());
taskTO.setEnd(latestExec.getEnd());
taskTO.setLastExecutor(latestExec.getExecutor());
}
if (details) {
task.getExecs().stream().
filter(Objects::nonNull).
forEach(execution -> taskTO.getExecutions().add(getExecTO(execution)));
}
switch (taskUtils.getType()) {
case PROPAGATION:
PropagationTask propagationTask = (PropagationTask) task;
PropagationTaskTO propagationTaskTO = (PropagationTaskTO) taskTO;
propagationTaskTO.setOperation(propagationTask.getOperation());
propagationTaskTO.setConnObjectKey(propagationTask.getConnObjectKey());
propagationTaskTO.setOldConnObjectKey(propagationTask.getOldConnObjectKey());
propagationTaskTO.setAttributes(propagationTask.getSerializedAttributes());
propagationTaskTO.setResource(propagationTask.getResource().getKey());
propagationTaskTO.setObjectClassName(propagationTask.getObjectClassName());
propagationTaskTO.setAnyTypeKind(propagationTask.getAnyTypeKind());
propagationTaskTO.setAnyType(propagationTask.getAnyType());
propagationTaskTO.setEntityKey(propagationTask.getEntityKey());
break;
case SCHEDULED:
SchedTask schedTask = (SchedTask) task;
SchedTaskTO schedTaskTO = (SchedTaskTO) taskTO;
fill(schedTaskTO, schedTask);
if (schedTask.getJobDelegate() != null) {
schedTaskTO.setJobDelegate(schedTask.getJobDelegate().getKey());
}
break;
case PULL:
PullTask pullTask = (PullTask) task;
PullTaskTO pullTaskTO = (PullTaskTO) taskTO;
fill(pullTaskTO, pullTask);
pullTaskTO.setDestinationRealm(pullTask.getDestinationRealm().getFullPath());
pullTaskTO.setMatchingRule(pullTask.getMatchingRule() == null
? MatchingRule.UPDATE : pullTask.getMatchingRule());
pullTaskTO.setUnmatchingRule(pullTask.getUnmatchingRule() == null
? UnmatchingRule.PROVISION : pullTask.getUnmatchingRule());
pullTaskTO.setPullMode(pullTask.getPullMode());
if (pullTask.getReconFilterBuilder() != null) {
pullTaskTO.setReconFilterBuilder(pullTask.getReconFilterBuilder().getKey());
}
pullTask.getTemplates().
forEach(template -> pullTaskTO.getTemplates().
put(template.getAnyType().getKey(), template.get()));
pullTaskTO.setRemediation(pullTask.isRemediation());
break;
case PUSH:
PushTask pushTask = (PushTask) task;
PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
fill(pushTaskTO, pushTask);
pushTaskTO.setSourceRealm(pushTask.getSourceRealm().getFullPath());
pushTaskTO.setMatchingRule(pushTask.getMatchingRule() == null
? MatchingRule.LINK : pushTask.getMatchingRule());
pushTaskTO.setUnmatchingRule(pushTask.getUnmatchingRule() == null
? UnmatchingRule.ASSIGN : pushTask.getUnmatchingRule());
pushTask.getFilters().
forEach(filter -> pushTaskTO.getFilters().
put(filter.getAnyType().getKey(), filter.getFIQLCond()));
break;
case NOTIFICATION:
NotificationTask notificationTask = (NotificationTask) task;
NotificationTaskTO notificationTaskTO = (NotificationTaskTO) taskTO;
notificationTaskTO.setNotification(notificationTask.getNotification().getKey());
notificationTaskTO.setAnyTypeKind(notificationTask.getAnyTypeKind());
notificationTaskTO.setEntityKey(notificationTask.getEntityKey());
notificationTaskTO.setSender(notificationTask.getSender());
notificationTaskTO.getRecipients().addAll(notificationTask.getRecipients());
notificationTaskTO.setSubject(notificationTask.getSubject());
notificationTaskTO.setHtmlBody(notificationTask.getHtmlBody());
notificationTaskTO.setTextBody(notificationTask.getTextBody());
notificationTaskTO.setExecuted(notificationTask.isExecuted());
if (notificationTask.isExecuted() && StringUtils.isBlank(taskTO.getLatestExecStatus())) {
taskTO.setLatestExecStatus("[EXECUTED]");
}
notificationTaskTO.setTraceLevel(notificationTask.getTraceLevel());
break;
default:
}
return taskTO;
}
}