Coverage Report - org.geotoolkit.referencing.factory.epsg.PropertyEpsgFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
PropertyEpsgFactory
18 %
10/54
0 %
0/14
3
 
 1  
 /*
 2  
  *    Geotoolkit.org - An Open Source Java GIS Toolkit
 3  
  *    http://www.geotoolkit.org
 4  
  *
 5  
  *    (C) 2005-2012, Open Source Geospatial Foundation (OSGeo)
 6  
  *    (C) 2009-2012, Geomatys
 7  
  *
 8  
  *    This library is free software; you can redistribute it and/or
 9  
  *    modify it under the terms of the GNU Lesser General Public
 10  
  *    License as published by the Free Software Foundation;
 11  
  *    version 2.1 of the License.
 12  
  *
 13  
  *    This library is distributed in the hope that it will be useful,
 14  
  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 15  
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 16  
  *    Lesser General Public License for more details.
 17  
  */
 18  
 package org.geotoolkit.referencing.factory.epsg;
 19  
 
 20  
 import java.util.Set;
 21  
 import java.util.Map;
 22  
 import java.util.TreeSet;
 23  
 import java.util.TreeMap;
 24  
 import java.io.PrintWriter;
 25  
 import java.io.IOException;
 26  
 import net.jcip.annotations.ThreadSafe;
 27  
 
 28  
 import org.opengis.util.FactoryException;
 29  
 import org.opengis.metadata.citation.Citation;
 30  
 import org.opengis.referencing.IdentifiedObject;
 31  
 import org.opengis.referencing.crs.CRSAuthorityFactory;
 32  
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 33  
 
 34  
 import org.geotoolkit.factory.Hints;
 35  
 import org.geotoolkit.factory.AuthorityFactoryFinder;
 36  
 import org.geotoolkit.referencing.factory.AbstractAuthorityFactory;
 37  
 import org.geotoolkit.referencing.factory.wkt.PropertyAuthorityFactory;
 38  
 import org.geotoolkit.metadata.iso.citation.Citations;
 39  
 import org.geotoolkit.io.TableWriter;
 40  
 import org.geotoolkit.io.IndentedLineWriter;
 41  
 import org.geotoolkit.resources.Vocabulary;
 42  
 
 43  
 
 44  
 /**
 45  
  * Authority factory for {@linkplain CoordinateReferenceSystem Coordinate Reference Systems}
 46  
  * beyong the one defined in the EPSG database. This factory is used as a fallback when a
 47  
  * requested code is not found in the EPSG database, or when there is no connection at all
 48  
  * to the EPSG database. The CRS are defined as <cite>Well Known Text</cite> in a property
 49  
  * file named {@value #FILENAME}. The search path is as below, in that order:
 50  
  *
 51  
  * <ol>
 52  
  *   <li><p>If a value for {@link Hints#CRS_AUTHORITY_EXTRA_DIRECTORY} exists in the hints map
 53  
  *       given at construction time, then that value will be used as the directory where to
 54  
  *       search for the {@value #FILENAME} file. Reminder: such hint can be
 55  
  *       {@linkplain Hints#putSystemDefault defined system-wide} for convenience.</p></li>
 56  
  *   <li><p>The {@value #FILENAME} files found in all {@code org/geotoolkit/referencing/factory/epsg}
 57  
  *       directories on the classpath are merged with the values found in previous step, if any.
 58  
  *       If the same value is defined twice, the value of previous step have precedence.</p></li>
 59  
  * </ol>
 60  
  *
 61  
  * This factory can also be used to provide custom extensions or overrides to a main EPSG factory:
 62  
  *
 63  
  * <ul>
 64  
  *   <li><p>In order to provide a custom extension, you can create a subclass that invoke the
 65  
  *   {@link #PropertyEpsgFactory(Hints, String, Citation[])} constructor with different constants.
 66  
  *   You can also subclass {@link PropertyAuthorityFactory} directly for getting more control.</p></li>
 67  
  *
 68  
  *   <li><p>In order to make the factory be an override, override the
 69  
  *   {@link #setOrdering setOrdering(...)} method as below:
 70  
  *
 71  
  * {@preformat java
 72  
  *     protected void setOrdering(Organizer organizer) {
 73  
  *         organizer.before(ThreadedEpsgFactory.class);
 74  
  *     }
 75  
  * }</p></li>
 76  
  * </ul>
 77  
  *
 78  
  * {@section Caching of CRS objects}
 79  
  * This factory doesn't cache any result. Any call to a {@code createFoo} method
 80  
  * will trig a new WKT parsing. For adding caching service, this factory should
 81  
  * be wrapped in {@link org.geotoolkit.referencing.factory.CachingAuthorityFactory}.
 82  
  * Note that this is done automatically when this factory is used through the
 83  
  * {@link org.geotoolkit.referencing.CRS} static methods.
 84  
  *
 85  
  * {@section Troubleshotting}
 86  
  * If the {@value #FILENAME} file is on the classpath but seems to be ignored,
 87  
  * the following actions may provide some useful informations:
 88  
  *
 89  
  * <ul>
 90  
  *   <li><p>Print the list of every registered factories using the code snippet documented
 91  
  *       in the {@link org.geotoolkit.referencing.factory.FactoryDependencies} class and verify
 92  
  *       that {@code PropertyEpsgFactory} is presents.</p></li>
 93  
  *
 94  
  *   <li><p>Set the logging level for the {@code org.geotoolkit} loggers to {@code CONFIG}.
 95  
  *       See <a href="http://java.sun.com/javase/6/docs/technotes/guides/logging/overview.html">Java
 96  
  *       Logging Overview</a> for the standard way, or use the following Geotk convenience method:
 97  
  *
 98  
  *       {@preformat java
 99  
  *         Logging.GEOTOOLKIT.forceMonolineConsoleOutput(Level.CONFIG);
 100  
  *       }
 101  
  *       </p></li>
 102  
  *
 103  
  *   <li><p>Force the system to ignore any factory other than {@code PropertyEpsgFactory}:
 104  
  *
 105  
  *       {@preformat java
 106  
  *         Hints.putSystemDefault(Hints.CRS_AUTHORITY_FACTORY, PropertyEpsgFactory.class);
 107  
  *       }
 108  
  *       </p></li>
 109  
  * </ul>
 110  
  *
 111  
  * @author Martin Desruisseaux (IRD)
 112  
  * @author Jody Garnett (Refractions)
 113  
  * @author Rueben Schulz (UBC)
 114  
  * @author Andrea Aime (TOPP)
 115  
  * @version 3.00
 116  
  *
 117  
  * @since 2.1
 118  
  * @module
 119  
  */
 120  
 @ThreadSafe
 121  
 public class PropertyEpsgFactory extends PropertyAuthorityFactory implements CRSAuthorityFactory {
 122  
     /**
 123  
      * The default filename to read, which is {@value}. The default
 124  
      * {@code PropertyEpsgFactory} implementation will search for every occurrences of
 125  
      * {@code org/geotoolkit/referencing/factory/espg/epsg.properties} on the classpath.
 126  
      * However a different directory for this filename can be specified using
 127  
      * {@link Hints#CRS_AUTHORITY_EXTRA_DIRECTORY}.
 128  
      */
 129  
     public static final String FILENAME = "epsg.properties";
 130  
 
 131  
     /**
 132  
      * Constructs a default authority factory.
 133  
      *
 134  
      * @throws IOException If an error occurred while reading the definition files.
 135  
      *         Note that do exception is thrown if there is no file - in this case
 136  
      *         the factory is only considered not {@linkplain #availability available}.
 137  
      */
 138  
     public PropertyEpsgFactory() throws IOException {
 139  1
         this(EMPTY_HINTS);
 140  1
     }
 141  
 
 142  
     /**
 143  
      * Constructs an authority factory from the given hints.
 144  
      * Hints of special interest are:
 145  
      * <p>
 146  
      * <ul>
 147  
      *   <li>{@link Hints#CRS_AUTHORITY_EXTRA_DIRECTORY}</li>
 148  
      *   <li>{@link Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER}</li>
 149  
      * </ul>
 150  
      * <p>
 151  
      * This constructor recognizes also {@link Hints#CRS_FACTORY CRS}, {@link Hints#CS_FACTORY CS},
 152  
      * {@link Hints#DATUM_FACTORY DATUM} and {@link Hints#MATH_TRANSFORM_FACTORY MATH_TRANSFORM}
 153  
      * {@code FACTORY} hints.
 154  
      *
 155  
      * @param userHints An optional set of hints, or {@code null} if none.
 156  
      * @throws IOException If an error occurred while reading the definition files.
 157  
      *         Note that do exception is thrown if there is no file - in this case
 158  
      *         the factory is only considered not {@linkplain #availability available}.
 159  
      */
 160  
     public PropertyEpsgFactory(final Hints userHints) throws IOException {
 161  2
         this(userHints, FILENAME, Citations.EPSG);
 162  2
     }
 163  
 
 164  
     /**
 165  
      * Constructs an authority factory for the given authorities. This constructor recognizes
 166  
      * the same hints than {@link #PropertyEpsgFactory(Hints)}. The {@code authorities} argument
 167  
      * should enumerate all relevant authorities, with {@linkplain Citations#EPSG EPSG} in last
 168  
      * position. For example {@link EsriExtension} returns {{@linkplain Citations#ESRI ESRI},
 169  
      * {@linkplain Citations#EPSG EPSG}}.
 170  
      *
 171  
      * @param userHints
 172  
      *          An optional set of hints, or {@code null} if none.
 173  
      * @param filename
 174  
      *          The name of the file to look in the {@link Hints#CRS_AUTHORITY_EXTRA_DIRECTORY}
 175  
      *          directory and in every {@code org/geotoolkit/referencing/factory/espg} directories
 176  
      *          found on the classpath.
 177  
      * @param authorities
 178  
      *          The organizations or parties responsible for definition and maintenance of the
 179  
      *          database. Should contains at least {@link Citations#EPSG}.
 180  
      * @throws IOException If an error occurred while reading the definition files.
 181  
      *         Note that do exception is thrown if there is no file - in this case
 182  
      *         the factory is only considered not {@linkplain #availability available}.
 183  
      *
 184  
      * @since 3.00
 185  
      */
 186  
     public PropertyEpsgFactory(final Hints userHints, final String filename, final Citation... authorities)
 187  
             throws IOException
 188  
     {
 189  8
         super(userHints, Hints.CRS_AUTHORITY_EXTRA_DIRECTORY, PropertyEpsgFactory.class, filename, authorities);
 190  8
     }
 191  
 
 192  
     /**
 193  
      * Invoked by {@code FactoryRegistry} on registration. The default implementation
 194  
      * declares that this factory should give precedence to {@link ThreadedEpsgFactory}
 195  
      * and {@link LongitudeFirstEpsgFactory}.
 196  
      */
 197  
     @Override
 198  
     protected void setOrdering(final Organizer organizer) {
 199  1
         super.setOrdering(organizer);
 200  1
         organizer.after(ThreadedEpsgFactory.class, true);
 201  1
         organizer.after(LongitudeFirstEpsgFactory.class, false);
 202  1
     }
 203  
 
 204  
     /**
 205  
      * Prints a list of codes that duplicate the ones provided by {@link ThreadedEpsgFactory}.
 206  
      * This is used in order to check the content of the {@value #FILENAME} file (or whatever
 207  
      * property file used as backing store for this factory) from the command line.
 208  
      *
 209  
      * {@preformat text
 210  
      *     java -jar geotk-referencing.jar test duplicates
 211  
      * }
 212  
      *
 213  
      * @param  out The writer where to print the report.
 214  
      * @return The set of duplicated codes.
 215  
      * @throws FactoryException if an error occurred.
 216  
      *
 217  
      * @see org.geotoolkit.console.ReferencingCommands#test
 218  
      *
 219  
      * @since 2.4
 220  
      */
 221  
     public Set<String> reportDuplicates(final PrintWriter out) throws FactoryException {
 222  0
         final AbstractAuthorityFactory sqlFactory =
 223  
                 (AbstractAuthorityFactory) AuthorityFactoryFinder.getCRSAuthorityFactory(
 224  
                 "EPSG", new Hints(Hints.CRS_AUTHORITY_FACTORY, ThreadedEpsgFactory.class));
 225  0
         final Vocabulary resources = Vocabulary.getResources(null);
 226  0
         out.println(resources.getLabel(Vocabulary.Keys.COMPARE_WITH));
 227  
         try {
 228  0
             final IndentedLineWriter w = new IndentedLineWriter(out);
 229  0
             w.setIndentation(4);
 230  0
             w.write(sqlFactory.getBackingStoreDescription());
 231  0
             w.flush();
 232  0
         } catch (IOException e) {
 233  
             // Should never happen, since we are writing to a PrintWriter.
 234  0
             throw new AssertionError(e);
 235  0
         }
 236  0
         out.println();
 237  0
         final Set<String> wktCodes   = this.      getAuthorityCodes(IdentifiedObject.class);
 238  0
         final Set<String> sqlCodes   = sqlFactory.getAuthorityCodes(IdentifiedObject.class);
 239  0
         final Set<String> duplicated = new TreeSet<String>();
 240  0
         for (String code : wktCodes) {
 241  0
             code = code.trim();
 242  0
             if (sqlCodes.contains(code)) {
 243  0
                 duplicated.add(code);
 244  
                 /*
 245  
                  * Note: we don't use wktCodes.retainsAll(sqlCode) because the Set implementations
 246  
                  *       are usually not the standard ones, but rather some implementations backed
 247  
                  *       by a connection to the resources of the underlying factory. We also close
 248  
                  *       the connection after this loop for the same reason.  In addition, we take
 249  
                  *       this opportunity for sorting the codes.
 250  
                  */
 251  
             }
 252  
         }
 253  0
         if (duplicated.isEmpty()) {
 254  0
             out.println(resources.getString(Vocabulary.Keys.NO_DUPLICATION_FOUND));
 255  
         } else {
 256  0
             for (final String code : duplicated) {
 257  0
                 out.print(resources.getLabel(Vocabulary.Keys.DUPLICATED_VALUE));
 258  0
                 out.println(code);
 259  
             }
 260  
         }
 261  0
         return duplicated;
 262  
     }
 263  
 
 264  
     /**
 265  
      * Prints a list of CRS that can't be instantiated. This is used in order to check the content
 266  
      * of the {@value #FILENAME} file (or whatever property file used as backing store for this
 267  
      * factory) from the command line. To lauch from the command line, use the following:
 268  
      *
 269  
      * {@preformat text
 270  
      *     java -jar geotk-referencing.jar test creates
 271  
      * }
 272  
      *
 273  
      * @param  out The writer where to print the report.
 274  
      * @return The set of codes that can't be instantiated.
 275  
      * @throws FactoryException if an error occurred while
 276  
      *         {@linkplain #getAuthorityCodes fetching authority codes}.
 277  
      *
 278  
      * @see org.geotoolkit.console.ReferencingCommands#test
 279  
      *
 280  
      * @since 2.4
 281  
      */
 282  
     public Set<String> reportInstantiationFailures(final PrintWriter out) throws FactoryException {
 283  0
         final Set<String> codes = getAuthorityCodes(CoordinateReferenceSystem.class);
 284  0
         final Map<String,String> failures = new TreeMap<String,String>();
 285  0
         for (final String code : codes) {
 286  
             try {
 287  0
                 createCoordinateReferenceSystem(code);
 288  0
             } catch (FactoryException exception) {
 289  0
                 failures.put(code, exception.getLocalizedMessage());
 290  0
             }
 291  
         }
 292  0
         if (!failures.isEmpty()) {
 293  0
             final TableWriter writer = new TableWriter(out, " ");
 294  0
             for (final Map.Entry<String,String> entry : failures.entrySet()) {
 295  0
                 writer.write(entry.getKey());
 296  0
                 writer.write(':');
 297  0
                 writer.nextColumn();
 298  0
                 writer.write(entry.getValue());
 299  0
                 writer.nextLine();
 300  
             }
 301  
             try {
 302  0
                 writer.flush();
 303  0
             } catch (IOException e) {
 304  
                 // Should not happen, since we are writing to a PrintWriter
 305  0
                 throw new AssertionError(e);
 306  0
             }
 307  
         }
 308  0
         return failures.keySet();
 309  
     }
 310  
 }