/*
* Copyright (c) 2010-2017 Evolveum
*
* Licensed 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 com.evolveum.midpoint.notifications.impl.notifiers;
import com.evolveum.midpoint.model.api.ProgressInformation;
import com.evolveum.midpoint.model.common.expression.Expression;
import com.evolveum.midpoint.model.common.expression.ExpressionEvaluationContext;
import com.evolveum.midpoint.model.common.expression.ExpressionVariables;
import com.evolveum.midpoint.model.impl.expr.ModelExpressionThreadLocalHolder;
import com.evolveum.midpoint.notifications.api.NotificationManager;
import com.evolveum.midpoint.notifications.api.events.Event;
import com.evolveum.midpoint.notifications.api.events.ModelEvent;
import com.evolveum.midpoint.notifications.api.transports.Message;
import com.evolveum.midpoint.notifications.api.transports.Transport;
import com.evolveum.midpoint.notifications.impl.NotificationFunctionsImpl;
import com.evolveum.midpoint.notifications.impl.api.transports.CustomTransport;
import com.evolveum.midpoint.notifications.impl.formatters.TextFormatter;
import com.evolveum.midpoint.notifications.impl.handlers.AggregatedEventHandler;
import com.evolveum.midpoint.notifications.impl.handlers.BaseHandler;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.PrismPropertyDefinitionImpl;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.ExpressionEvaluationException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CustomNotifierType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.EventHandlerType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.NotificationMessageType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static com.evolveum.midpoint.model.api.ProgressInformation.ActivityType.NOTIFICATIONS;
import static com.evolveum.midpoint.model.api.ProgressInformation.StateType.ENTERING;
/**
* @author mederly
*/
@Component
public class CustomNotifier extends BaseHandler {
private static final Trace DEFAULT_LOGGER = TraceManager.getTrace(CustomNotifier.class);
@Autowired
protected NotificationManager notificationManager;
@Autowired
protected NotificationFunctionsImpl notificationsUtil;
@Autowired
protected TextFormatter textFormatter;
@Autowired
protected AggregatedEventHandler aggregatedEventHandler;
@Autowired
private CustomTransport customTransport;
@PostConstruct
public void init() {
register(CustomNotifierType.class);
}
@Override
public boolean processEvent(Event event, EventHandlerType eventHandlerType, NotificationManager notificationManager,
Task task, OperationResult parentResult) throws SchemaException {
OperationResult result = parentResult.createSubresult(CustomNotifier.class.getName() + ".processEvent");
logStart(getLogger(), event, eventHandlerType);
boolean applies = aggregatedEventHandler.processEvent(event, eventHandlerType, notificationManager, task, result);
if (applies) {
CustomNotifierType config = (CustomNotifierType) eventHandlerType;
ExpressionVariables variables = getDefaultVariables(event, result);
if (event instanceof ModelEvent) {
((ModelEvent) event).getModelContext().reportProgress(new ProgressInformation(NOTIFICATIONS, ENTERING));
}
List<String> transports = new ArrayList<>(config.getTransport());
if (transports.isEmpty()) {
transports.add(customTransport.getName());
}
try {
for (String transportName : config.getTransport()) {
variables.addVariableDefinition(SchemaConstants.C_TRANSPORT_NAME, transportName);
Transport transport = notificationManager.getTransport(transportName);
Message message = getMessageFromExpression(config, variables, task, result);
if (message != null) {
getLogger().trace("Sending notification via transport {}:\n{}", transportName, message);
transport.send(message, transportName, event, task, result);
} else {
getLogger().debug("No message for transport {}, won't send anything", transportName);
}
}
} finally {
if (event instanceof ModelEvent) {
((ModelEvent) event).getModelContext().reportProgress(
new ProgressInformation(NOTIFICATIONS, result));
}
}
}
logEnd(getLogger(), event, eventHandlerType, applies);
result.computeStatusIfUnknown();
return true; // not-applicable notifiers do not stop processing of other notifiers
}
protected Trace getLogger() {
return DEFAULT_LOGGER; // in case a subclass does not provide its own logger
}
private Message getMessageFromExpression(CustomNotifierType config, ExpressionVariables variables,
Task task, OperationResult result) {
if (config.getExpression() == null) {
return null;
}
List<NotificationMessageType> messages;
try {
messages = evaluateExpression(config.getExpression(), variables,
"message expression", task, result);
} catch (ObjectNotFoundException|SchemaException|ExpressionEvaluationException e) {
throw new SystemException("Couldn't evaluate custom notifier expression: " + e.getMessage(), e);
}
if (messages == null || messages.isEmpty()) {
return null;
} else if (messages.size() > 1) {
getLogger().warn("Custom notifier returned more than one message: {}", messages);
}
return messages.get(0) != null ? new Message(messages.get(0)) : null;
}
private List<NotificationMessageType> evaluateExpression(ExpressionType expressionType, ExpressionVariables expressionVariables,
String shortDesc, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException,
ExpressionEvaluationException {
QName resultName = new QName(SchemaConstants.NS_C, "result");
PrismPropertyDefinition<NotificationMessageType> resultDef =
new PrismPropertyDefinitionImpl<>(resultName, NotificationMessageType.COMPLEX_TYPE, prismContext);
Expression<PrismPropertyValue<NotificationMessageType>,PrismPropertyDefinition<NotificationMessageType>> expression =
expressionFactory.makeExpression(expressionType, resultDef, shortDesc, task, result);
ExpressionEvaluationContext params = new ExpressionEvaluationContext(null, expressionVariables, shortDesc, task, result);
PrismValueDeltaSetTriple<PrismPropertyValue<NotificationMessageType>> exprResult = ModelExpressionThreadLocalHolder
.evaluateExpressionInContext(expression, params, task, result);
return exprResult.getZeroSet().stream().map(PrismPropertyValue::getValue).collect(Collectors.toList());
}
@Override
protected ExpressionVariables getDefaultVariables(Event event, OperationResult result) {
ExpressionVariables variables = super.getDefaultVariables(event, result);
variables.addVariableDefinition(SchemaConstants.C_TEXT_FORMATTER, textFormatter);
return variables;
}
}