/*
* Copyright (c) 2010-2013 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.api.events;
import com.evolveum.midpoint.model.api.context.ModelContext;
import com.evolveum.midpoint.model.api.context.ModelElementContext;
import com.evolveum.midpoint.model.api.context.ModelProjectionContext;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.delta.ChangeType;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.ObjectDeltaOperation;
import com.evolveum.midpoint.task.api.LightweightIdentifierGenerator;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.EventCategoryType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.EventOperationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.EventStatusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import org.apache.commons.lang.StringUtils;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author mederly
*/
public class ModelEvent extends BaseEvent {
private static final Trace LOGGER = TraceManager.getTrace(ModelEvent.class);
// we can expect that modelContext != null and focus context != null as well
private ModelContext modelContext;
public ModelEvent(LightweightIdentifierGenerator lightweightIdentifierGenerator) {
super(lightweightIdentifierGenerator);
}
public ModelContext getModelContext() {
return modelContext;
}
public ModelElementContext getFocusContext() {
return modelContext.getFocusContext();
}
public Collection<ModelElementContext> getProjectionContexts() {
return modelContext.getProjectionContexts();
}
public void setModelContext(ModelContext modelContext) {
this.modelContext = modelContext;
}
public List<? extends ObjectDeltaOperation> getFocusExecutedDeltas() {
return getFocusContext().getExecutedDeltas();
}
public List<ObjectDeltaOperation> getAllExecutedDeltas() {
List<ObjectDeltaOperation> retval = new ArrayList<ObjectDeltaOperation>();
retval.addAll(getFocusContext().getExecutedDeltas());
for (Object o : modelContext.getProjectionContexts()) {
ModelProjectionContext modelProjectionContext = (ModelProjectionContext) o;
retval.addAll(modelProjectionContext.getExecutedDeltas());
}
return retval;
}
@Override
public boolean isStatusType(EventStatusType eventStatusType) {
boolean allSuccess = true, anySuccess = false, allFailure = true, anyFailure = false, anyInProgress = false;
for (ObjectDeltaOperation objectDeltaOperation : getAllExecutedDeltas()) {
if (objectDeltaOperation.getExecutionResult() != null) {
switch (objectDeltaOperation.getExecutionResult().getStatus()) {
case SUCCESS: anySuccess = true; allFailure = false; break;
case FATAL_ERROR: allSuccess = false; anyFailure = true; break;
case WARNING: anySuccess = true; allFailure = false; break;
case HANDLED_ERROR: anySuccess = true; allFailure = false; break;
case IN_PROGRESS: allSuccess = false; allFailure = false; anyInProgress = true; break;
case NOT_APPLICABLE: break;
case PARTIAL_ERROR: allSuccess = false; anyFailure = true; break;
case UNKNOWN: allSuccess = false; allFailure = false; break;
default: LOGGER.warn("Unknown execution result: " + objectDeltaOperation.getExecutionResult().getStatus());
}
} else {
allSuccess = false; allFailure = false; anyInProgress = true;
}
}
switch (eventStatusType) {
case ALSO_SUCCESS: return anySuccess;
case SUCCESS: return allSuccess;
case FAILURE: return anyFailure;
case ONLY_FAILURE: return allFailure;
case IN_PROGRESS: return anyInProgress;
default: throw new IllegalStateException("Invalid eventStatusType: " + eventStatusType);
}
}
// a bit of hack but ...
public ChangeType getChangeType() {
if (isOperationType(EventOperationType.ADD)) {
return ChangeType.ADD;
} else if (isOperationType(EventOperationType.DELETE)) {
return ChangeType.DELETE;
} else {
return ChangeType.MODIFY;
}
}
@Override
public boolean isOperationType(EventOperationType eventOperationType) {
// we consider an operation to be 'add' when there is 'add' delta among deltas
// in a similar way with 'delete'
//
// alternatively, we could summarize deltas and then decide based on the type of summarized delta (would be a bit inefficient)
for (Object o : getFocusExecutedDeltas()) {
ObjectDeltaOperation objectDeltaOperation = (ObjectDeltaOperation) o;
if (objectDeltaOperation.getObjectDelta().isAdd()) {
return eventOperationType == EventOperationType.ADD;
} else if (objectDeltaOperation.getObjectDelta().isDelete()) {
return eventOperationType == EventOperationType.DELETE;
}
}
return eventOperationType == EventOperationType.MODIFY;
}
@Override
public boolean isCategoryType(EventCategoryType eventCategoryType) {
return eventCategoryType == EventCategoryType.MODEL_EVENT;
}
public List<ObjectDelta<FocusType>> getFocusDeltas() {
List<ObjectDelta<FocusType>> retval = new ArrayList<>();
Class c = modelContext.getFocusClass();
if (c != null && FocusType.class.isAssignableFrom(c)) {
for (Object o : getFocusExecutedDeltas()) {
ObjectDeltaOperation objectDeltaOperation = (ObjectDeltaOperation) o;
retval.add(objectDeltaOperation.getObjectDelta());
}
}
return retval;
}
public ObjectDelta<? extends FocusType> getSummarizedFocusDeltas() throws SchemaException {
return ObjectDelta.summarize(getFocusDeltas());
}
public boolean hasFocusOfType(Class<? extends FocusType> clazz) {
return getFocusContext() != null && clazz.isAssignableFrom(getFocusContext().getObjectTypeClass());
}
public boolean hasFocusOfType(QName focusType) {
PrismContext prismContext = getModelContext().getPrismContext();
if (prismContext == null) {
throw new IllegalStateException("No prismContext in model context");
}
PrismContainerDefinition pcd = prismContext.getSchemaRegistry().findContainerDefinitionByType(focusType);
if (pcd == null) {
LOGGER.warn("Couldn't find definition for type " + focusType);
return false;
}
Class expectedClass = pcd.getCompileTimeClass();
if (expectedClass == null) {
LOGGER.warn("Couldn't find class for type " + focusType);
return false;
}
return hasFocusOfType(expectedClass);
}
@Override
public boolean isRelatedToItem(ItemPath itemPath) {
return containsItem(getFocusDeltas(), itemPath);
}
@Override
public boolean isUserRelated() {
return hasFocusOfType(UserType.class);
}
public String getFocusTypeName() {
if (getFocusContext() == null || getFocusContext().getObjectTypeClass() == null) {
return null;
}
String simpleName = getFocusContext().getObjectTypeClass().getSimpleName();
return StringUtils.substringBeforeLast(simpleName, "Type"); // should usually work ;)
}
public String getContentAsFormattedList() {
return getContentAsFormattedList(false, false);
}
public String getContentAsFormattedList(boolean showSynchronizationItems, boolean showAuxiliaryAttributes) {
return getNotificationFunctions().getContentAsFormattedList(this, showSynchronizationItems, showAuxiliaryAttributes);
}
}