/**
  * Tests all map projection creation.
  *
  * @throws FactoryException If a CRS can not be created.
  */
 @Test
 public void testMapProjections() throws FactoryException {
   out.println();
   out.println("Testing classification names");
   out.println("----------------------------");
   final CRSFactory crsFactory = ReferencingFactoryFinder.getCRSFactory(null);
   final MathTransformFactory mtFactory = ReferencingFactoryFinder.getMathTransformFactory(null);
   final Collection<OperationMethod> methods = mtFactory.getAvailableMethods(Projection.class);
   final Map<String, ?> dummyName = Collections.singletonMap("name", "Test");
   for (final OperationMethod method : methods) {
     final String classification = method.getName().getCode();
     final ParameterValueGroup param = mtFactory.getDefaultParameters(classification);
     try {
       param.parameter("semi_major").setValue(6377563.396);
       param.parameter("semi_minor").setValue(6356256.909237285);
     } catch (IllegalArgumentException e) {
       // Above parameters do not exists. Ignore.
     }
     final MathTransform mt;
     try {
       mt = mtFactory.createParameterizedTransform(param);
     } catch (FactoryException e) {
       // Probably not a map projection. This test is mostly about projection, so ignore.
       continue;
     } catch (UnsupportedOperationException e) {
       continue;
     }
     if (mt instanceof MapProjection) {
       /*
        * Tests map projection properties. Some tests are ommitted for south-oriented
        * map projections, since they are implemented as a concatenation of their North-
        * oriented variants with an affine transform.
        */
       out.println(classification);
       final boolean skip =
           classification.equalsIgnoreCase("Transverse Mercator (South Orientated)")
               || classification.equalsIgnoreCase("Equidistant_Cylindrical");
       if (!skip) {
         assertEquals(
             classification, ((MapProjection) mt).getParameterDescriptors().getName().getCode());
       }
       final ProjectedCRS projCRS =
           crsFactory.createProjectedCRS(
               dummyName,
               DefaultGeographicCRS.WGS84,
               new DefiningConversion(dummyName, method, mt),
               DefaultCartesianCS.PROJECTED);
       final Conversion conversion = projCRS.getConversionFromBase();
       assertSame(mt, conversion.getMathTransform());
       final OperationMethod projMethod = conversion.getMethod();
       assertEquals(classification, projMethod.getName().getCode());
     }
   }
 }
  public void testRead() throws Exception {
    URL url = TestData.url("shapes/pointtest.shp");
    ShapefileDataStore ds =
        (ShapefileDataStore) new ShapefileDataStoreFactory().createDataStore(url);

    Envelope env = ds.getFeatureSource().getBounds();
    CoordinateReferenceSystem crs = DefaultGeographicCRS.WGS84;
    MathTransform mt = CRS.findMathTransform(crs, DefaultGeographicCRS.WGS84);

    Rectangle rectangle = new Rectangle(300, 0, 300, 300);
    AffineTransform transform = RendererUtilities.worldToScreenTransform(env, rectangle);
    GeneralMatrix matrix = new GeneralMatrix(transform);
    MathTransform at =
        ReferencingFactoryFinder.getMathTransformFactory(null).createAffineTransform(matrix);
    mt = ReferencingFactoryFinder.getMathTransformFactory(null).createConcatenatedTransform(mt, at);

    ShapefileReader reader =
        new ShapefileReader(ShapefileRendererUtil.getShpFiles(ds), false, false);
    reader.setHandler(
        new org.geotools.renderer.shape.shapehandler.jts.PointHandler(
            reader.getHeader().getShapeType(), env, rectangle, mt, false));

    Object shape = reader.nextRecord().shape();
    assertNotNull(shape);
    assertTrue(shape instanceof Geometry);
    Coordinate[] coords = ((Geometry) shape).getCoordinates();
    for (int i = 0; i < coords.length; i++) {
      Coordinate coordinate = coords[i];
      assertNotNull(coordinate);
    }

    int i = 0;
    while (reader.hasNext()) {
      i++;
      shape = reader.nextRecord().shape();
      assertNotNull(shape);
      assertTrue(shape instanceof Geometry);
    }
    assertEquals(ds.getFeatureSource().getCount(Query.ALL) - 1, i);
  }
  private static MathTransform createTransverseMercatorMathTransform(
      TransverseMercatorDescriptor.TMT t) throws FactoryException {

    final MathTransformFactory transformFactory =
        ReferencingFactoryFinder.getMathTransformFactory(null);
    final ParameterValueGroup parameters = transformFactory.getDefaultParameters("EPSG:9807");

    parameters.parameter("semi_major").setValue(t.getSemiMajor());
    parameters.parameter("semi_minor").setValue(t.getSemiMinor());
    parameters.parameter("central_meridian").setValue(t.getCentralMeridian());
    parameters.parameter("latitude_of_origin").setValue(t.getLatitudeOfOrigin());
    parameters.parameter("scale_factor").setValue(t.getScaleFactor());
    parameters.parameter("false_easting").setValue(t.getFalseEasting());
    parameters.parameter("false_northing").setValue(t.getFalseNorthing());

    return transformFactory.createParameterizedTransform(parameters);
  }
  private static MathTransform createAlbersConicEqualAreaMathTransform(
      AlbersEqualAreaConicDescriptor.AEAC t) throws FactoryException {
    final MathTransformFactory transformFactory =
        ReferencingFactoryFinder.getMathTransformFactory(null);
    final ParameterValueGroup parameters = transformFactory.getDefaultParameters("EPSG:9822");

    parameters.parameter("semi_major").setValue(t.getSemiMajor());
    parameters.parameter("semi_minor").setValue(t.getSemiMinor());
    parameters.parameter("central_meridian").setValue(t.getCentralMeridian());
    parameters.parameter("latitude_of_origin").setValue(t.getLatitudeOfOrigin());
    parameters.parameter("standard_parallel_1").setValue(t.getStandardParallel1());
    parameters.parameter("standard_parallel_2").setValue(t.getStandardParallel2());
    parameters.parameter("false_easting").setValue(t.getFalseEasting());
    parameters.parameter("false_northing").setValue(t.getFalseNorthing());

    return transformFactory.createParameterizedTransform(parameters);
  }
  public static void attachGeoCoding(
      Product p,
      double upperLeftLon,
      double upperLeftLat,
      double lowerRightLon,
      double lowerRightLat,
      String projection,
      double[] projectionParameter) {
    double pixelSizeX = (lowerRightLon - upperLeftLon) / p.getSceneRasterWidth();
    double pixelSizeY = (upperLeftLat - lowerRightLat) / p.getSceneRasterHeight();

    AffineTransform transform = new AffineTransform();
    transform.translate(upperLeftLon, upperLeftLat);
    transform.scale(pixelSizeX, -pixelSizeY);
    transform.translate(PIXEL_CENTER, PIXEL_CENTER);
    Rectangle imageBounds = new Rectangle(p.getSceneRasterWidth(), p.getSceneRasterHeight());

    if (projection.equals("GCTP_GEO")) {
      if ((upperLeftLon >= -180 && upperLeftLon <= 180)
          && (upperLeftLat >= -90 && upperLeftLat <= 90)
          && (lowerRightLon >= -180 && lowerRightLon <= 180)
          && (lowerRightLat >= -90 && lowerRightLat <= 90)) {
        try {
          p.setGeoCoding(new CrsGeoCoding(DefaultGeographicCRS.WGS84, imageBounds, transform));
        } catch (FactoryException | TransformException ignore) {
        }
      }
    } else {
      if (projection.equals("GCTP_SNSOID")) {
        final MathTransformFactory transformFactory =
            ReferencingFactoryFinder.getMathTransformFactory(null);
        ParameterValueGroup parameters;
        try {
          parameters = transformFactory.getDefaultParameters("OGC:Sinusoidal");
        } catch (NoSuchIdentifierException ignore) {
          return;
        }
        double semi_major;
        double semi_minor;
        if (projectionParameter != null) {
          semi_major = projectionParameter[0];
          semi_minor = projectionParameter[1];
          if (semi_minor == 0) {
            semi_minor = semi_major;
          }
        } else {
          Ellipsoid ellipsoid = DefaultGeographicCRS.WGS84.getDatum().getEllipsoid();
          semi_major = ellipsoid.getSemiMajorAxis();
          semi_minor = ellipsoid.getSemiMinorAxis();
        }
        parameters.parameter("semi_major").setValue(semi_major);
        parameters.parameter("semi_minor").setValue(semi_minor);

        MathTransform mathTransform;
        try {
          mathTransform = transformFactory.createParameterizedTransform(parameters);
        } catch (Exception ignore) {
          return;
        }

        DefaultGeographicCRS base = DefaultGeographicCRS.WGS84;
        CoordinateReferenceSystem modelCrs =
            new DefaultProjectedCRS(
                "Sinusoidal", base, mathTransform, DefaultCartesianCS.PROJECTED);
        try {
          CrsGeoCoding geoCoding = new CrsGeoCoding(modelCrs, imageBounds, transform);

          p.setGeoCoding(geoCoding);
        } catch (Exception ignore) {
        }
      }
    }
  }
 /** Returns a factory of the given type. */
 private static final <T extends AbstractAuthorityFactory> T getFactory(final Class<T> type) {
   return type.cast(
       ReferencingFactoryFinder.getCRSAuthorityFactory(
           "EPSG", new Hints(Hints.CRS_AUTHORITY_FACTORY, type)));
 }
Beispiel #7
0
/**
 * Provides a filtered, sorted view over the available EPSG coordinate reference systems.
 *
 * @author Gabriel Roldan - OpenGeo
 * @author Andrea Aime - OpenGeo
 */
public class SRSProvider extends GeoServerDataProvider<SRSProvider.SRS> {

  private static final long serialVersionUID = 3731647638872356912L;

  /**
   * Spots integral numbers
   *
   * @see #buildCodeList()
   */
  private static Pattern NUMERIC = Pattern.compile("\\d+");

  /**
   * A lightweight bean to carry over the code and description of a {@link
   * CoordinateReferenceSystem}
   *
   * @author Gabriel Roldan - OpenGeo
   */
  public static class SRS implements Serializable, Comparable<SRS> {

    private static final long serialVersionUID = -4155644876049747585L;

    private String code;

    private transient String description;

    public SRS(String code) {
      this.code = code;
    }

    public String getCode() {
      return code;
    }

    public String getDescription() {
      // lazy loading of description
      if (description == null) {
        // grab the description
        String desc = "-";
        try {
          // REVISIT: as far as I know the EPSG names are not localized? anyway, if
          // they're revisit to use the page locale
          // description = CRS.getAuthorityFactory(true).getDescriptionText("EPSG:" +
          // code)
          // .toString(getLocale()).toUpperCase();
          desc = CRS.getAuthorityFactory(true).getDescriptionText("EPSG:" + code).toString();
        } catch (Exception e) {
          // no problem
        }
        description = desc;
      }
      return description;
    }

    @Override
    public boolean equals(Object o) {
      return code.equals(((SRS) o).code);
    }

    @Override
    public int hashCode() {
      return 17 * code.hashCode();
    }

    public int compareTo(SRS o) {
      return code.compareTo(o.code);
    }
  }

  /** custom geoserver crs factory which loads codes from epsg.properties file in data directory */
  private static CRSAuthorityFactory customFactory =
      ReferencingFactoryFinder.getCRSAuthorityFactory(
          "EPSG", new Hints(Hints.CRS_AUTHORITY_FACTORY, GeoserverCustomWKTFactory.class));

  public static final Property<SRS> CODE =
      new BeanProperty<SRS>("code", "code") {

        private static final long serialVersionUID = -1638823520421390286L;

        @Override
        public Comparator<SRS> getComparator() {
          return new CodeComparator();
        }
      };

  public static final Property<SRS> DESCRIPTION =
      new BeanProperty<SRS>("description", "description") {

        private static final long serialVersionUID = 3549074714488486991L;

        @Override
        public Comparator<SRS> getComparator() {
          return new Comparator<SRS>() {

            public int compare(SRS o1, SRS o2) {
              return String.CASE_INSENSITIVE_ORDER.compare(
                  o1.getDescription(), o2.getDescription());
            }
          };
        }
      };

  @SuppressWarnings("unchecked")
  private static final ArrayList<Property<SRS>> PROPERTIES =
      new ArrayList<Property<SRS>>(Arrays.asList(CODE, DESCRIPTION));

  private List<SRS> items;

  @Override
  protected List<SRS> getItems() {
    if (items == null) {
      synchronized (SRSProvider.class) {
        if (items == null) {
          items = buildCodeList();
        }
      }
    }
    return items;
  }

  @Override
  protected List<Property<SRS>> getProperties() {
    return PROPERTIES;
  }

  static List<SRS> buildCodeList() {
    long t = System.currentTimeMillis();
    Set<String> codes = CRS.getSupportedCodes("EPSG");

    try {
      codes.addAll(customFactory.getAuthorityCodes(CoordinateReferenceSystem.class));
    } catch (FactoryException e) {
      LOGGER.log(Level.WARNING, "Error occurred while trying to gather custom CRS codes", e);
    }

    // make a set with each code
    Set<SRS> idSet = new HashSet<SRS>();
    for (String code : codes) {
      // make sure we're using just the non prefix part
      String id = code.substring(code.indexOf(':') + 1);
      // avoid WGS84DD and eventual friends, as we're still not able to handle them,
      // if they are chosen exceptions arises everywhere
      if (NUMERIC.matcher(id).matches()) {
        idSet.add(new SRS(id));
      }
    }

    List<SRS> srsList = new ArrayList<SRS>(idSet);
    Collections.sort(srsList, new CodeComparator()); // sort to get them in order
    return srsList;
  }

  /**
   * Compares the codes so that most of the codes ger compared as numbers, but unfortunately some
   * non numeric ones can sneak in...
   *
   * @author Andrea Aime - TOPP
   */
  private static class CodeComparator implements Comparator<SRS> {

    public int compare(SRS srs1, SRS srs2) {
      String s1 = srs1.getCode();
      String s2 = srs2.getCode();
      Integer c1 = null, c2 = null;
      try {
        c1 = Integer.parseInt(s1);
      } catch (NumberFormatException e) {
        //
      }
      try {
        c2 = Integer.parseInt(s2);
      } catch (NumberFormatException e) {
        //
      }
      if (c1 == null) {
        if (c2 == null) return s1.compareTo(s2);
        else return -1;
      } else {
        if (c2 == null) return 1;
        else return c1 - c2;
      }
    }
  }
}
  /**
   * This method tries hard to stop all threads and remove all references to classes in GeoServer so
   * that we can avoid permgen leaks on application undeploy. What happes is that, if any JDK class
   * references to one of the classes loaded by the webapp classloader, then the classloader cannot
   * be collected and neither can all the classes loaded by it (since each class keeps a back
   * reference to the classloader that loaded it). The same happens for any residual thread launched
   * by the web app.
   */
  public void contextDestroyed(ServletContextEvent sce) {
    try {
      LOGGER.info("Beginning GeoServer cleanup sequence");

      // the dreaded classloader
      ClassLoader webappClassLoader = getClass().getClassLoader();

      // unload all of the jdbc drivers we have loaded. We need to store them and unregister
      // later to avoid concurrent modification exceptions
      Enumeration<Driver> drivers = DriverManager.getDrivers();
      Set<Driver> driversToUnload = new HashSet<Driver>();
      while (drivers.hasMoreElements()) {
        Driver driver = drivers.nextElement();
        try {
          // the driver class loader can be null if the driver comes from the JDK, such as the
          // sun.jdbc.odbc.JdbcOdbcDriver
          ClassLoader driverClassLoader = driver.getClass().getClassLoader();
          if (driverClassLoader != null && webappClassLoader.equals(driverClassLoader)) {
            driversToUnload.add(driver);
          }
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
      for (Driver driver : driversToUnload) {
        try {
          DriverManager.deregisterDriver(driver);
          LOGGER.info("Unregistered JDBC driver " + driver);
        } catch (Exception e) {
          LOGGER.log(Level.SEVERE, "Could now unload driver " + driver.getClass(), e);
        }
      }
      drivers = DriverManager.getDrivers();
      while (drivers.hasMoreElements()) {
        Driver driver = drivers.nextElement();
      }
      try {
        Class h2Driver = Class.forName("org.h2.Driver");
        Method m = h2Driver.getMethod("unload");
        m.invoke(null);
      } catch (Exception e) {
        LOGGER.log(Level.WARNING, "Failed to unload the H2 driver", e);
      }

      // unload all deferred authority factories so that we get rid of the timer tasks in them
      try {
        disposeAuthorityFactories(
            ReferencingFactoryFinder.getCoordinateOperationAuthorityFactories(null));
      } catch (Throwable e) {
        LOGGER.log(Level.WARNING, "Error occurred trying to dispose authority factories", e);
      }
      try {
        disposeAuthorityFactories(ReferencingFactoryFinder.getCRSAuthorityFactories(null));
      } catch (Throwable e) {
        LOGGER.log(Level.WARNING, "Error occurred trying to dispose authority factories", e);
      }
      try {
        disposeAuthorityFactories(ReferencingFactoryFinder.getCSAuthorityFactories(null));
      } catch (Throwable e) {
        LOGGER.log(Level.WARNING, "Error occurred trying to dispose authority factories", e);
      }

      // kill the threads created by referencing
      WeakCollectionCleaner.DEFAULT.exit();
      DeferredAuthorityFactory.exit();
      CRS.reset("all");
      LOGGER.info("Shut down GT referencing threads ");
      // reset
      ReferencingFactoryFinder.reset();
      CommonFactoryFinder.reset();
      DataStoreFinder.reset();
      DataAccessFinder.reset();
      LOGGER.info("Shut down GT  SPI ");

      LOGGER.info("Shut down coverage thread pool ");
      Object o = Hints.getSystemDefault(Hints.EXECUTOR_SERVICE);
      if (o != null && o instanceof ExecutorService) {
        final ThreadPoolExecutor executor = (ThreadPoolExecutor) o;
        try {
          executor.shutdown();
        } finally {
          try {
            executor.shutdownNow();
          } finally {

          }
        }
      }

      // unload everything that JAI ImageIO can still refer to
      // We need to store them and unregister later to avoid concurrent modification exceptions
      final IIORegistry ioRegistry = IIORegistry.getDefaultInstance();
      Set<IIOServiceProvider> providersToUnload = new HashSet();
      for (Iterator<Class<?>> cats = ioRegistry.getCategories(); cats.hasNext(); ) {
        Class<?> category = cats.next();
        for (Iterator it = ioRegistry.getServiceProviders(category, false); it.hasNext(); ) {
          final IIOServiceProvider provider = (IIOServiceProvider) it.next();
          if (webappClassLoader.equals(provider.getClass().getClassLoader())) {
            providersToUnload.add(provider);
          }
        }
      }
      for (IIOServiceProvider provider : providersToUnload) {
        ioRegistry.deregisterServiceProvider(provider);
        LOGGER.info("Unregistering Image I/O provider " + provider);
      }

      // unload everything that JAI can still refer to
      final OperationRegistry opRegistry = JAI.getDefaultInstance().getOperationRegistry();
      for (String mode : RegistryMode.getModeNames()) {
        for (Iterator descriptors = opRegistry.getDescriptors(mode).iterator();
            descriptors != null && descriptors.hasNext(); ) {
          RegistryElementDescriptor red = (RegistryElementDescriptor) descriptors.next();
          int factoryCount = 0;
          int unregisteredCount = 0;
          // look for all the factories for that operation
          for (Iterator factories = opRegistry.getFactoryIterator(mode, red.getName());
              factories != null && factories.hasNext(); ) {
            Object factory = factories.next();
            if (factory == null) {
              continue;
            }
            factoryCount++;
            if (webappClassLoader.equals(factory.getClass().getClassLoader())) {
              boolean unregistered = false;
              // we need to scan against all "products" to unregister the factory
              Vector orderedProductList = opRegistry.getOrderedProductList(mode, red.getName());
              if (orderedProductList != null) {
                for (Iterator products = orderedProductList.iterator();
                    products != null && products.hasNext(); ) {
                  String product = (String) products.next();
                  try {
                    opRegistry.unregisterFactory(mode, red.getName(), product, factory);
                    LOGGER.info("Unregistering JAI factory " + factory.getClass());
                  } catch (Throwable t) {
                    // may fail due to the factory not being registered against that product
                  }
                }
              }
              if (unregistered) {
                unregisteredCount++;
              }
            }
          }

          // if all the factories were unregistered, get rid of the descriptor as well
          if (factoryCount > 0 && unregisteredCount == factoryCount) {
            opRegistry.unregisterDescriptor(red);
          }
        }
      }

      // flush all javabean introspection caches as this too can keep a webapp classloader from
      // being unloaded
      Introspector.flushCaches();
      LOGGER.info("Cleaned up javabean caches");

      // unload the logging framework
      if (!relinquishLoggingControl) LogManager.shutdown();
      LogFactory.release(Thread.currentThread().getContextClassLoader());

      // GeoTools/GeoServer have a lot of finalizers and until they are run the JVM
      // itself wil keepup the class loader...
      try {
        System.gc();
        System.runFinalization();
        System.gc();
        System.runFinalization();
        System.gc();
        System.runFinalization();
      } catch (Throwable t) {
        LOGGER.severe("Failed to perform closing up finalization");
        t.printStackTrace();
      }
    } catch (Throwable t) {
      // if anything goes south during the cleanup procedures I want to know what it is
      t.printStackTrace();
    }
  }
  /**
   * Tests the creation of new coordinate reference systems.
   *
   * @throws FactoryException if a coordinate reference system can't be created.
   */
  @Test
  public void testCreation() throws FactoryException {
    out.println();
    out.println("Testing CRS creations");
    out.println("---------------------");
    out.println();
    out.println("create Coodinate Reference System....1: ");
    final DatumFactory datumFactory = ReferencingFactoryFinder.getDatumFactory(null);
    final CSFactory csFactory = ReferencingFactoryFinder.getCSFactory(null);
    final CRSFactory crsFactory = ReferencingFactoryFinder.getCRSFactory(null);
    final MathTransformFactory mtFactory = ReferencingFactoryFinder.getMathTransformFactory(null);

    final Ellipsoid airy1830;
    final Unit<Length> meters = SI.METER;
    airy1830 = datumFactory.createEllipsoid(name("Airy1830"), 6377563.396, 6356256.910, meters);
    out.println();
    out.println("create Coodinate Reference System....2: ");
    out.println(airy1830.toWKT());

    final PrimeMeridian greenwich;
    final Unit<Angle> degrees = NonSI.DEGREE_ANGLE;
    greenwich = datumFactory.createPrimeMeridian(name("Greenwich"), 0, degrees);
    out.println();
    out.println("create Coodinate Reference System....3: ");
    out.println(greenwich.toWKT());

    // NOTE: we could use the following pre-defined constant instead:
    //       DefaultPrimeMeridian.GREENWICH;
    final GeodeticDatum datum;
    datum = datumFactory.createGeodeticDatum(name("Airy1830"), airy1830, greenwich);
    out.println();
    out.println("create Coodinate Reference System....4: ");
    out.println(datum.toWKT());

    // NOTE: we could use the following pre-defined constant instead:
    //       DefaultEllipsoidalCS.GEODETIC_2D;
    final EllipsoidalCS ellCS;
    ellCS =
        csFactory.createEllipsoidalCS(
            name("Ellipsoidal"),
            csFactory.createCoordinateSystemAxis(
                name("Longitude"), "long", AxisDirection.EAST, degrees),
            csFactory.createCoordinateSystemAxis(
                name("Latitude"), "lat", AxisDirection.NORTH, degrees));
    out.println();
    out.println("create Coodinate Reference System....5: ");
    out.println(ellCS); // No WKT for coordinate systems

    final GeographicCRS geogCRS;
    geogCRS = crsFactory.createGeographicCRS(name("Airy1830"), datum, ellCS);
    out.println();
    out.println("create Coodinate Reference System....6: ");
    out.println(geogCRS.toWKT());

    final MathTransform p;
    final ParameterValueGroup param = mtFactory.getDefaultParameters("Transverse_Mercator");
    param.parameter("semi_major").setValue(airy1830.getSemiMajorAxis());
    param.parameter("semi_minor").setValue(airy1830.getSemiMinorAxis());
    param.parameter("central_meridian").setValue(49);
    param.parameter("latitude_of_origin").setValue(-2);
    param.parameter("false_easting").setValue(400000);
    param.parameter("false_northing").setValue(-100000);
    out.println();
    out.println("create Coodinate System....7: ");
    out.println(param);

    // NOTE: we could use the following pre-defined constant instead:
    //       DefaultCartesianCS.PROJECTED;
    final CartesianCS cartCS;
    cartCS =
        csFactory.createCartesianCS(
            name("Cartesian"),
            csFactory.createCoordinateSystemAxis(name("Easting"), "x", AxisDirection.EAST, meters),
            csFactory.createCoordinateSystemAxis(
                name("Northing"), "y", AxisDirection.NORTH, meters));
    out.println();
    out.println("create Coodinate Reference System....8: ");
    out.println(cartCS); // No WKT for coordinate systems

    final Hints hints = new Hints();
    hints.put(Hints.DATUM_FACTORY, datumFactory);
    hints.put(Hints.CS_FACTORY, csFactory);
    hints.put(Hints.CRS_FACTORY, crsFactory);
    hints.put(Hints.MATH_TRANSFORM_FACTORY, mtFactory);

    final ReferencingFactoryContainer container = new ReferencingFactoryContainer(hints);
    assertSame(datumFactory, container.getDatumFactory());
    assertSame(csFactory, container.getCSFactory());
    assertSame(crsFactory, container.getCRSFactory());
    assertSame(mtFactory, container.getMathTransformFactory());

    final Conversion conversion = new DefiningConversion("GBN grid", param);
    final ProjectedCRS projCRS =
        crsFactory.createProjectedCRS(
            name("Great_Britian_National_Grid"), geogCRS, conversion, cartCS);
    out.println();
    out.println("create Coodinate System....9: ");
    out.println(projCRS.toWKT());
  }
  /**
   * Tests datum aliases. Note: ellipsoid and prime meridian are dummy values just (not conform to
   * the usage in real world) just for testing purpose.
   *
   * @throws FactoryException If a CRS can not be created.
   */
  @Test
  public void testDatumAliases() throws FactoryException {
    final String name0 = "Nouvelle Triangulation Francaise (Paris)";
    final String name1 = "Nouvelle_Triangulation_Francaise_Paris";
    final String name2 = "D_NTF";
    final String name3 = "NTF (Paris meridian)";
    final Ellipsoid ellipsoid = DefaultEllipsoid.WGS84;
    final PrimeMeridian meridian = DefaultPrimeMeridian.GREENWICH;
    DatumFactory factory = new ReferencingObjectFactory();
    final Map<String, ?> properties = Collections.singletonMap("name", name1);
    GeodeticDatum datum = factory.createGeodeticDatum(properties, ellipsoid, meridian);
    assertTrue(datum.getAlias().isEmpty());

    for (int i = 0; i < 3; i++) {
      switch (i) {
        case 0:
          factory = new DatumAliases(factory);
          break;
        case 1:
          factory = ReferencingFactoryFinder.getDatumFactory(null);
          break;
        case 2:
          ((DatumAliases) factory).freeUnused();
          break;
        default:
          throw new AssertionError(); // Should not occurs.
      }
      final String pass = "******" + i;
      datum = factory.createGeodeticDatum(properties, ellipsoid, meridian);
      final GenericName[] aliases = datum.getAlias().toArray(new GenericName[0]);
      assertEquals(pass, 4, aliases.length);
      assertEquals(pass, name0, aliases[0].tip().toString());
      assertEquals(pass, name1, aliases[1].tip().toString());
      assertEquals(pass, name2, aliases[2].tip().toString());
      assertEquals(pass, name3, aliases[3].tip().toString());
      assertTrue(pass, aliases[0] instanceof ScopedName);
      assertTrue(pass, aliases[1] instanceof ScopedName);
      assertTrue(pass, aliases[2] instanceof ScopedName);
      assertTrue(pass, aliases[3] instanceof ScopedName);
    }

    datum =
        factory.createGeodeticDatum(Collections.singletonMap("name", "Tokyo"), ellipsoid, meridian);
    Collection<GenericName> aliases = datum.getAlias();
    assertEquals(4, aliases.size());

    ((DatumAliases) factory).freeUnused();
    datum =
        factory.createGeodeticDatum(
            Collections.singletonMap("name", "_toKyo  _"), ellipsoid, meridian);
    assertEquals(4, datum.getAlias().size());
    assertTrue(aliases.equals(datum.getAlias()));

    datum =
        factory.createGeodeticDatum(
            Collections.singletonMap("name", "D_Tokyo"), ellipsoid, meridian);
    assertEquals(4, datum.getAlias().size());

    datum =
        factory.createGeodeticDatum(
            Collections.singletonMap("name", "Luxembourg 1930"), ellipsoid, meridian);
    assertEquals(3, datum.getAlias().size());

    datum =
        factory.createGeodeticDatum(Collections.singletonMap("name", "Dummy"), ellipsoid, meridian);
    assertTrue("Non existing datum should have no alias.", datum.getAlias().isEmpty());

    datum =
        factory.createGeodeticDatum(
            Collections.singletonMap("name", "WGS 84"), ellipsoid, meridian);
    assertTrue(AbstractIdentifiedObject.nameMatches(datum, "WGS 84"));
    assertTrue(AbstractIdentifiedObject.nameMatches(datum, "WGS_1984"));
    assertTrue(AbstractIdentifiedObject.nameMatches(datum, "World Geodetic System 1984"));
    assertFalse(AbstractIdentifiedObject.nameMatches(datum, "WGS 72"));
  }
  public static CoordinateReferenceSystem getCRS(MapProjection projection, Datum datum) {
    CoordinateReferenceSystem result = WGS84;

    try {
      final MapTransform mapTransform = projection.getMapTransform();
      if (mapTransform.getDescriptor() instanceof IdentityTransformDescriptor) {
        // 1. Identity map projection
        if (Datum.ITRF_97.equals(datum)) {
          result = ITRF97;
        } else if (Datum.WGS_72.equals(datum)) {
          result = WGS72;
        }
      } else if (projection instanceof UTMProjection && !Datum.ITRF_97.equals(datum)) {
        // 2. UTM map projections
        final UTMProjection utmProjection = (UTMProjection) projection;
        final int zone = utmProjection.getZone();

        if (zone >= 1 && zone <= 60) {
          final CRSAuthorityFactory factory =
              ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG", null);
          if (utmProjection.isNorth()) {
            if (Datum.WGS_72.equals(datum)) {
              final int WGS72_UTM_zone_N_BASE = 32200;
              result = factory.createProjectedCRS("EPSG:" + (WGS72_UTM_zone_N_BASE + zone));
            } else if (Datum.WGS_84.equals(datum)) {
              final int WGS84_UTM_zone_N_BASE = 32600;
              result = factory.createProjectedCRS("EPSG:" + (WGS84_UTM_zone_N_BASE + zone));
            }
          } else {
            if (Datum.WGS_72.equals(datum)) {
              final int WGS72_UTM_zone_S_BASE = 32300;
              result = factory.createProjectedCRS("EPSG:" + (WGS72_UTM_zone_S_BASE + zone));
            } else if (Datum.WGS_84.equals(datum)) {
              final int WGS84_UTM_zone_S_BASE = 32700;
              result = factory.createProjectedCRS("EPSG:" + (WGS84_UTM_zone_S_BASE + zone));
            }
          }
        }
      } else if (Datum.ITRF_97.equals(datum)) {
        // 3. Other map projections
        final String crsName = "ITRF 97 / " + mapTransform.getDescriptor().getName();
        final MathTransform mathTransform = getMathTransform(mapTransform);
        if (mathTransform != null) {
          result =
              new DefaultProjectedCRS(crsName, ITRF97, mathTransform, DefaultCartesianCS.PROJECTED);
        }
      } else if (Datum.WGS_72.equals(datum)) {
        final String crsName = "WGS 72 / " + mapTransform.getDescriptor().getName();
        final MathTransform mathTransform = getMathTransform(mapTransform);
        if (mathTransform != null) {
          result =
              new DefaultProjectedCRS(crsName, WGS72, mathTransform, DefaultCartesianCS.PROJECTED);
        }
      } else if (Datum.WGS_84.equals(datum)) {
        final String crsName = "WGS 84 / " + mapTransform.getDescriptor().getName();
        final MathTransform mathTransform = getMathTransform(mapTransform);
        if (mathTransform != null) {
          result =
              new DefaultProjectedCRS(crsName, WGS84, mathTransform, DefaultCartesianCS.PROJECTED);
        }
      }
    } catch (FactoryException e) {
      // ignore
    }

    return result;
  }