Commit 0dc89329 authored by Steve Ikeoka's avatar Steve Ikeoka Committed by Andrea Aime
Browse files

[GEOS-7366] Fixed a WPS file handle leak.

parent 91721702
/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
/* (c) 2014 - 2015 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.resource;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.geoserver.wcs.CoverageCleanerCallback;
import org.geoserver.wps.ProcessListenerAdapter;
import org.geoserver.wps.ProcessEvent;
import org.geoserver.wps.ProcessListenerAdapter;
import org.geoserver.wps.WPSException;
import org.opengis.coverage.grid.GridCoverage;
......@@ -27,9 +30,9 @@ public class CoverageResourceListener extends ProcessListenerAdapter {
* @author Andrea Aime - GeoSolutions
*/
private static class ResourceStatus {
boolean inputChecked;
final Set<String> inputsChecked = new HashSet<>();
boolean outputChecked;
final Set<String> outputsChecked = new HashSet<>();
}
WPSResourceManager resourceManager;
......@@ -44,39 +47,46 @@ public class CoverageResourceListener extends ProcessListenerAdapter {
@Override
public void progress(ProcessEvent event) throws WPSException {
if (event.getInputs() == null) {
return;
}
checkInputOutput(event);
}
private void checkInputOutput(ProcessEvent event) {
Map<String, Object> inputs = event.getInputs();
Map<String, Object> outputs = event.getOutputs();
if (((inputs == null) || inputs.isEmpty()) &&
((outputs == null) || outputs.isEmpty())) {
return;
}
// check if we have the status
String executionId = event.getStatus().getExecutionId();
// check if we have the status, and if inputs have already been checked
ResourceStatus status = resourceStates.get(executionId);
if (status == null) {
status = new ResourceStatus();
resourceStates.put(executionId, status);
}
if (!status.inputChecked) {
for (Object input : event.getInputs().values()) {
if (input instanceof GridCoverage) {
resourceManager.addResource(new GridCoverageResource(((GridCoverage) input)));
// check if the available inputs have already been checked
Set<String> inputsChecked = status.inputsChecked;
if ((inputs != null) && (inputsChecked.size() < inputs.size())) {
for (Entry<String, Object> entry : inputs.entrySet()) {
Object input = entry.getValue();
if ((input != null) && inputsChecked.add(entry.getKey()) &&
(input instanceof GridCoverage)) {
resourceManager.addResource(new GridCoverageResource((GridCoverage) input));
}
}
status.inputChecked = true;
}
// check if the outputs are available have already been checked
if (!status.outputChecked && event.getOutputs() != null) {
for (Object output : event.getOutputs().values()) {
if (output instanceof GridCoverage) {
resourceManager.addResource(new GridCoverageResource(((GridCoverage) output)));
// check if the available outputs have already been checked
Set<String> outputsChecked = status.outputsChecked;
if ((outputs != null) && (outputsChecked.size() < outputs.size())) {
for (Entry<String, Object> entry : outputs.entrySet()) {
Object output = entry.getValue();
if ((output != null) && outputsChecked.add(entry.getKey()) &&
(output instanceof GridCoverage)) {
resourceManager.addResource(new GridCoverageResource((GridCoverage) output));
}
}
status.outputChecked = true;
}
}
......
/* (c) 2015 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.resource;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.easymock.classextension.EasyMock;
import org.geoserver.wcs.CoverageCleanerCallback;
import org.geoserver.wps.ProcessEvent;
import org.geoserver.wps.ProcessListener;
import org.geoserver.wps.executor.ExecutionStatus;
import org.geoserver.wps.executor.ProcessState;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.feature.NameImpl;
import org.junit.Before;
import org.junit.Test;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
public class CoverageResourceListenerTest {
private WPSResourceManager resourceManager;
private ProcessListener listener;
private ExecutionStatus status;
private Map<String, Object> inputs;
@Before
public void setUp() {
this.resourceManager = createMock(WPSResourceManager.class);
this.listener = new CoverageResourceListener(
this.resourceManager, new CoverageCleanerCallback());
this.status = new ExecutionStatus(
new NameImpl("gs", "TestProcess"), UUID.randomUUID().toString(), false);
this.status.setPhase(ProcessState.RUNNING);
this.inputs = new HashMap<>();
this.inputs.put("coverageA", null);
this.inputs.put("coverageB", null);
this.inputs.put("string", null);
this.inputs.put("integer", null);
}
@Test
public void testCheckInputWhenSucceeded() {
// expected addResource to be called twice
this.resourceManager.addResource(EasyMock.<GridCoverageResource> anyObject());
expectLastCall().times(2);
replay(this.resourceManager);
this.listener.progress(new ProcessEvent(this.status, this.inputs));
this.inputs.put("coverageA", createMock(GridCoverage2D.class));
this.listener.progress(new ProcessEvent(this.status, this.inputs));
this.inputs.put("coverageB", createMock(GridCoverage2D.class));
this.listener.progress(new ProcessEvent(this.status, this.inputs));
this.inputs.put("string", "testString");
this.listener.progress(new ProcessEvent(this.status, this.inputs));
this.inputs.put("integer", 1);
this.listener.progress(new ProcessEvent(this.status, this.inputs));
this.listener.progress(new ProcessEvent(this.status, this.inputs));
this.status.setPhase(ProcessState.SUCCEEDED);
this.listener.succeeded(new ProcessEvent(this.status, this.inputs));
// verify that addResource was called twice
verify(this.resourceManager);
}
@Test
public void testCheckInputWhenFailed() {
// expected addResource to be called once
this.resourceManager.addResource(EasyMock.<GridCoverageResource> anyObject());
expectLastCall().once();
replay(this.resourceManager);
// failure loading second coverage
this.listener.progress(new ProcessEvent(this.status, this.inputs));
this.inputs.put("coverageA", createMock(GridCoverage2D.class));
this.listener.progress(new ProcessEvent(this.status, this.inputs));
this.status.setPhase(ProcessState.FAILED);
this.listener.failed(new ProcessEvent(this.status, this.inputs));
// verify that addResource was called once
verify(this.resourceManager);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment