class FootprintExtractionProcess implements RasterProcess {

    @DescribeResult(name = "result", description = "The compute footprint geometry")
    public SimpleFeatureCollection execute(
            @DescribeParameter(name = "data", description = "Source raster") GridCoverage2D coverage,
            @DescribeParameter(name = "exclusionRanges", description = "the ranges of luminance values to be excluded by the computation.", min = 0) List<Range<Integer>> exclusionRanges,
            @DescribeParameter(name = "thresholdArea", description = "Indicates the minimum area of a polygon to be included in the final result", min = 0) Double thresholdArea, 
            @DescribeParameter(name = "computeSimplifiedFootprint", description = "Indicates whether the simplified footprint should be computed", min = 0) Boolean computeSimplifiedFootprint, 
            @DescribeParameter(name = "simplifierFactor", description = "Indicates the simplifier factor to be applied when computing the simplified footprint", min = 0) Double simplifierFactor, 
            @DescribeParameter(name = "removeCollinear", description = "Indicates whether remove collinear point should be applied", min = 0) Boolean removeCollinear,
            @DescribeParameter(name = "forceValid", description = "Indicates whether polygon should be forced to be valid, also removing holes", min = 0) Boolean forceValid,
            @DescribeParameter(name = "loadingType", description = "Indicates which type of imageLoading should be performed (DEFERRED vs IMMEDIATE)", min = 0) ImageLoadingType imageLoadingType,
            ProgressListener progressListener)
            throws ProcessException {

        //
        // initial checks
        //
        if (coverage == null) {
            throw new ProcessException("Invalid input, source grid coverage should be not null");
        }

        // Checking for defaults
        if (exclusionRanges == null) {
            exclusionRanges = MarchingSquaresVectorizer.DEFAULT_RANGES;
        }

        if (computeSimplifiedFootprint == null) {
            computeSimplifiedFootprint = false;
        }

        if (simplifierFactor == null) {
            simplifierFactor = MarchingSquaresVectorizer.DEFAULT_SIMPLIFIER_FACTOR;
        }

        if (forceValid == null) {
            forceValid = true;
        }

        if (removeCollinear == null) {
            removeCollinear = true;
        }

        if (imageLoadingType == null) {
            imageLoadingType = ImageLoadingType.getDefault();
        }

        if (thresholdArea == null) {
            thresholdArea = MarchingSquaresVectorizer.DEFAULT_THRESHOLD_AREA;
        }

        MarchingSquaresVectorizer vectorizer = new MarchingSquaresVectorizer(coverage, null, thresholdArea, simplifierFactor, imageLoadingType, exclusionRanges);
        vectorizer.setComputeSimplifiedFootprint(computeSimplifiedFootprint);
        vectorizer.setForceValid(forceValid);
        vectorizer.setRemoveCollinear(removeCollinear);
        try {
            vectorizer.process();

            Geometry geometry = vectorizer.getFootprint();

            // wrap as a feature collection and return
            final SimpleFeatureType featureType = CoverageUtilities.createFeatureType(coverage,
                    Geometry.class);
            final SimpleFeatureBuilder builder = new SimpleFeatureBuilder(featureType);
            int i = 0;
            final ListFeatureCollection featureCollection = new ListFeatureCollection(featureType);

            // create feature and add to list
            builder.set("the_geom", geometry);

            featureCollection.add(builder.buildFeature(String.valueOf(i++)));
            if (computeSimplifiedFootprint) {
                builder.set("the_geom", vectorizer.getSimplifiedFootprint());
                featureCollection.add(builder.buildFeature(String.valueOf(i++)));
            }
            return featureCollection;
        } catch (Exception e) {
            throw new ProcessException("Exception occurred while computing the footprint", e);
        } finally {
            vectorizer.dispose();
        }
    }

}