Skip to content

Commit

Permalink
[GEOS-7366] Fixed a WPS file handle leak.
Browse files Browse the repository at this point in the history
  • Loading branch information
sikeoka committed Jan 6, 2016
1 parent 95c9112 commit 932b22f
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 21 deletions.
@@ -1,15 +1,18 @@
/* (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;

Expand All @@ -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;
Expand All @@ -44,39 +47,46 @@ public CoverageResourceListener(WPSResourceManager resourceManager, CoverageClea

@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;
}
}

Expand Down
@@ -0,0 +1,93 @@
/* (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);
}
}

0 comments on commit 932b22f

Please sign in to comment.