001/* 002 * GeoAPI - Java interfaces for OGC/ISO standards 003 * http://www.geoapi.org 004 * 005 * Copyright (C) 2012-2019 Open Geospatial Consortium, Inc. 006 * All Rights Reserved. http://www.opengeospatial.org/ogc/legal 007 * 008 * Permission to use, copy, and modify this software and its documentation, with 009 * or without modification, for any purpose and without fee or royalty is hereby 010 * granted, provided that you include the following on ALL copies of the software 011 * and documentation or portions thereof, including modifications, that you make: 012 * 013 * 1. The full text of this NOTICE in a location viewable to users of the 014 * redistributed or derivative work. 015 * 2. Notice of any changes or modifications to the OGC files, including the 016 * date changes were made. 017 * 018 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE 019 * NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 020 * TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT 021 * THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY 022 * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. 023 * 024 * COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR 025 * CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. 026 * 027 * The name and trademarks of copyright holders may NOT be used in advertising or 028 * publicity pertaining to the software without specific, written prior permission. 029 * Title to copyright in this software and any associated documentation will at all 030 * times remain with copyright holders. 031 */ 032package org.opengis.test.coverage.image; 033 034import javax.imageio.ImageReader; 035import javax.imageio.ImageWriter; 036import javax.imageio.spi.ImageReaderSpi; 037import javax.imageio.spi.ImageWriterSpi; 038import javax.imageio.spi.ImageReaderWriterSpi; 039import javax.imageio.metadata.IIOMetadataFormat; 040import javax.imageio.metadata.IIOMetadataFormatImpl; 041 042import org.opengis.test.Validator; 043import org.opengis.test.ValidatorContainer; 044 045import static org.opengis.test.Assert.*; 046 047 048/** 049 * Validators for implementations of {@link java.awt.image} or {@link javax.imageio} services. 050 * 051 * @author Martin Desruisseaux (Geomatys) 052 * @version 3.1 053 * @since 3.1 054 */ 055public class ImageValidator extends Validator { 056 /** 057 * Creates a new validator instance. 058 * 059 * @param container the set of validators to use for validating other kinds of objects 060 * (see {@linkplain #container field javadoc}). 061 */ 062 public ImageValidator(final ValidatorContainer container) { 063 super(container, "org.opengis.test.coverage.image"); 064 } 065 066 /** 067 * Validates the given provider of image readers. 068 * First, this method verifies that mandatory elements are non-null, arrays are non-empty 069 * (Image I/O specification requires them to be {@code null} rather than empty), and class 070 * names are valid. Next, this method invokes {@link #validate(IIOMetadataFormat)} for each 071 * metadata format (which can be null). 072 * 073 * @param provider the provider to validate, or {@code null} if none. 074 */ 075 public void validate(final ImageReaderSpi provider) { 076 if (provider != null) { 077 validateProvider(provider, ImageReader.class); 078 final Class<?>[] inputTypes = provider.getInputTypes(); 079 mandatory("ImageReaderSpi: shall have an inputTypes array.", inputTypes); 080 validateArray("inputTypes", inputTypes); 081 final String[] imageWriterSpiNames = provider.getImageWriterSpiNames(); 082 validateArray("imageWriterSpiNames", imageWriterSpiNames); 083 if (imageWriterSpiNames != null) { 084 final ClassLoader loader = provider.getClass().getClassLoader(); 085 for (int i=0; i<imageWriterSpiNames.length; i++) { 086 final String field = "imageWriterSpiNames[" + i + ']'; 087 final String className = imageWriterSpiNames[i]; 088 assertNotNull(field + " can not be null.", className); 089 validateClass(field, ImageWriterSpi.class, loader, className); 090 } 091 } 092 } 093 } 094 095 /** 096 * Validates the given provider of image writers. 097 * First, this method verifies that mandatory elements are non-null, arrays are non-empty 098 * (Image I/O specification requires them to be {@code null} rather than empty), and class 099 * names are valid. Next, this method invokes {@link #validate(IIOMetadataFormat)} for each 100 * metadata format (which can be null). 101 * 102 * @param provider the provider to validate, or {@code null} if none. 103 */ 104 public void validate(final ImageWriterSpi provider) { 105 if (provider != null) { 106 validateProvider(provider, ImageWriter.class); 107 final Class<?>[] outputTypes = provider.getOutputTypes(); 108 mandatory("ImageWriterSpi: shall have an outputTypes array.", outputTypes); 109 validateArray("outputTypes", outputTypes); 110 final String[] imageReaderSpiNames = provider.getImageReaderSpiNames(); 111 validateArray("imageReaderSpiNames", imageReaderSpiNames); 112 if (imageReaderSpiNames != null) { 113 final ClassLoader loader = provider.getClass().getClassLoader(); 114 for (int i=0; i<imageReaderSpiNames.length; i++) { 115 final String field = "imageReaderSpiNames[" + i + ']'; 116 final String className = imageReaderSpiNames[i]; 117 assertNotNull(field + " can not be null.", className); 118 validateClass(field, ImageReaderSpi.class, loader, className); 119 } 120 } 121 } 122 } 123 124 /** 125 * Validates the given image reader or image writer provider. 126 * 127 * @param spi the provider to validate, or {@code null} if none. 128 */ 129 private void validateProvider(final ImageReaderWriterSpi spi, final Class<?> pluginType) { 130 mandatory("ImageReaderWriterSpi: shall have a vendorName string.", spi.getVendorName()); 131 mandatory("ImageReaderWriterSpi: shall have a version string.", spi.getVersion()); 132 final String[] formatNames = spi.getFormatNames(); 133 mandatory("ImageReaderWriterSpi: shall have a formatNames array.", formatNames); 134 validateArray("formatNames", formatNames); 135 validateArray("fileSuffixes", spi.getFileSuffixes()); 136 validateArray("MIMETypes", spi.getMIMETypes()); 137 validateClass("pluginClassName", pluginType, spi.getClass().getClassLoader(), spi.getPluginClassName()); 138 validateMetadataFormatName("Stream", spi.getNativeStreamMetadataFormatName(), spi.getExtraStreamMetadataFormatNames()); 139 validateMetadataFormatName("Image", spi.getNativeImageMetadataFormatName(), spi.getExtraImageMetadataFormatNames()); 140 /* 141 * Ensures that a IIOMetadataFormat can be instantiated for each declared format name. 142 * Then, invokes validate(IIOMetadataFormat) for each format. Note that the format are 143 * allowed to be null according Image I/O specification. 144 */ 145 if (spi.isStandardStreamMetadataFormatSupported()) { 146 assertSame("Expected the standard metadata format instance.", 147 IIOMetadataFormatImpl.getStandardFormatInstance(), 148 spi.getStreamMetadataFormat(IIOMetadataFormatImpl.standardMetadataFormatName)); 149 } 150 if (spi.isStandardImageMetadataFormatSupported()) { 151 assertSame("Expected the standard metadata format instance.", 152 IIOMetadataFormatImpl.getStandardFormatInstance(), 153 spi.getImageMetadataFormat(IIOMetadataFormatImpl.standardMetadataFormatName)); 154 } 155 String formatName = spi.getNativeStreamMetadataFormatName(); 156 if (formatName != null) { 157 validate(spi.getStreamMetadataFormat(formatName)); 158 } 159 formatName = spi.getNativeImageMetadataFormatName(); 160 if (formatName != null) { 161 validate(spi.getImageMetadataFormat(formatName)); 162 } 163 String[] names = spi.getExtraStreamMetadataFormatNames(); 164 if (names != null) { 165 for (final String name : names) { 166 validate(spi.getStreamMetadataFormat(name)); 167 } 168 } 169 names = spi.getExtraImageMetadataFormatNames(); 170 if (names != null) { 171 for (final String name : names) { 172 validate(spi.getImageMetadataFormat(name)); 173 } 174 } 175 } 176 177 /** 178 * Validates the image or stream metadata format names. 179 * This method ensures that there is no duplicated values. 180 */ 181 private static void validateMetadataFormatName(final String type, String nativeMetadataFormatName, 182 final String[] extraMetadataFormatNames) 183 { 184 if (nativeMetadataFormatName != null) { 185 nativeMetadataFormatName = nativeMetadataFormatName.trim(); 186 assertFalse("The native" + type + "MetadataFormatName value can not be equal to \"" + 187 IIOMetadataFormatImpl.standardMetadataFormatName + "\".", 188 IIOMetadataFormatImpl.standardMetadataFormatName.equalsIgnoreCase(nativeMetadataFormatName)); 189 } 190 if (extraMetadataFormatNames != null) { 191 final String field = "extra" + type + "MetadataFormatNames"; 192 validateArray(field, extraMetadataFormatNames); 193 for (int i=0; i<extraMetadataFormatNames.length; i++) { 194 final String formatName = extraMetadataFormatNames[i].trim(); 195 assertFalse("The " + field + '[' + i + "] value can not be equal to \"" + 196 IIOMetadataFormatImpl.standardMetadataFormatName + "\".", 197 IIOMetadataFormatImpl.standardMetadataFormatName.equalsIgnoreCase(formatName)); 198 if (nativeMetadataFormatName != null) { 199 assertFalse("The " + field + '[' + i + "] value can not be equal to \"" + 200 nativeMetadataFormatName + "\" since it is already declared as the native format name.", 201 nativeMetadataFormatName.equalsIgnoreCase(formatName)); 202 } 203 } 204 } 205 } 206 207 /** 208 * Ensures that the given array complies with the conditions of Java Image I/O. 209 * The array can be either null or non-empty; empty arrays are illegal. 210 * Then ensures that there is no duplicated value. 211 * 212 * @param field the field name, used in case of errors. 213 * @param array the array to validate, or {@code null} if none. 214 */ 215 private static void validateArray(final String field, final Object[] array) { 216 if (array != null) { 217 assertStrictlyPositive("The " + field + " array shall be either null or non-empty.", array.length); 218 for (int i=0; i<array.length; i++) { 219 final Object element = array[i]; 220 assertNotNull(field + '[' + i + ']', element); 221 for (int j=i; ++i<array.length;) { 222 if (element.equals(array[i])) { 223 fail(field + '[' + i + "] and [" + j + "] duplicate the \"" + element + "\" value."); 224 } 225 } 226 } 227 } 228 } 229 230 /** 231 * Ensure that given class exists and is an instance of the given type. 232 * 233 * @param field the name of the tested field. 234 * @param expectedType the expected base class. 235 * @param loader the loader to use for loading the class. 236 * @param classname the name of the class to test. 237 */ 238 private void validateClass(final String field, final Class<?> expectedType, 239 final ClassLoader loader, final String classname) 240 { 241 mandatory("ImageReaderWriterSpi: shall have a " + field + " string.", classname); 242 if (classname != null) try { 243 final Class<?> actual = Class.forName(classname, false, loader); 244 assertTrue(actual.getCanonicalName() + " is not an instance of " + 245 expectedType.getSimpleName() + '.', expectedType.isAssignableFrom(actual)); 246 } catch (ClassNotFoundException e) { 247 throw new AssertionError("Class \"" + classname + "\" declared in " + field + " was not found.", e); 248 } 249 } 250 251 /** 252 * Validates the given metadata format. 253 * 254 * @param format the metadata format to validate, or {@code null} if none. 255 */ 256 public void validate(final IIOMetadataFormat format) { 257 // Not yet implemented. 258 } 259}