/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2012, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.wps.io; import com.vividsolutions.jts.geom.Geometry; import java.awt.geom.AffineTransform; import java.awt.image.RenderedImage; import java.io.File; import java.net.URL; import java.net.URLConnection; import java.util.*; import javax.imageio.ImageIO; import javax.measure.Unit; import org.geotoolkit.data.FeatureCollection; import org.geotoolkit.ows.xml.v110.BoundingBoxType; import org.apache.sis.measure.NumberRange; import org.geotoolkit.ows.xml.v110.DomainMetadataType; import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.ObjectConverters; import org.apache.sis.util.UnconvertibleObjectException; import org.geotoolkit.wps.converters.WPSConverterRegistry; import org.geotoolkit.wps.converters.WPSConvertersUtils; import org.geotoolkit.wps.converters.WPSObjectConverter; import org.geotoolkit.wps.converters.WPSObjectConverterAdapter; import org.geotoolkit.wps.xml.ComplexDataType; import org.geotoolkit.wps.xml.DataType; import org.opengis.coverage.Coverage; import org.opengis.feature.Feature; import org.opengis.feature.FeatureType; import org.geotoolkit.wps.xml.Reference; import org.opengis.filter.Filter; import org.opengis.filter.sort.SortBy; import org.opengis.geometry.Envelope; import org.opengis.sld.StyledLayerDescriptor; /** * * @author Quentin Boileau (Geomatys). */ public final class WPSIO { /** * A key for userdata map of an {@link org.geotoolkit.parameter.ExtendedParameterDescriptor} object. The aim is to * link it with a list of {@link FormatSupport} wanted for the parameter. */ public static final String SUPPORTED_FORMATS_KEY = "supportedFormats"; /** * A key for userdata map of an {@link org.geotoolkit.parameter.ExtendedParameterDescriptor} object. The aim is to * link it with a String, which is an URL to the schema which current parameter must match. */ public static final String SCHEMA_KEY = "schema"; private static final List<FormatSupport> FORMATSUPPORTS = Collections.synchronizedList(new ArrayList<FormatSupport>()); static { FORMATSUPPORTS.add(new FormatSupport(StyledLayerDescriptor.class, IOType.BOTH, WPSMimeType.APP_SLD.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_SLD_1_1_0.getValue(), true)); FORMATSUPPORTS.add(new FormatSupport(Feature.class, IOType.BOTH, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Feature.class, IOType.BOTH, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Feature.class, IOType.BOTH, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), true)); FORMATSUPPORTS.add(new FormatSupport(Feature.class, IOType.BOTH, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Feature.class, IOType.BOTH, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Feature.class, IOType.BOTH, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), true)); FORMATSUPPORTS.add(new FormatSupport(Feature.class, IOType.BOTH, WPSMimeType.APP_GEOJSON.val(), WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(Feature[].class, IOType.INPUT, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Feature[].class, IOType.INPUT, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Feature[].class, IOType.INPUT, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), true)); FORMATSUPPORTS.add(new FormatSupport(Feature[].class, IOType.INPUT, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Feature[].class, IOType.INPUT, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Feature[].class, IOType.INPUT, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), true)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection.class, IOType.BOTH, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection.class, IOType.BOTH, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection.class, IOType.BOTH, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection.class, IOType.BOTH, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection.class, IOType.BOTH, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection.class, IOType.BOTH, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection.class, IOType.BOTH, WPSMimeType.APP_GEOJSON.val(), WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection[].class, IOType.INPUT, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection[].class, IOType.INPUT, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection[].class, IOType.INPUT, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), true)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection[].class, IOType.INPUT, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection[].class, IOType.INPUT, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(FeatureCollection[].class, IOType.INPUT, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), true)); FORMATSUPPORTS.add(new FormatSupport(Geometry.class, IOType.BOTH, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry.class, IOType.BOTH, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry.class, IOType.BOTH, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry.class, IOType.BOTH, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry.class, IOType.BOTH, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry.class, IOType.BOTH, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry.class, IOType.BOTH, WPSMimeType.APP_GEOJSON.val(), WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(Geometry[].class, IOType.BOTH, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry[].class, IOType.BOTH, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry[].class, IOType.BOTH, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_1_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry[].class, IOType.BOTH, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry[].class, IOType.BOTH, WPSMimeType.TEXT_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry[].class, IOType.BOTH, WPSMimeType.APP_GML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_GML_3_2_1.getValue(), false)); FORMATSUPPORTS.add(new FormatSupport(Geometry[].class, IOType.BOTH, WPSMimeType.APP_GEOJSON.val(), WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(FeatureType.class, IOType.BOTH, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_1_1.getValue(), true)); FORMATSUPPORTS.add(new FormatSupport(FeatureType.class, IOType.BOTH, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.OGC_FEATURE_3_2_1.getValue(), true)); //Coverage support FORMATSUPPORTS.add(new FormatSupport(Coverage.class, IOType.BOTH, WPSMimeType.IMG_GEOTIFF_BIS.val(), null, null, true)); FORMATSUPPORTS.add(new FormatSupport(Coverage.class, IOType.BOTH, WPSMimeType.IMG_GEOTIFF_BIS.val(), WPSEncoding.BASE64.getValue(), null, false)); FORMATSUPPORTS.add(new FormatSupport(Coverage.class, IOType.BOTH, WPSMimeType.IMG_GEOTIFF.val(), null, null, false)); FORMATSUPPORTS.add(new FormatSupport(Coverage.class, IOType.BOTH, WPSMimeType.IMG_GEOTIFF.val(), WPSEncoding.BASE64.getValue(), null, false)); FORMATSUPPORTS.add(new FormatSupport(Coverage.class, IOType.OUTPUT, WPSMimeType.OGC_WMS.val(), WPSEncoding.UTF8.getValue(), null, false)); //TODO test NetCDF & GRIB in base64 FORMATSUPPORTS.add(new FormatSupport(Coverage.class, IOType.INPUT, WPSMimeType.APP_NETCDF.val(), null, null, false)); FORMATSUPPORTS.add(new FormatSupport(Coverage.class, IOType.INPUT, WPSMimeType.APP_NETCDF.val(), WPSEncoding.BASE64.getValue(), null, false)); FORMATSUPPORTS.add(new FormatSupport(Coverage.class, IOType.INPUT, WPSMimeType.APP_GRIB.val(), null, null, false)); FORMATSUPPORTS.add(new FormatSupport(Coverage.class, IOType.INPUT, WPSMimeType.APP_GRIB.val(), WPSEncoding.BASE64.getValue(), null, false)); // Images support for (final String readerMime : ImageIO.getReaderMIMETypes()) { if (!readerMime.isEmpty()) { if (readerMime.equals("image/png")) { FORMATSUPPORTS.add(new FormatSupport(RenderedImage.class, IOType.INPUT, readerMime, null, null, true)); FORMATSUPPORTS.add(new FormatSupport(RenderedImage.class, IOType.INPUT, readerMime, WPSEncoding.BASE64.getValue(), null, true)); } else { FORMATSUPPORTS.add(new FormatSupport(RenderedImage.class, IOType.INPUT, readerMime, null, null, false)); FORMATSUPPORTS.add(new FormatSupport(RenderedImage.class, IOType.INPUT, readerMime, WPSEncoding.BASE64.getValue(), null, false)); } } } for (final String writerMime : ImageIO.getWriterMIMETypes()) { if (!writerMime.isEmpty()) { if (writerMime.equals("image/png")) { FORMATSUPPORTS.add(new FormatSupport(RenderedImage.class, IOType.OUTPUT, writerMime, null, null, true)); FORMATSUPPORTS.add(new FormatSupport(RenderedImage.class, IOType.OUTPUT, writerMime, WPSEncoding.BASE64.getValue(), null, true)); } else { FORMATSUPPORTS.add(new FormatSupport(RenderedImage.class, IOType.OUTPUT, writerMime, null, null, false)); FORMATSUPPORTS.add(new FormatSupport(RenderedImage.class, IOType.OUTPUT, writerMime, WPSEncoding.BASE64.getValue(), null, false)); } } } FORMATSUPPORTS.add(new FormatSupport(AffineTransform.class, IOType.INPUT, WPSMimeType.TEXT_XML.val(), WPSEncoding.UTF8.getValue(), WPSSchema.MATHML_3.getValue(), true)); FORMATSUPPORTS.add(new FormatSupport(Number.class, IOType.BOTH, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(Boolean.class, IOType.BOTH, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(String.class, IOType.BOTH, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(String.class, IOType.BOTH, WPSMimeType.TEXT_PLAIN.val(), WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(String.class, IOType.BOTH, WPSMimeType.APP_JSON.val(), WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(URL.class, IOType.BOTH, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(URLConnection.class, IOType.BOTH, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(File.class, IOType.BOTH, WPSMimeType.APP_OCTET.val(), null, null, true)); FORMATSUPPORTS.add(new FormatSupport(File.class, IOType.BOTH, WPSMimeType.APP_ZIP.val(), null, null, true)); FORMATSUPPORTS.add(new FormatSupport(File.class, IOType.BOTH, WPSMimeType.APP_ZIP_BIS.val(), null, null, true)); FORMATSUPPORTS.add(new FormatSupport(File.class, IOType.BOTH, WPSMimeType.APP_GZIP.val(), null, null, true)); FORMATSUPPORTS.add(new FormatSupport(File.class, IOType.BOTH, WPSMimeType.APP_OCTET.val(), WPSEncoding.BASE64.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(File.class, IOType.BOTH, WPSMimeType.APP_ZIP.val(), WPSEncoding.BASE64.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(File.class, IOType.BOTH, WPSMimeType.APP_ZIP_BIS.val(), WPSEncoding.BASE64.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(File.class, IOType.BOTH, WPSMimeType.APP_GZIP.val(), WPSEncoding.BASE64.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(Unit.class, IOType.INPUT, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(SortBy[].class, IOType.INPUT, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(NumberRange[].class, IOType.INPUT, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(Filter.class, IOType.INPUT, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(Date.class, IOType.INPUT, null, WPSEncoding.UTF8.getValue(), null, true)); //primitive arrays FORMATSUPPORTS.add(new FormatSupport(double[].class, IOType.BOTH, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(int[].class, IOType.BOTH, null, WPSEncoding.UTF8.getValue(), null, true)); FORMATSUPPORTS.add(new FormatSupport(float[].class, IOType.BOTH, null, WPSEncoding.UTF8.getValue(), null, true)); } public static void addFormatSupport(FormatSupport newSupport) { ArgumentChecks.ensureNonNull("Support format to add", newSupport); FORMATSUPPORTS.add(newSupport); } /** * Private constructor. */ private WPSIO() { } /** * Check if a class for one {@link IOType} and one {@link DataType} is supported by the service. * * @param clazz * @param ioType * @param dataType * @return true if supported else false. */ private static boolean isSupportedClass(final Class clazz, final IOType ioType, final FormChoice dataType) { boolean isSupported = false; if (clazz != null) { if (dataType.equals(FormChoice.LITERAL) || dataType.equals(FormChoice.ALL)) { try { ObjectConverters.find(String.class, clazz); isSupported = true; } catch (UnconvertibleObjectException ex) { //Do nothing. In this case no simple converter where found } } //search the IOType final IOType classIOType = findIOType(clazz); if (!isSupported && classIOType != null) { Class source, target; Class formClass = null; if (dataType.equals(FormChoice.LITERAL)) { formClass = String.class; } else if (dataType.equals(FormChoice.BBOX)) { formClass = BoundingBoxType.class; } else if (dataType.equals(FormChoice.COMPLEX)) { formClass = ComplexDataType.class; } else if (dataType.equals(FormChoice.REFERENCE)) { formClass = Reference.class; } if (ioType.equals(IOType.INPUT)) { source = formClass; target = clazz; } else { source = clazz; target = formClass; } boolean tryAllSources = (source == null); boolean tryAllTargets = (target == null); final WPSConverterRegistry registry = WPSConverterRegistry.getInstance(); WPSObjectConverter converter = null; int loop = 0; final Class[] testClass = new Class[]{String.class, Reference.class, BoundingBoxType.class, ComplexDataType.class}; while (converter == null) { try { if (!tryAllSources && !tryAllTargets) { converter = registry.getConverter(source, target); } else if (tryAllSources) { converter = registry.getConverter(testClass[loop], target); } else if (tryAllTargets) { converter = registry.getConverter(source, testClass[loop]); } else { break; } } catch (UnconvertibleObjectException ex) { loop++; if (loop == testClass.length) { break; } continue; } } if (converter != null) { isSupported = true; } } } return isSupported; } /** * Find if a class is supported in INPUT, OUTPUT or BOTH. * * @param clazz * @return IOType supported or null otherwise. */ private static IOType findIOType(final Class clazz) { boolean hasInputConverter = false; boolean hasOutputConverter = false; if (!WPSConverterRegistry.getInstance().getInputConvertersFoTargetClass(clazz).isEmpty()) { hasInputConverter = true; } if (!WPSConverterRegistry.getInstance().getOutputConvertersForSourceClass(clazz).isEmpty()) { hasOutputConverter = true; } if (hasInputConverter && hasOutputConverter) { return IOType.BOTH; } else if (hasInputConverter) { return IOType.INPUT; } else if (hasOutputConverter) { return IOType.OUTPUT; } return null; } /** * Return the list of supported format for a class in an {@link IOType}. * * @param clazz * @param ioType * @return a list of {@link FormatSupport} */ public static List<FormatSupport> getFormats(final Class clazz, final IOType ioType) { final List<FormatSupport> supports = new ArrayList<FormatSupport>(); for (final FormatSupport formatSupport : FORMATSUPPORTS) { if (clazz != null && formatSupport.getClazz().equals(clazz) || formatSupport.getClazz().isAssignableFrom(clazz)) { if (formatSupport.getIOType().equals(IOType.BOTH) || formatSupport.getIOType().equals(ioType)) { supports.add(formatSupport); } } } return supports; } /** * Return the default {@link FormatSupport} for the given class in an {@link IOType}. * * @param clazz * @param ioType * @return a {@link FormatSupport} */ public static FormatSupport getDefaultFormats(final Class clazz, final IOType ioType) { final List<FormatSupport> supports = getFormats(clazz, ioType); if (!supports.isEmpty()) { for (FormatSupport formatSupport : supports) { if (formatSupport.isDefaultFormat()) { return formatSupport; } } } return null; } /** * Get the default encoding for a given class and ioType * @param clazz * @param ioType * @return null if there is no default encoding, otherwise returns the default * encoding */ public static String getDefaultEncoding(final Class clazz, final IOType ioType) { final FormatSupport defaultFormat = getDefaultFormats(clazz, ioType); if (defaultFormat == null) return null; return defaultFormat.getEncoding(); } /** * Get the default mime type for a given class and ioType * @param clazz * @param ioType * @return null if there is no default mime type, otherwise returns the * default mime type */ public static String getDefaultMimeType(final Class clazz, final IOType ioType) { final FormatSupport defaultFormat = getDefaultFormats(clazz, ioType); if (defaultFormat == null) return null; return defaultFormat.getMimeType(); } /** * Check if a class is supported in INPUT. * * @param clazz * @return true if supported, false otherwise. */ public static boolean isSupportedInputClass(final Class clazz) { if(isSupportedBBoxInputClass(clazz)) { return true; } return isSupportedClass(clazz, IOType.INPUT, FormChoice.ALL); } /** * Check if a class is supported in OUTPUT. * * @param clazz * @return true if supported, false otherwise. */ public static boolean isSupportedOutputClass(final Class clazz) { return isSupportedClass(clazz, IOType.OUTPUT, FormChoice.ALL); } /** * Check if a class is supported for LITERAL INPUT. * * @param clazz * @return true if supported, false otherwise. */ public static boolean isSupportedLiteralInputClass(final Class clazz) { return isSupportedClass(clazz, IOType.INPUT, FormChoice.LITERAL); } /** * Check if a class is supported for COMPLEX INPUT. * * @param clazz * @return true if supported, false otherwise. */ public static boolean isSupportedComplexInputClass(final Class clazz) { return isSupportedClass(clazz, IOType.INPUT, FormChoice.COMPLEX); } /** * Check if a class is supported for REFERENCE INPUT. * * @param clazz * @return true if supported, false otherwise. */ public static boolean isSupportedReferenceInputClass(final Class clazz) { return isSupportedClass(clazz, IOType.INPUT, FormChoice.REFERENCE); } /** * Check if a class is supported for BBOX INPUT. * * @param clazz * @return true if supported, false otherwise. */ public static boolean isSupportedBBoxInputClass(final Class clazz) { if (clazz.isAssignableFrom(Envelope.class)) { return true; } return false; } /** * Check if a class is supported for LITERAL OUTPUT. * * @param clazz * @return true if supported, false otherwise. */ public static boolean isSupportedLiteralOutputClass(final Class clazz) { return isSupportedClass(clazz, IOType.OUTPUT, FormChoice.LITERAL); } /** * Check if a class is supported for COMPLEX OUTPUT. * * @param clazz * @return true if supported, false otherwise. */ public static boolean isSupportedComplexOutputClass(final Class clazz) { return isSupportedClass(clazz, IOType.OUTPUT, FormChoice.COMPLEX); } /** * Check if a class is supported for REFERENCE OUTPUT. * * @param clazz * @return true if supported, false otherwise. */ public static boolean isSupportedReferenceOutputClass(final Class clazz) { return isSupportedClass(clazz, IOType.OUTPUT, FormChoice.REFERENCE); } /** * Check if a class is supported for BBOX OUTPUT. * * @param clazz * @return true if supported, false otherwise. */ public static boolean isSupportedBBoxOutputClass(final Class clazz) { if (clazz.isAssignableFrom(Envelope.class)) { return true; } return false; } /** * Check if given mimetype, encoding, schema are supported by the given input class in an {@link IOType}. * * @param clazz * @param ioType * @param mimeType * @param encoding * @param schema * @throws UnconvertibleObjectException if not supported. */ public static void checkSupportedFormat(final Class clazz, final IOType ioType, String mimeType, String encoding, String schema) throws UnconvertibleObjectException { boolean formatOK = false; final List<FormatSupport> candidates = getFormats(clazz, ioType); int nbSearch = 0; if (mimeType != null) { mimeType.trim(); if (mimeType.isEmpty()) { mimeType = null; } else { nbSearch++; } } if (encoding != null) { encoding.trim(); if (encoding.isEmpty()) { encoding = null; } else { nbSearch++; } } if (schema != null) { schema.trim(); if (schema.isEmpty()) { schema = null; } else { nbSearch++; } } if (mimeType == null && encoding == null && schema == null) { formatOK = true; } else { FormatSupport bestMatch = null; int maxMatch = 0; int match; for (int i = 0; i < candidates.size(); i++) { final FormatSupport formatSupport = candidates.get(i); final String wpsMime = formatSupport.getMimeType(); final String wpsSchema = formatSupport.getSchema() != null ? formatSupport.getSchema() : null; final String wpsEncoding = formatSupport.getEncoding() != null ? formatSupport.getEncoding() : null; match = 0; if (mimeType != null && mimeType.equalsIgnoreCase(wpsMime)) { match++; } if (schema != null && schema.equalsIgnoreCase(wpsSchema)) { match++; } if (encoding != null && encoding.equalsIgnoreCase(wpsEncoding)) { match++; } if (match > maxMatch) { maxMatch = match; bestMatch = formatSupport; } if (maxMatch == nbSearch) { formatOK = true; } } if (!formatOK) { final StringBuilder errorMsg = new StringBuilder("Can't find a converter for these format : "); errorMsg.append(WPSConvertersUtils.dataFormatToString(mimeType, encoding, schema)); if (bestMatch != null) { final String bestMime = bestMatch.getMimeType(); final String bestSchema = bestMatch.getSchema() != null ? bestMatch.getSchema() : null; final String bestEncoding = bestMatch.getEncoding() != null ? bestMatch.getEncoding() : null; errorMsg.append(". You can try with this tuple : ").append(WPSConvertersUtils.dataFormatToString(bestMime, bestEncoding, bestSchema)); } throw new UnconvertibleObjectException(errorMsg.toString()); } } } /** * Return the converter used to parse the data, using his class, his IOType, his DataType and his mimeType. * * @param clazz the binding Class. * @param ioType the {@link IOType} * @param dataType the {@link FormChoice} * @return a WPSObjectConverter * @throws UnconvertibleObjectException if no converter found */ public static WPSObjectConverter getConverter(final Class clazz, final IOType ioType, final FormChoice dataType) throws UnconvertibleObjectException { WPSObjectConverter converter = null; if (dataType.equals(FormChoice.LITERAL)) { try { converter = new WPSObjectConverterAdapter(ObjectConverters.find(String.class, clazz)); } catch (UnconvertibleObjectException ex) { //Do nothing. In this case no simple converter where found } } if (converter == null) { List<WPSObjectConverter> candidates = null; if (ioType.equals(IOType.INPUT)) { //get candidates candidates = WPSConverterRegistry.getInstance().getInputConvertersFoTargetClass(clazz); for (WPSObjectConverter conv : candidates) { final Class sourceClass = conv.getSourceClass(); if ((dataType.equals(FormChoice.COMPLEX) && ComplexDataType.class.isAssignableFrom(sourceClass)) || (dataType.equals(FormChoice.REFERENCE) && Reference.class.isAssignableFrom(sourceClass)) || (dataType.equals(FormChoice.BBOX) && BoundingBoxType.class.isAssignableFrom(sourceClass)) || (dataType.equals(FormChoice.LITERAL) && String.class.isAssignableFrom(sourceClass))) { converter = conv; break; } } if (candidates.isEmpty() || converter == null) { throw new UnconvertibleObjectException("No converter found."); } } else if (ioType.equals(IOType.OUTPUT)) { candidates = WPSConverterRegistry.getInstance().getOutputConvertersForSourceClass(clazz); for (WPSObjectConverter conv : candidates) { final Class targetClass = conv.getTargetClass(); if ((dataType.equals(FormChoice.COMPLEX) && ComplexDataType.class.isAssignableFrom(targetClass)) || (dataType.equals(FormChoice.REFERENCE) && Reference.class.isAssignableFrom(targetClass)) || (dataType.equals(FormChoice.BBOX) && BoundingBoxType.class.isAssignableFrom(targetClass)) || (dataType.equals(FormChoice.LITERAL) && String.class.isAssignableFrom(targetClass))) { converter = conv; break; } } if (candidates.isEmpty() || converter == null) { throw new UnconvertibleObjectException("No converter found."); } } } return converter; } /** * Find the most appropriate Java class for an INPUT/OUTPUT using mime/encoding/schema. If the FormChoice is LITERAL * and a DomainMetadataType not null, the method use the DomaineMetadataType value to find an appropriate class. * * @param ioType * @param dataType * @param mimeType * @param encoding * @param schema * @param literalDataType * * @return a java class or null if nothing found. */ public static Class findClass(final IOType ioType, final FormChoice dataType, final String mimeType, final String encoding, final String schema, final DomainMetadataType literalDataType) { ArgumentChecks.ensureNonNull("dataType", dataType); Class clazz = null; if (dataType.equals(FormChoice.LITERAL) && literalDataType != null) { String value = literalDataType.getValue(); clazz = String.class; if (value != null && !value.isEmpty()) { try { clazz = Class.forName(value); } catch (ClassNotFoundException ex) { value = value.toLowerCase(); if (value.contains("double")) { clazz = Double.class; } else if (value.contains("boolean")) { clazz = Boolean.class; } else if (value.contains("float")) { clazz = Float.class; } else if (value.contains("integer")) { clazz = Integer.class; } else if (value.contains("long")) { clazz = Long.class; } } } return clazz; } else if (dataType.equals(FormChoice.BBOX)) { clazz = Envelope.class; } else { int nbSearch = 3; int match; for (final FormatSupport formatSupport : FORMATSUPPORTS) { final String wpsMime = formatSupport.getMimeType(); final String wpsSchema = formatSupport.getSchema(); final String wpsEncoding = formatSupport.getEncoding(); match = 0; if ((mimeType == null && wpsMime== null) || (mimeType != null && mimeType.equalsIgnoreCase(wpsMime))) { match++; } if ((schema == null && wpsSchema== null) || (schema != null && schema.equalsIgnoreCase(wpsSchema))) { match++; } if ((encoding == null && wpsEncoding == null) || (encoding != null && encoding.equalsIgnoreCase(wpsEncoding))) { match++; } if (match == nbSearch) { clazz = formatSupport.getClazz(); break; } } } return clazz; } /** * Enumeration for INPUT/OUTPUT. */ public static enum IOType { INPUT, OUTPUT, BOTH; } /** * Enumeration of WPS data type. */ public static enum FormChoice { LITERAL, COMPLEX, BBOX, REFERENCE, ALL; } /** * That pojo define if an {@link Class binding} is supported by the WPS for the{@link FormChoice} defined by the WPS * standard (LITERAL,COMPLEX,BBOX,REFERENCE). */ public static class WPSSupport { private Class clazz; private FormChoice from; public WPSSupport(final Class clazz, final FormChoice from) { this.clazz = clazz; this.from = from; } public Class getClazz() { return clazz; } public FormChoice getFrom() { return from; } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final WPSSupport other = (WPSSupport) obj; if (this.clazz != other.clazz && (this.clazz == null || (!this.clazz.equals(other.clazz) && !other.clazz.isAssignableFrom(this.clazz)))) { return false; } if (this.from != other.from) { return false; } return true; } @Override public int hashCode() { int hash = 3; hash = 37 * hash + (this.clazz != null ? this.clazz.hashCode() : 0); hash = 37 * hash + (this.from != null ? this.from.hashCode() : 0); return hash; } } /** * That pojo define the mime/encoding/schema supported by a binding class for one {@link IOType} INPUT/OUPTUT. */ public static class FormatSupport { private Class clazz; private IOType ioType; private String mimeType; private String encoding; private String schema; private boolean defaultFormat; public FormatSupport(Class clazz, IOType ioType, String mimeType, String encoding, String schema, boolean defaultFormat) { this.clazz = clazz; this.ioType = ioType; this.mimeType = mimeType; this.encoding = encoding; this.schema = schema; this.defaultFormat = defaultFormat; } public Class getClazz() { return clazz; } public void setClazz(Class clazz) { this.clazz = clazz; } public IOType getIOType() { return ioType; } public void setIOType(IOType ioType) { this.ioType = ioType; } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; } public String getMimeType() { return mimeType; } public void setMimeType(String mimeType) { this.mimeType = mimeType; } public String getSchema() { return schema; } public void setSchema(String schema) { this.schema = schema; } public boolean isDefaultFormat() { return defaultFormat; } public void setDefaultFormat(boolean defaultFormat) { this.defaultFormat = defaultFormat; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final FormatSupport other = (FormatSupport) obj; if (this.clazz != other.clazz && (this.clazz == null || (!this.clazz.equals(other.clazz) && !other.clazz.isAssignableFrom(this.clazz)))) { return false; } if ((this.mimeType == null) ? (other.mimeType != null) : !this.mimeType.equals(other.mimeType)) { return false; } if ((this.encoding == null) ? (other.encoding != null) : !this.encoding.equals(other.encoding)) { return false; } if ((this.schema == null) ? (other.schema != null) : !this.schema.equals(other.schema)) { return false; } return true; } @Override public int hashCode() { int hash = 7; hash = 83 * hash + (this.mimeType != null ? this.mimeType.hashCode() : 0); hash = 83 * hash + (this.encoding != null ? this.encoding.hashCode() : 0); hash = 83 * hash + (this.schema != null ? this.schema.hashCode() : 0); return hash; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("FormatSupport{"); sb.append("class:").append(clazz.getCanonicalName()).append(", "); sb.append("ioType:").append(ioType.toString()).append(", "); sb.append("mimeType:").append(mimeType).append(", "); sb.append("encoding:").append(encoding).append(", "); sb.append("schema:").append(schema).append(", "); sb.append("isDefault:").append(defaultFormat).append("}"); return sb.toString(); } } }