from snappy import jpy, Band, ProductIO, ProductUtils

OpType = jpy.get_type('org.esa.snap.core.datamodel.GeneralFilterBand$OpType')
GeneralFilterBand = jpy.get_type('org.esa.snap.core.datamodel.GeneralFilterBand')
Kernel = jpy.get_type('org.esa.snap.core.datamodel.Kernel')

product_file = 'G:/EOData/temp/subset_of_S2A_MSIL2A_20170830T110621_N0205_.dim'
out_file = 'G:/EOData/temp/prod_with_filtered_band.dim'

try:
    product = ProductIO.readProduct(product_file)
except BaseException as e:
     print(e)

sourceRaster = product.getBandAt(0)
realBand = False
filteredBandName = 'myFilteredBand'
# OpType can be one of {MIN, MAX, MEDIAN, MEAN, STDDEV, EROSION, DILATION, OPENING, CLOSING}
opType = OpType.STDDEV
iterationCount = 1

kernel_data = [0, 1, 1, 1, 1, 1, 1, 1, 0,
               1, 1, 1, 1, 1, 1, 1, 1, 1,
               1, 1, 1, 1, 0, 1, 1, 1, 1,
               1, 1, 1, 0, 0, 0, 1, 1, 1,
               1, 1, 0, 0, 0, 0, 0, 1, 1,
               1, 1, 1, 0, 0, 0, 1, 1, 1,
               1, 1, 1, 1, 0, 1, 1, 1, 1,
               1, 1, 1, 1, 1, 1, 1, 1, 1,
               0, 1, 1, 1, 1, 1, 1, 1, 0]
kernel = Kernel(9, 9, 4, 4, 1 / 64, kernel_data)

filtered_band = GeneralFilterBand(filteredBandName, sourceRaster, opType, kernel, iterationCount)

# Turn into real Band
if realBand:
    target_band = Band(filtered_band.getName(), filtered_band.getDataType(),
                       filtered_band.getRasterWidth(), filtered_band.getRasterHeight())
    target_band.setSourceImage(filtered_band.getSourceImage())
else:
    target_band = filtered_band

if isinstance(jpy.cast(sourceRaster, Band), Band):
    ProductUtils.copySpectralBandProperties(sourceRaster, target_band)

product.addBand(target_band)

PrintPM = jpy.get_type('com.bc.ceres.core.PrintWriterProgressMonitor')
# or a more concise implementation
ConcisePM = jpy.get_type('com.bc.ceres.core.PrintWriterConciseProgressMonitor')
System = jpy.get_type('java.lang.System')
pm = ConcisePM(System.out)

ProductIO.writeProduct(product, out_file, 'BEAM-DIMAP', pm)
