/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wps; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.beanutils.BeanComparator; import org.geoserver.wps.executor.ExecutionStatus; import org.geoserver.wps.executor.ProcessState; import org.geotools.data.Query; import org.geotools.util.logging.Logging; import org.opengis.filter.Filter; import org.opengis.filter.sort.SortBy; import org.opengis.filter.sort.SortOrder; /** * In memory implementation of the {@link ProcessStatusStore} interface * * @author Andrea Aime - GeoSolutions */ public class MemoryProcessStatusStore implements ProcessStatusStore { static final Logger LOGGER = Logging.getLogger(MemoryProcessStatusStore.class); Map<String, ExecutionStatus> statuses = new ConcurrentHashMap<String, ExecutionStatus>(); @Override public void save(ExecutionStatus status) { boolean succeded = false; if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Saving status " + status); } // use optimistic locking to update the status, and check the phase transition is a valid // one while (!succeded) { ExecutionStatus oldStatus = statuses.get(status.getExecutionId()); ExecutionStatus newStatus = new ExecutionStatus(status); if (oldStatus != null) { ProcessState previousPhase = oldStatus.getPhase(); ProcessState currPhase = status.getPhase(); if (!currPhase.isValidSuccessor(previousPhase)) { throw new WPSException("Cannot switch process status from " + previousPhase + " to " + currPhase); } ExecutionStatus prevInMap = statuses.put(status.getExecutionId(), newStatus); succeded = prevInMap == oldStatus; } else { ExecutionStatus previous = statuses.put(status.getExecutionId(), newStatus); succeded = previous == null; } } } @Override public int remove(Filter filter) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Removing statuses matching " + filter); } int count = 0; for (ExecutionStatus status : statuses.values()) { if (filter.evaluate(status)) { count++; statuses.remove(status.getExecutionId()); } } return count; } @Override public List<ExecutionStatus> list(Query query) { List<ExecutionStatus> result = new ArrayList<>(); // extract and filter Filter filter = query.getFilter(); for (ExecutionStatus status : statuses.values()) { if (filter.evaluate(status)) { result.add(status); } } // sort SortBy[] sorts = query.getSortBy(); if (sorts != null) { List<Comparator<ExecutionStatus>> comparators = new ArrayList<>(); for (SortBy sort : sorts) { if (sort == SortBy.NATURAL_ORDER) { comparators.add(new BeanComparator("creationTime")); } else if (sort == SortBy.REVERSE_ORDER) { comparators.add(Collections.reverseOrder(new BeanComparator("creationTime"))); } else { String property = sort.getPropertyName().getPropertyName(); //map property to ExecutionStatus values if("node".equalsIgnoreCase(property)) { property = "nodeId"; }else if("user".equalsIgnoreCase(property)) { property = "userName"; }else if("task".equalsIgnoreCase(property)) { property = "task"; } Comparator<ExecutionStatus> comparator = new BeanComparator(property); if (sort.getSortOrder() == SortOrder.DESCENDING) { comparator = Collections.reverseOrder(comparator); } comparators.add(comparator); } } if (comparators.size() > 1) { Comparator<ExecutionStatus> comparator = new CompositeComparator<>(comparators); Collections.sort(result, comparator); } else if (comparators.size() == 1) { Collections.sort(result, comparators.get(0)); } } // paging Integer startIndex = query.getStartIndex(); if (startIndex != null && startIndex > 0) { if (startIndex > result.size()) { result.clear(); } else { result = result.subList(startIndex, result.size()); } } if (result.size() > query.getMaxFeatures()) { result = result.subList(0, query.getMaxFeatures()); } return result; } @Override public ExecutionStatus get(String executionId) { return statuses.get(executionId); } @Override public ExecutionStatus remove(String executionId) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Removing status for execution id: " + executionId); } return statuses.remove(executionId); } @Override public boolean supportsPredicate() { // return true; } @Override public boolean supportsPaging() { return false; } }