Home | History | Annotate | Download | only in imageio
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 /**
     18  * @author Rustem V. Rafikov
     19  * @version $Revision: 1.3 $
     20  */
     21 
     22 package javax.imageio;
     23 
     24 import javax.imageio.stream.ImageInputStream;
     25 import javax.imageio.stream.ImageOutputStream;
     26 import javax.imageio.spi.*;
     27 import java.io.File;
     28 import java.io.IOException;
     29 import java.io.InputStream;
     30 import java.io.OutputStream;
     31 import java.util.Iterator;
     32 import java.util.Arrays;
     33 import java.awt.image.BufferedImage;
     34 import java.awt.image.RenderedImage;
     35 import java.net.URL;
     36 
     37 /**
     38  * The ImageIO class provides static methods to perform reading and writing
     39  * operations using registered ImageReader and ImageWriter objects.
     40  *
     41  * @since Android 1.0
     42  */
     43 public final class ImageIO {
     44 
     45     /**
     46      * The constant registry.
     47      */
     48     private static final IIORegistry registry = IIORegistry.getDefaultInstance();
     49 
     50     /**
     51      * Instantiates a new ImageIO.
     52      */
     53     private ImageIO() {
     54     }
     55 
     56     /**
     57      * Scans for plug-ins in the class path, loads spi classes, and registers
     58      * them with the IIORegistry.
     59      */
     60     public static void scanForPlugins() {
     61         throw new UnsupportedOperationException("Not supported yet");
     62     }
     63 
     64     /**
     65      * Sets flag which indicates whether a cache file is used when creating
     66      * ImageInputStreams and ImageOutputStreams or not.
     67      *
     68      * @param useCache
     69      *            the use cache flag.
     70      */
     71     public static void setUseCache(boolean useCache) {
     72         throw new UnsupportedOperationException("Not supported yet");
     73     }
     74 
     75     /**
     76      * Gets the flag which indicates whether a cache file is used when creating
     77      * ImageInputStreams and ImageOutputStreams or not. This method returns the
     78      * current value which is set by setUseCache method.
     79      *
     80      * @return the use cache flag.
     81      */
     82     public static boolean getUseCache() {
     83         // TODO implement
     84         return false;
     85     }
     86 
     87     /**
     88      * Sets the cache directory.
     89      *
     90      * @param cacheDirectory
     91      *            the File which specifies a cache directory.
     92      */
     93     public static void setCacheDirectory(File cacheDirectory) {
     94         throw new UnsupportedOperationException("Not supported yet");
     95     }
     96 
     97     /**
     98      * Gets the directory where cache files are created, returned the file which
     99      * is set by setCacheDirectory method, or null.
    100      *
    101      * @return the File object which is set by setCacheDirectory method, or
    102      *         null.
    103      */
    104     public static File getCacheDirectory() {
    105         // TODO implement
    106         // -- null indicates system-dep default temporary directory
    107         return null;
    108     }
    109 
    110     /**
    111      * Creates an ImageInputStream from the specified Object. The specified
    112      * Object should obtain the input source such as File, or InputStream.
    113      *
    114      * @param input
    115      *            the input Object such as File, or InputStream.
    116      * @return the ImageInputStream object, or null.
    117      * @throws IOException
    118      *             if an I/O exception has occurred.
    119      */
    120     public static ImageInputStream createImageInputStream(Object input) throws IOException {
    121 
    122         if (input == null) {
    123             throw new IllegalArgumentException("input source cannot be NULL");
    124         }
    125 
    126         Iterator<ImageInputStreamSpi> it = registry.getServiceProviders(ImageInputStreamSpi.class,
    127                 true);
    128 
    129         while (it.hasNext()) {
    130             ImageInputStreamSpi spi = it.next();
    131             if (spi.getInputClass().isInstance(input)) {
    132                 return spi.createInputStreamInstance(input);
    133             }
    134         }
    135         return null;
    136     }
    137 
    138     /**
    139      * Creates an ImageOutputStream using the specified Object. The specified
    140      * Object should obtain the output source such as File, or OutputStream.
    141      *
    142      * @param output
    143      *            the output Object such as File, or OutputStream.
    144      * @return the ImageOutputStream object, or null.
    145      * @throws IOException
    146      *             if an I/O exception has occurred.
    147      */
    148     public static ImageOutputStream createImageOutputStream(Object output) throws IOException {
    149         if (output == null) {
    150             throw new IllegalArgumentException("output destination cannot be NULL");
    151         }
    152 
    153         Iterator<ImageOutputStreamSpi> it = registry.getServiceProviders(
    154                 ImageOutputStreamSpi.class, true);
    155 
    156         while (it.hasNext()) {
    157             ImageOutputStreamSpi spi = it.next();
    158             if (spi.getOutputClass().isInstance(output)) {
    159                 // todo - use getUseCache and getCacheDir here
    160                 return spi.createOutputStreamInstance(output);
    161             }
    162         }
    163         return null;
    164     }
    165 
    166     /**
    167      * Gets the array of format names as String which can be decoded by
    168      * registered ImageReader objects.
    169      *
    170      * @return the array of format names.
    171      */
    172     public static String[] getReaderFormatNames() {
    173         throw new UnsupportedOperationException("Not supported yet");
    174     }
    175 
    176     /**
    177      * Gets the array of MIME types as String which can be decoded by registered
    178      * ImageReader objects.
    179      *
    180      * @return the array of MIME types.
    181      */
    182     public static String[] getReaderMIMETypes() {
    183         throw new UnsupportedOperationException("Not supported yet");
    184     }
    185 
    186     /**
    187      * Gets the Iterator of registered ImageReader which are able to decode an
    188      * input data specified by input Object.
    189      *
    190      * @param input
    191      *            the input Object with encoded data such as ImageInputStream
    192      *            object.
    193      * @return the Iterator of registered ImageReader.
    194      */
    195     public static Iterator<ImageReader> getImageReaders(Object input) {
    196         if (input == null) {
    197             throw new NullPointerException("input cannot be NULL");
    198         }
    199 
    200         Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
    201                 new CanReadFilter(input), true);
    202 
    203         return new SpiIteratorToReadersIteratorWrapper(it);
    204     }
    205 
    206     /**
    207      * Gets the Iterator of registered ImageReader which are able to decode the
    208      * specified format.
    209      *
    210      * @param formatName
    211      *            the format name such as "jpeg", or "gif".
    212      * @return the Iterator of registered ImageReader.
    213      */
    214     public static Iterator<ImageReader> getImageReadersByFormatName(String formatName) {
    215         if (formatName == null) {
    216             throw new NullPointerException("format name cannot be NULL");
    217         }
    218 
    219         Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
    220                 new FormatFilter(formatName), true);
    221 
    222         return new SpiIteratorToReadersIteratorWrapper(it);
    223     }
    224 
    225     /**
    226      * Gets the Iterator which lists the registered ImageReader objects that are
    227      * able to decode files with the specified suffix.
    228      *
    229      * @param fileSuffix
    230      *            the file suffix such as "jpg".
    231      * @return the Iterator of registered ImageReaders.
    232      */
    233     public static Iterator<ImageReader> getImageReadersBySuffix(String fileSuffix) {
    234         if (fileSuffix == null) {
    235             throw new NullPointerException("suffix cannot be NULL");
    236         }
    237         Iterator<ImageReaderSpi> it = registry.getServiceProviders(ImageReaderSpi.class,
    238                 new SuffixFilter(fileSuffix), true);
    239 
    240         return new SpiIteratorToReadersIteratorWrapper(it);
    241     }
    242 
    243     /**
    244      * Gets the Iterator of registered ImageReader objects that are able to
    245      * decode files with the specified MIME type.
    246      *
    247      * @param MIMEType
    248      *            the MIME type such as "image/jpeg".
    249      * @return the Iterator of registered ImageReaders.
    250      */
    251     public static Iterator<ImageReader> getImageReadersByMIMEType(String MIMEType) {
    252         throw new UnsupportedOperationException("Not supported yet");
    253     }
    254 
    255     /**
    256      * Gets an array of Strings giving the names of the formats supported by
    257      * registered ImageWriter objects.
    258      *
    259      * @return the array of format names.
    260      */
    261     public static String[] getWriterFormatNames() {
    262         throw new UnsupportedOperationException("Not supported yet");
    263     }
    264 
    265     /**
    266      * Gets an array of Strings giving the MIME types of the formats supported
    267      * by registered ImageWriter objects.
    268      *
    269      * @return the array of MIME types.
    270      */
    271     public static String[] getWriterMIMETypes() {
    272         throw new UnsupportedOperationException("Not supported yet");
    273     }
    274 
    275     /**
    276      * Gets the Iterator which lists the registered ImageReader objects that are
    277      * able to encode the specified image format.
    278      *
    279      * @param formatName
    280      *            the image format name such as "jpeg".
    281      * @return the Iterator of registered ImageWriter.
    282      */
    283     public static Iterator<ImageWriter> getImageWritersByFormatName(String formatName) {
    284         if (formatName == null) {
    285             throw new NullPointerException("format name cannot be NULL");
    286         }
    287 
    288         Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
    289                 new FormatFilter(formatName), true);
    290 
    291         return new SpiIteratorToWritersIteratorWrapper(it);
    292     }
    293 
    294     /**
    295      * Gets the Iterator which lists the registered ImageReader objects that are
    296      * able to encode the specified suffix.
    297      *
    298      * @param fileSuffix
    299      *            the file suffix such as "jpg".
    300      * @return the Iterator of registered ImageWriter.
    301      */
    302     public static Iterator<ImageWriter> getImageWritersBySuffix(String fileSuffix) {
    303         if (fileSuffix == null) {
    304             throw new NullPointerException("suffix cannot be NULL");
    305         }
    306         Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
    307                 new SuffixFilter(fileSuffix), true);
    308         return new SpiIteratorToWritersIteratorWrapper(it);
    309     }
    310 
    311     /**
    312      * Gets the Iterator which lists the registered ImageReader objects that are
    313      * able to encode the specified MIME type.
    314      *
    315      * @param MIMEType
    316      *            the MIME type such as "image/jpeg".
    317      * @return the Iterator of registered ImageWriter.
    318      */
    319     public static Iterator<ImageWriter> getImageWritersByMIMEType(String MIMEType) {
    320         throw new UnsupportedOperationException("Not supported yet");
    321     }
    322 
    323     /**
    324      * Gets an ImageWriter object which corresponds to the specified
    325      * ImageReader, or returns null if the specified ImageReader is not
    326      * registered.
    327      *
    328      * @param reader
    329      *            the specified ImageReader.
    330      * @return the ImageWriter, or null.
    331      */
    332     public static ImageWriter getImageWriter(ImageReader reader) {
    333         throw new UnsupportedOperationException("Not supported yet");
    334     }
    335 
    336     /**
    337      * Gets an ImageReader object which corresponds to the specified
    338      * ImageWriter, or returns null if the specified ImageWriter is not
    339      * registered.
    340      *
    341      * @param writer
    342      *            the registered ImageWriter object.
    343      * @return the ImageReader.
    344      */
    345     public static ImageReader getImageReader(ImageWriter writer) {
    346         throw new UnsupportedOperationException("Not supported yet");
    347     }
    348 
    349     /**
    350      * Gets the Iterator of ImageWriter objects which are able to encode images
    351      * with the specified ImageTypeSpecifier and format.
    352      *
    353      * @param type
    354      *            the ImageTypeSpecifier, which defines layout.
    355      * @param formatName
    356      *            the format name.
    357      * @return the Iterator of ImageWriter objects.
    358      */
    359     public static Iterator<ImageWriter> getImageWriters(ImageTypeSpecifier type, String formatName) {
    360         if (type == null) {
    361             throw new NullPointerException("type cannot be NULL");
    362         }
    363 
    364         if (formatName == null) {
    365             throw new NullPointerException("format name cannot be NULL");
    366         }
    367 
    368         Iterator<ImageWriterSpi> it = registry.getServiceProviders(ImageWriterSpi.class,
    369                 new FormatAndEncodeFilter(type, formatName), true);
    370 
    371         return new SpiIteratorToWritersIteratorWrapper(it);
    372     }
    373 
    374     /**
    375      * Gets the Iterator of registered ImageTranscoders which are able to
    376      * transcode the metadata of the specified ImageReader object to a suitable
    377      * object for encoding by the specified ImageWriter.
    378      *
    379      * @param reader
    380      *            the specified ImageReader.
    381      * @param writer
    382      *            the specified ImageWriter.
    383      * @return the Iterator of registered ImageTranscoders.
    384      */
    385     public static Iterator<ImageTranscoder> getImageTranscoders(ImageReader reader,
    386             ImageWriter writer) {
    387         throw new UnsupportedOperationException("Not supported yet");
    388     }
    389 
    390     /**
    391      * Reads image data from the specified File and decodes it using the
    392      * appropriate registered ImageReader object. The File is wrapped in an
    393      * ImageInputStream.
    394      *
    395      * @param input
    396      *            the File to be read.
    397      * @return the BufferedImage decoded from the specified File, or null.
    398      * @throws IOException
    399      *             if an I/O exception has occurred.
    400      */
    401     public static BufferedImage read(File input) throws IOException {
    402         if (input == null) {
    403             throw new IllegalArgumentException("input == null!");
    404         }
    405 
    406         ImageInputStream stream = createImageInputStream(input);
    407         return read(stream);
    408     }
    409 
    410     /**
    411      * Reads image data from the specified InputStream and decodes it using an
    412      * appropriate registered an ImageReader object.
    413      *
    414      * @param input
    415      *            the InputStream.
    416      * @return the BufferedImage decoded from the specified InputStream, or
    417      *         null.
    418      * @throws IOException
    419      *             if an I/O exception has occurred.
    420      */
    421     public static BufferedImage read(InputStream input) throws IOException {
    422         if (input == null) {
    423             throw new IllegalArgumentException("input == null!");
    424         }
    425 
    426         ImageInputStream stream = createImageInputStream(input);
    427         return read(stream);
    428     }
    429 
    430     /**
    431      * Reads image data from the specified URL and decodes it using the
    432      * appropriate registered ImageReader object.
    433      *
    434      * @param input
    435      *            the URL to be read.
    436      * @return the BufferedImage decoded from the specified URL, or null.
    437      * @throws IOException
    438      *             if an I/O exception has occurred.
    439      */
    440     public static BufferedImage read(URL input) throws IOException {
    441         if (input == null) {
    442             throw new IllegalArgumentException("input == null!");
    443         }
    444 
    445         InputStream stream = input.openStream();
    446         BufferedImage res = read(stream);
    447         stream.close();
    448 
    449         return res;
    450     }
    451 
    452     /**
    453      * Reads image data from the specified ImageInputStream and decodes it using
    454      * appropriate registered an ImageReader object.
    455      *
    456      * @param stream
    457      *            the ImageInputStream.
    458      * @return the BufferedImage decoded from the specified ImageInputStream, or
    459      *         null.
    460      * @throws IOException
    461      *             if an I/O exception has occurred.
    462      */
    463     public static BufferedImage read(ImageInputStream stream) throws IOException {
    464         if (stream == null) {
    465             throw new IllegalArgumentException("stream == null!");
    466         }
    467 
    468         Iterator<ImageReader> imageReaders = getImageReaders(stream);
    469         if (!imageReaders.hasNext()) {
    470             return null;
    471         }
    472 
    473         ImageReader reader = imageReaders.next();
    474         reader.setInput(stream, false, true);
    475         BufferedImage res = reader.read(0);
    476         reader.dispose();
    477 
    478         try {
    479             stream.close();
    480         } catch (IOException e) {
    481             // Stream could be already closed, proceed silently in this case
    482         }
    483 
    484         return res;
    485     }
    486 
    487     /**
    488      * Writes the specified image in the specified format (using an appropriate
    489      * ImageWriter) to the specified ImageOutputStream.
    490      *
    491      * @param im
    492      *            the RenderedImage.
    493      * @param formatName
    494      *            the format name.
    495      * @param output
    496      *            the ImageOutputStream where Image to be written.
    497      * @return true, if Image is written successfully, false otherwise.
    498      * @throws IOException
    499      *             if an I/O exception has occurred.
    500      */
    501     public static boolean write(RenderedImage im, String formatName, ImageOutputStream output)
    502             throws IOException {
    503 
    504         if (im == null) {
    505             throw new IllegalArgumentException("image cannot be NULL");
    506         }
    507         if (formatName == null) {
    508             throw new IllegalArgumentException("format name cannot be NULL");
    509         }
    510         if (output == null) {
    511             throw new IllegalArgumentException("output cannot be NULL");
    512         }
    513 
    514         Iterator<ImageWriter> it = getImageWriters(ImageTypeSpecifier.createFromRenderedImage(im),
    515                 formatName);
    516         if (it.hasNext()) {
    517             ImageWriter writer = it.next();
    518             writer.setOutput(output);
    519             writer.write(im);
    520             output.flush();
    521             writer.dispose();
    522             return true;
    523         }
    524         return false;
    525     }
    526 
    527     /**
    528      * Writes the specified image in the specified format (using an appropriate
    529      * ImageWriter) to the specified File.
    530      *
    531      * @param im
    532      *            the RenderedImage.
    533      * @param formatName
    534      *            the format name.
    535      * @param output
    536      *            the output File where Image to be written.
    537      * @return true, if Image is written successfully, false otherwise.
    538      * @throws IOException
    539      *             if an I/O exception has occurred.
    540      */
    541     public static boolean write(RenderedImage im, String formatName, File output)
    542             throws IOException {
    543 
    544         if (output == null) {
    545             throw new IllegalArgumentException("output cannot be NULL");
    546         }
    547 
    548         if (output.exists()) {
    549             output.delete();
    550         }
    551 
    552         ImageOutputStream ios = createImageOutputStream(output);
    553         boolean rt = write(im, formatName, ios);
    554         ios.close();
    555         return rt;
    556     }
    557 
    558     /**
    559      * Writes the specified image in the specified format (using an appropriate
    560      * ImageWriter) to the specified OutputStream.
    561      *
    562      * @param im
    563      *            the RenderedImage.
    564      * @param formatName
    565      *            the format name.
    566      * @param output
    567      *            the OutputStream where Image is to be written.
    568      * @return true, if Image is written successfully, false otherwise.
    569      * @throws IOException
    570      *             if an I/O exception has occurred.
    571      */
    572     public static boolean write(RenderedImage im, String formatName, OutputStream output)
    573             throws IOException {
    574 
    575         if (output == null) {
    576             throw new IllegalArgumentException("output cannot be NULL");
    577         }
    578 
    579         ImageOutputStream ios = createImageOutputStream(output);
    580         boolean rt = write(im, formatName, ios);
    581         ios.close();
    582         return rt;
    583     }
    584 
    585     /**
    586      * Filter to match spi by format name.
    587      */
    588     static class FormatFilter implements ServiceRegistry.Filter {
    589 
    590         /**
    591          * The name.
    592          */
    593         private String name;
    594 
    595         /**
    596          * Instantiates a new format filter.
    597          *
    598          * @param name
    599          *            the name.
    600          */
    601         public FormatFilter(String name) {
    602             this.name = name;
    603         }
    604 
    605         public boolean filter(Object provider) {
    606             ImageReaderWriterSpi spi = (ImageReaderWriterSpi)provider;
    607             return Arrays.asList(spi.getFormatNames()).contains(name);
    608         }
    609     }
    610 
    611     /**
    612      * Filter to match spi by format name and encoding possibility.
    613      */
    614     static class FormatAndEncodeFilter extends FormatFilter {
    615 
    616         /**
    617          * The type.
    618          */
    619         private ImageTypeSpecifier type;
    620 
    621         /**
    622          * Instantiates a new format and encode filter.
    623          *
    624          * @param type
    625          *            the type.
    626          * @param name
    627          *            the name.
    628          */
    629         public FormatAndEncodeFilter(ImageTypeSpecifier type, String name) {
    630             super(name);
    631             this.type = type;
    632         }
    633 
    634         @Override
    635         public boolean filter(Object provider) {
    636             ImageWriterSpi spi = (ImageWriterSpi)provider;
    637             return super.filter(provider) && spi.canEncodeImage(type);
    638         }
    639     }
    640 
    641     /**
    642      * Filter to match spi by suffix.
    643      */
    644     static class SuffixFilter implements ServiceRegistry.Filter {
    645 
    646         /**
    647          * The suf.
    648          */
    649         private String suf;
    650 
    651         /**
    652          * Instantiates a new suffix filter.
    653          *
    654          * @param suf
    655          *            the suf.
    656          */
    657         public SuffixFilter(String suf) {
    658             this.suf = suf;
    659         }
    660 
    661         public boolean filter(Object provider) {
    662             ImageReaderWriterSpi spi = (ImageReaderWriterSpi)provider;
    663             return Arrays.asList(spi.getFileSuffixes()).contains(suf);
    664         }
    665     }
    666 
    667     /**
    668      * Filter to match spi by decoding possibility.
    669      */
    670     static class CanReadFilter implements ServiceRegistry.Filter {
    671 
    672         /**
    673          * The input.
    674          */
    675         private Object input;
    676 
    677         /**
    678          * Instantiates a new can read filter.
    679          *
    680          * @param input
    681          *            the input.
    682          */
    683         public CanReadFilter(Object input) {
    684             this.input = input;
    685         }
    686 
    687         public boolean filter(Object provider) {
    688             ImageReaderSpi spi = (ImageReaderSpi)provider;
    689             try {
    690                 return spi.canDecodeInput(input);
    691             } catch (IOException e) {
    692                 return false;
    693             }
    694         }
    695     }
    696 
    697     /**
    698      * Wraps Spi's iterator to ImageWriter iterator.
    699      */
    700     static class SpiIteratorToWritersIteratorWrapper implements Iterator<ImageWriter> {
    701 
    702         /**
    703          * The backend.
    704          */
    705         private Iterator<ImageWriterSpi> backend;
    706 
    707         /**
    708          * Instantiates a new spi iterator to writers iterator wrapper.
    709          *
    710          * @param backend
    711          *            the backend.
    712          */
    713         public SpiIteratorToWritersIteratorWrapper(Iterator<ImageWriterSpi> backend) {
    714             this.backend = backend;
    715         }
    716 
    717         /**
    718          * Next.
    719          *
    720          * @return the image writer.
    721          */
    722         public ImageWriter next() {
    723             try {
    724                 return backend.next().createWriterInstance();
    725             } catch (IOException e) {
    726                 e.printStackTrace();
    727                 return null;
    728             }
    729         }
    730 
    731         /**
    732          * Checks for next.
    733          *
    734          * @return true, if successful.
    735          */
    736         public boolean hasNext() {
    737             return backend.hasNext();
    738         }
    739 
    740         /**
    741          * Removes the.
    742          */
    743         public void remove() {
    744             throw new UnsupportedOperationException(
    745                     "Use deregisterServiceprovider instead of Iterator.remove()");
    746         }
    747     }
    748 
    749     /**
    750      * Wraps spi's iterator to ImageReader iterator.
    751      */
    752     static class SpiIteratorToReadersIteratorWrapper implements Iterator<ImageReader> {
    753 
    754         /**
    755          * The backend.
    756          */
    757         private Iterator<ImageReaderSpi> backend;
    758 
    759         /**
    760          * Instantiates a new spi iterator to readers iterator wrapper.
    761          *
    762          * @param backend
    763          *            the backend.
    764          */
    765         public SpiIteratorToReadersIteratorWrapper(Iterator<ImageReaderSpi> backend) {
    766             this.backend = backend;
    767         }
    768 
    769         /**
    770          * Next.
    771          *
    772          * @return the image reader.
    773          */
    774         public ImageReader next() {
    775             try {
    776                 return backend.next().createReaderInstance();
    777             } catch (IOException e) {
    778                 e.printStackTrace();
    779                 return null;
    780             }
    781         }
    782 
    783         /**
    784          * Checks for next.
    785          *
    786          * @return true, if successful.
    787          */
    788         public boolean hasNext() {
    789             return backend.hasNext();
    790         }
    791 
    792         /**
    793          * Removes the.
    794          */
    795         public void remove() {
    796             throw new UnsupportedOperationException(
    797                     "Use deregisterServiceprovider instead of Iterator.remove()");
    798         }
    799     }
    800 }
    801