/*
* Copyright 2013 JBoss Inc
*
* 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 org.overlord.rtgov.ui.provider.situations;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.tryFind;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.overlord.commons.services.ServiceRegistryUtil;
import org.overlord.rtgov.active.collection.ActiveChangeListener;
import org.overlord.rtgov.active.collection.ActiveCollection;
import org.overlord.rtgov.active.collection.ActiveCollectionListener;
import org.overlord.rtgov.active.collection.ActiveCollectionManager;
import org.overlord.rtgov.active.collection.ActiveCollectionManagerAccessor;
import org.overlord.rtgov.active.collection.ActiveList;
import org.overlord.rtgov.activity.model.ActivityType;
import org.overlord.rtgov.activity.model.ActivityTypeId;
import org.overlord.rtgov.activity.model.ActivityUnit;
import org.overlord.rtgov.activity.model.Context;
import org.overlord.rtgov.activity.model.soa.RPCActivityType;
import org.overlord.rtgov.activity.server.ActivityServer;
import org.overlord.rtgov.activity.server.ActivityStore;
import org.overlord.rtgov.activity.server.ActivityStoreFactory;
import org.overlord.rtgov.activity.server.QuerySpec;
import org.overlord.rtgov.analytics.situation.Situation;
import org.overlord.rtgov.ui.client.model.ResolutionState;
import org.overlord.rtgov.analytics.situation.store.SituationStore;
import org.overlord.rtgov.analytics.situation.store.SituationStoreFactory;
import org.overlord.rtgov.analytics.situation.store.SituationsQuery;
import org.overlord.rtgov.call.trace.CallTraceService;
import org.overlord.rtgov.call.trace.CallTraceServiceImpl;
import org.overlord.rtgov.call.trace.model.Call;
import org.overlord.rtgov.call.trace.model.CallTrace;
import org.overlord.rtgov.call.trace.model.Task;
import org.overlord.rtgov.call.trace.model.TraceNode;
import org.overlord.rtgov.common.util.RTGovProperties;
import org.overlord.rtgov.ui.client.model.BatchRetryResult;
import org.overlord.rtgov.ui.client.model.CallTraceBean;
import org.overlord.rtgov.ui.client.model.MessageBean;
import org.overlord.rtgov.ui.client.model.SituationBean;
import org.overlord.rtgov.ui.client.model.SituationEventBean;
import org.overlord.rtgov.ui.client.model.SituationSummaryBean;
import org.overlord.rtgov.ui.client.model.SituationsFilterBean;
import org.overlord.rtgov.ui.client.model.TraceNodeBean;
import org.overlord.rtgov.ui.client.model.UiException;
import org.overlord.rtgov.ui.provider.ResubmitActionProvider;
import org.overlord.rtgov.ui.provider.ServicesProvider;
import org.overlord.rtgov.ui.provider.SituationEventListener;
import org.overlord.rtgov.ui.provider.SituationsProvider;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
/**
* Concrete implementation of the faults service using RTGov situations.
*
*/
public class RTGovSituationsProvider implements SituationsProvider, ActiveChangeListener {
private static final String PROVIDER_NAME = "rtgov"; //$NON-NLS-1$
// Active collection name
private static final String SITUATIONS = "Situations"; //$NON-NLS-1$
protected static final int MILLISECONDS_PER_DAY = 86400000;
private static volatile Messages i18n = new Messages();
private CallTraceService _callTraceService=new CallTraceServiceImpl();
private ActivityStore _activityStore;
private SituationStore _situationStore;
private java.util.Set<ServicesProvider> _providers=null;
private java.util.List<SituationEventListener> _listeners=new java.util.ArrayList<SituationEventListener>();
private ActiveList _situations;
private ActiveCollectionManager _acmManager;
/**
* Constructor.
*/
public RTGovSituationsProvider() {
}
/**
* This method returns the set of services providers.
*
* @return The providers
*/
protected java.util.Set<ServicesProvider> getProviders() {
return (_providers);
}
/**
* This method sets the activity store.
*
* @param acts The activity store
*/
protected void setActivityStore(ActivityStore acts) {
_activityStore = acts;
}
/**
* This method returns the activity store.
*
* @return The activity store
*/
protected ActivityStore getActivityStore() {
return (_activityStore);
}
/**
* This method sets the situation store.
*
* @param sits The situation store
*/
protected void setSituationStore(SituationStore sits) {
_situationStore = sits;
}
/**
* This method returns the situation store.
*
* @return The situation store
*/
protected SituationStore getSituationStore() {
return (_situationStore);
}
/**
* This method sets the call trace service.
*
* @param cts The call trace service
*/
protected void setCallTraceService(CallTraceService cts) {
_callTraceService = cts;
}
/**
* This method returns the call trace service.
*
* @return The call trace service
*/
protected CallTraceService getCallTraceService() {
return (_callTraceService);
}
/**
* This method sets the situations active list.
*
* @param cts The situations active list
*/
protected void setSituations(ActiveList situations) {
_situations = situations;
}
/**
* This method returns the situations active list.
*
* @return The situations active list
*/
protected ActiveList getSituations() {
return (_situations);
}
@PostConstruct
public void init() {
if (_activityStore == null) {
_activityStore = ActivityStoreFactory.getActivityStore();
}
if (_situationStore == null) {
_situationStore = SituationStoreFactory.getSituationStore();
}
_providers = ServiceRegistryUtil.getServices(ServicesProvider.class);
if (_callTraceService != null) {
// Overwrite any existing activity server to ensure using the
// same activity store as the situations provider
_callTraceService.setActivityServer(new ActivityServerAdapter());
}
if (_situations == null) {
_acmManager = ActiveCollectionManagerAccessor.getActiveCollectionManager();
_acmManager.addActiveCollectionListener(new ActiveCollectionListener() {
@Override
public void registered(ActiveCollection ac) {
if (ac.getName().equals(SITUATIONS)) {
synchronized (SITUATIONS) {
if (_situations == null) {
_situations = (ActiveList)ac;
_situations.addActiveChangeListener(RTGovSituationsProvider.this);
}
}
}
}
@Override
public void unregistered(ActiveCollection ac) {
}
});
}
// TEMPORARY WORKAROUND: Currently hen active collection listener is registered, existing
// collections are not notified to the listener, thus potentially causing a situation where
// a collection may be missed if registered prior to the listener being established (RTGOV-286).
synchronized (SITUATIONS) {
if (_situations == null) {
_situations = (ActiveList)_acmManager.getActiveCollection(SITUATIONS);
}
if (_situations != null) {
_situations.addActiveChangeListener(RTGovSituationsProvider.this);
}
}
}
/**
* {@inheritDoc}
*/
public String getName() {
return PROVIDER_NAME;
}
/**
* {@inheritDoc}
*/
public void addSituationEventListener(SituationEventListener l) {
synchronized (_listeners) {
_listeners.add(l);
}
}
/**
* {@inheritDoc}
*/
public void removeSituationEventListener(SituationEventListener l) {
synchronized (_listeners) {
_listeners.remove(l);
}
}
/**
* This method fires the situation event to any registered listeners.
*
* @param event The situation event
*/
protected void fireSituationEvent(SituationEventBean event) {
synchronized (_listeners) {
for (int i=0; i < _listeners.size(); i++) {
_listeners.get(i).onSituationEvent(event);
}
}
}
/**
* {@inheritDoc}
*/
public java.util.List<SituationSummaryBean> search(SituationsFilterBean filters) throws UiException {
ArrayList<SituationSummaryBean> situations = new ArrayList<SituationSummaryBean>();
try {
java.util.List<Situation> results=querySituations(filters);
for (Situation item : results) {
// Check if only root nodes, and if so filter out situations that
// have been resubmitted
if (!filters.isRootOnly()
|| !item.getProperties().containsKey(Situation.RESUBMITTED_SITUATION_ID)) {
SituationSummaryBean ssb=RTGovSituationsUtil.getSituationBean(item);
// Identify resubmission failures
java.util.List<Situation> resubmitted=getResubmittedSituations(item.getId(), true);
ssb.setResubmissionFailureTotalCount(resubmitted.size());
situations.add(ssb);
}
}
} catch (Exception e) {
throw new UiException(e);
}
return (situations);
}
/**
* This method creates a query from the supplied filter.
*
* @param filter The filter
* @return The query
*/
protected static SituationsQuery createQuery(SituationsFilterBean filters) {
SituationsQuery ret=new SituationsQuery();
ret.setType(filters.getType());
if (filters.getSeverity() != null && filters.getSeverity().trim().length() > 0) {
String severityName=Character.toUpperCase(filters.getSeverity().charAt(0))
+filters.getSeverity().substring(1);
ret.setSeverity(Situation.Severity.valueOf(severityName));
}
if (filters.getTimestampFrom() != null) {
ret.setFromTimestamp(filters.getTimestampFrom().getTime());
}
if (filters.getTimestampTo() != null) {
ret.setToTimestamp(filters.getTimestampTo().getTime());
}
ret.setDescription(filters.getDescription());
ret.setResolutionState(filters.getResolutionState());
ret.setSubject(filters.getSubject());
try {
ret.setProperties(filters.getProperties());
} catch (IOException ioException) {
Throwables.propagate(ioException);
}
return (ret);
}
/**
* {@inheritDoc}
*/
@Override
public SituationBean getSituation(String situationId) throws UiException {
SituationBean ret=null;
try {
Situation situation=_situationStore.getSituation(situationId);
if (situation == null) {
throw new UiException(i18n.format("RTGovSituationsProvider.SitNotFound", situationId)); //$NON-NLS-1$
}
ret = RTGovSituationsUtil.getSituationBean(situation);
MessageBean message = getMessage(situation);
ret.setMessage(message);
CallTraceBean callTrace = getCallTrace(situation);
ret.setCallTrace(callTrace);
// Check if other situations have been created based on the
// resubmission of this situation's message
java.util.List<Situation> resubmits=getResubmittedSituations(situationId, true);
ret.setResubmissionFailureTotalCount(resubmits.size());
// If resubmit situations exist OR the situation is RESOLVED,
// then resubmit of this situation is not possible
if (resubmits.size() == 0
&& !ret.getResolutionState().equalsIgnoreCase(ResolutionState.RESOLVED.name())) {
ret.setResubmitPossible(any(_providers, new IsResubmitSupported(situation)));
}
ret.setManualResolutionPossible(RTGovProperties.getPropertyAsBoolean("UI.manualResolution",
Boolean.TRUE));
} catch (UiException uie) {
throw uie;
} catch (Exception e) {
throw new UiException("Failed to retrieve situation", e); //$NON-NLS-1$
}
return (ret);
}
/**
* This method returns the resubmitted situations.
*
* @param situationId The parent situation id
* @param deep Whether to traverse the tree (true) or just return the immediate child situations (false)
* @return The list of resubmitted situations
*/
protected java.util.List<Situation> getResubmittedSituations(String situationId, boolean deep) {
java.util.List<Situation> results=new java.util.ArrayList<Situation>();
queryResubmittedSituations(situationId, deep, results);
return (results);
}
/**
* This method queries the situation store to obtain situations resubmitted
* by the situation associated with the supplied id.
*
* @param situationId The parent situation id
* @param deep Whether this should be done recursively
* @param results The list of situations
*/
protected void queryResubmittedSituations(String situationId, boolean deep,
java.util.List<Situation> results) {
SituationsQuery query=new SituationsQuery();
query.getProperties().put(Situation.RESUBMITTED_SITUATION_ID, situationId);
java.util.List<Situation> resubmitted=_situationStore.getSituations(query);
for (Situation sit : resubmitted) {
// Need to double check id, as fuzzy 'like' used when retrieving situations based on
// properties to enable partial strings to be provided.
if (!sit.getSituationProperties().containsKey(Situation.RESUBMITTED_SITUATION_ID)
|| !sit.getSituationProperties().get(Situation.RESUBMITTED_SITUATION_ID)
.equals(situationId)) {
continue;
}
if (!results.contains(sit)) {
results.add(sit);
if (deep) {
queryResubmittedSituations(sit.getId(), deep, results);
}
}
}
}
/**
* This method checks whether a request message exists for the supplied
* situation and if so, returns a MessageBean to represent it's content.
*
* @param situation The situation
* @return The message, or null if not found
* @throws UiException Failed to get message
*/
protected MessageBean getMessage(Situation situation) throws UiException {
MessageBean ret=null;
for (ActivityTypeId id : situation.getActivityTypeIds()) {
try {
ActivityType at=null;
ActivityUnit au=_activityStore.getActivityUnit(id.getUnitId());
if (au != null && id.getUnitIndex() < au.getActivityTypes().size()) {
at = au.getActivityTypes().get(id.getUnitIndex());
}
if (at instanceof RPCActivityType && ((RPCActivityType)at).isRequest()
&& ((RPCActivityType)at).getContent() != null) {
ret = new MessageBean();
ret.setContent(((RPCActivityType)at).getContent());
// Handle header properties that need to be copied over
configureHeaders(ret, at);
// Associate principal with the message
ret.setPrincipal(((RPCActivityType)at).getPrincipal());
if (ret.getPrincipal() == null && au.getOrigin() != null) {
ret.setPrincipal(au.getOrigin().getPrincipal());
}
break;
}
} catch (Exception e) {
throw new UiException("Failed to get message for activity type id '"+id+"'", e);
}
}
return (ret);
}
/**
* This method copies the header properties from the activity type into the message
* bean.
*
* @param mb Messag bean
* @param at The activity type
*/
protected static void configureHeaders(MessageBean mb, ActivityType at) throws UiException {
if (at != null) {
for (String key : at.getProperties().keySet()) {
if (isHeaderFormatProperty(key)) {
String format=at.getProperties().get(key);
String propName=getPropertyName(key);
if (format != null) {
mb.getHeaders().put(propName, at.getProperties().get(propName));
mb.getHeaderFormats().put(propName, format);
}
}
}
}
}
/**
* This method determines whether a property name represents a header property.
*
* @param headerName The property name
* @return Whether a header property
*/
protected static boolean isHeaderFormatProperty(String headerName) {
return (headerName.startsWith(ActivityType.HEADER_FORMAT_PROPERTY_PREFIX));
}
/**
* This method returns the property name associated with the header.
*
* @param headerName The property name
* @return The property name associated with the header name
*/
protected static String getPropertyName(String headerName) {
return (headerName.substring(ActivityType.HEADER_FORMAT_PROPERTY_PREFIX.length()));
}
/**
* This method retrieves the call trace for the supplied situation.
*
* @param situation The situation
* @return The call trace
*/
protected CallTraceBean getCallTrace(Situation situation) throws UiException {
CallTraceBean ret = new CallTraceBean();
// Obtain call trace
Context context=null;
for (Context c : situation.getContext()) {
if (c.getType() == Context.Type.Conversation) {
context = c;
break;
}
}
if (context == null && situation.getContext().size() > 0) {
// If no conversation context available, then use any other
context = situation.getContext().iterator().next();
}
if (context != null && _callTraceService != null) {
try {
CallTrace ct=_callTraceService.createCallTrace(context);
if (ct != null) {
for (TraceNode tn : ct.getTasks()) {
ret.getTasks().add(createTraceNode(tn));
}
}
} catch (Exception e) {
throw new UiException("Failed to get call trace for context '"+context+"'", e);
}
}
return (ret);
}
/**
* This method creates a UI bean from the supplied trace node.
*
* @param node The trace node
* @return The trace node bean
*/
protected TraceNodeBean createTraceNode(TraceNode node) {
TraceNodeBean ret=new TraceNodeBean();
ret.setType(node.getClass().getSimpleName());
ret.setStatus(node.getStatus().name());
if (node instanceof Task) {
Task task=(Task)node;
ret.setDescription(task.getDescription());
} else if (node instanceof Call) {
Call call=(Call)node;
ret.setIface(call.getInterface());
ret.setOperation(call.getOperation());
ret.setDuration(call.getDuration());
ret.setPercentage(call.getPercentage());
ret.setComponent(call.getComponent());
ret.setFault(call.getFault());
ret.setPrincipal(call.getPrincipal());
ret.setRequest(call.getRequest());
ret.setResponse(call.getResponse());
ret.setRequestLatency(call.getRequestLatency());
ret.setResponseLatency(call.getResponseLatency());
ret.setProperties(call.getProperties());
for (TraceNode child : call.getTasks()) {
ret.getTasks().add(createTraceNode(child));
}
}
return (ret);
}
/**
* @see org.overlord.rtgov.ui.server.services.ISituationsServiceImpl#resubmit(java.lang.String, java.lang.String)
*/
@Override
public void resubmit(String situationId, MessageBean message, String username) throws UiException {
Situation situation=_situationStore.getSituation(situationId);
if (situation == null) {
throw new UiException(i18n.format("RTGovSituationsProvider.SitNotFound", situationId)); //$NON-NLS-1$
}
resubmitInternal(situation, message, username);
}
private void resubmitInternal(Situation situation, MessageBean message, String username) throws UiException {
final ServiceOperationName operationName = getServiceOperationName(situation);
Optional<ServicesProvider> serviceProvider = tryFind(_providers, new IsResubmitSupported(
operationName));
if (!serviceProvider.isPresent()) {
throw new UiException(i18n.format("RTGovSituationsProvider.ResubmitProviderNotFound", situation.getId())); //$NON-NLS-1$
}
// RTGOV-649 If situation resolved, then should not allow resubmit
if (situation.getSituationProperties().containsKey(SituationStore.RESOLUTION_STATE_PROPERTY)
&& situation.getSituationProperties().get(SituationStore.RESOLUTION_STATE_PROPERTY)
.equalsIgnoreCase(ResolutionState.RESOLVED.name())) {
return;
}
// RTGOV-649 Assign situation to current user
if (!situation.getSituationProperties().containsKey(SituationStore.ASSIGNED_TO_PROPERTY)
|| !situation.getSituationProperties().get(SituationStore.ASSIGNED_TO_PROPERTY).equals(username)) {
assign(situation.getId(), username);
}
// RTGOV-649 Set resolution state to RESOLVED on the assumption that the resubmit will
// fix the problem. If an immediate exception is received, then set it back to IN_PROGRESS,
// and if a subsequent situation is reported, then it can also be set back to IN_PROGRESS.
updateResolutionState(situation.getId(), ResolutionState.RESOLVED);
// RTGOV-645 - include situation id, assignTo and resolutionState in resubmission, in case
// further failures (resulting in linked situations) occur.
message.getHeaders().put(Situation.RESUBMITTED_SITUATION_ID, situation.getId());
try {
ResubmitActionProvider resubmit=serviceProvider.get().getAction(ResubmitActionProvider.class);
if (resubmit == null) {
_situationStore.recordResubmitFailure(situation.getId(),
i18n.format("RTGovSituationsProvider.ResubmitNotSupported"), username);
} else {
resubmit.resubmit(operationName.getService(), operationName.getOperation(), message);
_situationStore.recordSuccessfulResubmit(situation.getId(), username);
}
} catch (Exception exception) {
// RTGOV-649 Set resolution state back to IN_PROGRESS
updateResolutionState(situation.getId(), ResolutionState.IN_PROGRESS);
_situationStore.recordResubmitFailure(situation.getId(),
Throwables.getStackTraceAsString(exception), username);
throw new UiException(
i18n.format(
"RTGovSituationsProvider.ResubmitFailed", situation.getId() + ":" + exception.getLocalizedMessage()), exception); //$NON-NLS-1$
}
}
@Override
public BatchRetryResult resubmit(SituationsFilterBean situationsFilterBean, String username) throws UiException {
int processedCount = 0, failedCount = 0, ignoredCount = 0;
List<Situation> situationIdToactivityTypeIds = querySituations(situationsFilterBean);
for (Situation situation : situationIdToactivityTypeIds) {
// RTGOV-649 If situation resolved, then should not allow resubmit
if (situation.getSituationProperties().containsKey(SituationStore.RESOLUTION_STATE_PROPERTY)
&& situation.getSituationProperties().get(SituationStore.RESOLUTION_STATE_PROPERTY)
.equalsIgnoreCase(ResolutionState.RESOLVED.name())) {
continue;
}
// Check if situation is root, and has resubmission failures
if (situationsFilterBean.isRootOnly()) {
java.util.List<Situation> resubmits=getResubmittedSituations(situation.getId(), true);
if (resubmits.size() > 0) {
situation = resubmits.get(resubmits.size()-1);
}
}
MessageBean message = getMessage(situation);
if (message == null) {
ignoredCount++;
continue;
}
try {
processedCount++;
resubmitInternal(situation, message, username);
} catch (UiException uiException) {
failedCount++;
}
}
return new BatchRetryResult(processedCount, failedCount, ignoredCount);
}
@Override
public java.util.List<SituationSummaryBean> getResubmitFailures(String situationId) throws UiException {
ArrayList<SituationSummaryBean> situations = new ArrayList<SituationSummaryBean>();
try {
java.util.List<Situation> results=getResubmittedSituations(situationId, true);
for (Situation item : results) {
SituationSummaryBean ssb=RTGovSituationsUtil.getSituationBean(item);
situations.add(ssb);
}
} catch (Exception e) {
throw new UiException(e);
}
return (situations);
}
@Override
public void export(SituationsFilterBean situationsFilterBean, OutputStream outputStream) {
List<Situation> situations = querySituations(situationsFilterBean);
PrintWriter printWriter = new PrintWriter(outputStream);
try {
for (Situation situation : situations) {
// Check if situation is root, and has resubmission failures
if (situationsFilterBean.isRootOnly()) {
java.util.List<Situation> resubmits=getResubmittedSituations(situation.getId(), true);
if (resubmits.size() > 0) {
situation = resubmits.get(resubmits.size()-1);
}
}
MessageBean message = getMessage(situation);
if (message == null) {
continue;
}
printWriter.println(message.getContent());
}
} catch (UiException uiException) {
Throwables.propagate(uiException);
} finally {
if (null != printWriter) {
printWriter.close();
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void inserted(Object key, Object value) {
if (value instanceof Situation) {
SituationEventBean event=RTGovSituationsUtil.getSituationEventBean((Situation)value);
fireSituationEvent(event);
}
}
/**
* {@inheritDoc}
*/
@Override
public void updated(Object key, Object value) {
}
/**
* {@inheritDoc}
*/
@Override
public void removed(Object key, Object value) {
}
/**
* This method returns the root situation associated with
* a resubmit hierarchy (i.e. where one situation is created
* as the result of a resubmission failure from a previous
* situation).
*
* @param situationId The situation id
* @return The root situation, or null if this situation does
* not have a resubmitted situation
*/
protected Situation getRootSituation(String situationId) throws UiException {
return (getRootSituation(_situationStore.getSituation(situationId)));
}
/**
* This method returns the root situation associated with
* a resubmit hierarchy (i.e. where one situation is created
* as the result of a resubmission failure from a previous
* situation).
*
* @param original The original situation
* @return The root situation, or null if this situation does
* not have a resubmitted situation
*/
protected Situation getRootSituation(Situation original) throws UiException {
Situation root=original;
if (original != null) {
String parentId=original.getProperties().get(Situation.RESUBMITTED_SITUATION_ID);
while (parentId != null) {
root = _situationStore.getSituation(parentId);
if (root == null) {
// Failed to retrieve parent situation
throw new UiException("Failed to locate parent situation");
}
parentId = root.getProperties().get(Situation.RESUBMITTED_SITUATION_ID);
}
}
return (root);
}
@Override
public void assign(String situationId, final String userName) throws UiException {
SituationsAction action=new SituationsAction() {
@Override
public void perform(Situation situation) throws Exception {
_situationStore.assignSituation(situation.getId(), userName);
}
};
Situation root=getRootSituation(situationId);
if (root != null) {
try {
performAction(root, action);
} catch (UiException uie) {
throw uie;
} catch (Exception e) {
throw new UiException(e);
}
}
}
@Override
public void unassign(String situationId) throws UiException {
SituationsAction action=new SituationsAction() {
@Override
public void perform(Situation situation) throws Exception {
_situationStore.unassignSituation(situation.getId());
}
};
Situation root=getRootSituation(situationId);
if (root != null) {
try {
performAction(root, action);
} catch (UiException uie) {
throw uie;
} catch (Exception e) {
throw new UiException(e);
}
}
}
@Override
public void updateResolutionState(String situationId, final ResolutionState resolutionState) throws UiException {
SituationsAction action=new SituationsAction() {
@Override
public void perform(Situation situation) throws Exception {
_situationStore.updateResolutionState(situation.getId(),
org.overlord.rtgov.analytics.situation.store.ResolutionState.valueOf(resolutionState.name()));
}
};
Situation root=getRootSituation(situationId);
if (root != null) {
try {
performAction(root, action);
} catch (UiException uie) {
throw uie;
} catch (Exception e) {
throw new UiException(e);
}
}
}
protected void performAction(Situation root, SituationsAction action) throws Exception {
action.perform(root);
// Check if situation has child situations
java.util.List<Situation> resubmitted=getResubmittedSituations(root.getId(), true);
for (Situation sit : resubmitted) {
action.perform(sit);
}
}
protected java.util.List<Situation> querySituations(SituationsFilterBean situationsFilterBean) {
SituationsQuery query=createQuery(situationsFilterBean);
java.util.List<Situation> results=_situationStore.getSituations(query);
// Check if only root situations should be returned
if (situationsFilterBean.isRootOnly()) {
for (int i=results.size()-1; i >= 0; i--) {
if (results.get(i).getProperties().containsKey(Situation.RESUBMITTED_SITUATION_ID)) {
results.remove(i);
}
}
}
return (results);
}
@Override
public int delete(SituationsFilterBean situationsFilterBean) throws UiException {
try {
final java.util.List<Situation> results=querySituations(situationsFilterBean);
final java.util.Set<Situation> deletions=new java.util.HashSet<Situation>();
for (Situation sit : results) {
Situation root=sit;
if (!situationsFilterBean.isRootOnly()) {
root = getRootSituation(sit);
}
deletions.add(root);
java.util.List<Situation> resubmitted=getResubmittedSituations(root.getId(), true);
deletions.addAll(resubmitted);
}
int count=0;
for (Situation sit : deletions) {
_situationStore.delete(sit);
count++;
}
return (count);
} catch (Exception e) {
throw new UiException(e);
}
}
/**
* This class provides a simple activity server adapter that passes requests
* through to the activity store.
*
*/
protected class ActivityServerAdapter implements ActivityServer {
/**
* {@inheritDoc}
*/
@Override
public void store(List<ActivityUnit> activities) throws Exception {
}
/**
* {@inheritDoc}
*/
@Override
public ActivityUnit getActivityUnit(String id) throws Exception {
return (_activityStore.getActivityUnit(id));
}
/**
* {@inheritDoc}
*/
@Override
public List<ActivityType> getActivityTypes(Context context)
throws Exception {
return (_activityStore.getActivityTypes(context));
}
/**
* {@inheritDoc}
*/
@Override
public List<ActivityType> getActivityTypes(Context context, long from,
long to) throws Exception {
return (_activityStore.getActivityTypes(context, from, to));
}
/**
* {@inheritDoc}
*/
@Override
public List<ActivityType> query(QuerySpec query) throws Exception {
return (_activityStore.query(query));
}
}
private static ServiceOperationName getServiceOperationName(Situation situation) throws UiException {
if (situation == null) {
throw new IllegalArgumentException("parameter 'situation' must not be null");
}
String parts[] = Strings.nullToEmpty(situation.getSubject()).split("\\x7C");
if (parts.length < 2 || parts.length > 3) {
throw new UiException(i18n.format("RTGovSituationsProvider.InvalidSubject",
situation.getSubject(), parts.length));
}
return new ServiceOperationName(parts[0], parts[1]);
}
/**
* Predicate to test
* {@link ServicesProvider#isResubmitSupported(String, String)}
*/
private final class IsResubmitSupported implements com.google.common.base.Predicate<ServicesProvider> {
private final ServiceOperationName operationName;
private IsResubmitSupported(Situation situation) throws UiException {
this(getServiceOperationName(situation));
}
private IsResubmitSupported(ServiceOperationName operationName) {
this.operationName = operationName;
}
@Override
public boolean apply(ServicesProvider input) {
try {
ResubmitActionProvider resubmit=input.getAction(ResubmitActionProvider.class);
if (resubmit == null) {
return false;
}
return resubmit.isResubmitSupported(operationName.getService(), operationName.getOperation());
} catch (UiException e) {
Throwables.propagate(e);
}
return false;
}
}
/**
* Simple value object for service and operation name.
*
*/
private static class ServiceOperationName {
private String service;
private String operation;
private ServiceOperationName(String service, String operation) {
super();
this.service = service;
this.operation = operation;
}
/**
* @return the service
*/
public String getService() {
return service;
}
/**
* @return the operation
*/
public String getOperation() {
return operation;
}
}
/**
* Interface for performing an action on a situation.
*
*/
public interface SituationsAction {
/**
* This method performs the action on a specified situation.
*
* @param situation The situation
* @throws Exception Failed to perform action
*/
public void perform(Situation situation) throws Exception;
}
}