/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2009, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/
package org.geotools.arcsde.util;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geotools.data.DataSourceException;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultEngineeringCRS;
import org.geotools.util.logging.Logging;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.esri.sde.sdk.client.SeCoordinateReference;
import com.esri.sde.sdk.pe.PeCoordinateSystem;
import com.esri.sde.sdk.pe.PeFactory;
import com.esri.sde.sdk.pe.PeGeographicCS;
import com.esri.sde.sdk.pe.PeProjectedCS;
import com.esri.sde.sdk.pe.PeProjectionException;
/**
* ArcSDE Java API related utility methods to be shared between the gce and dataaccess
* implementations
*
* @author Gabriel Roldan
*
* @source $URL$
* http://svn.osgeo.org/geotools/trunk/modules/plugin/arcsde/datastore/src/main/java/org
* /geotools/arcsde/util/ArcSDEUtils.java $
* @version $Id$
* @since 2.5.6
*/
public final class ArcSDEUtils {
public static final Logger LOGGER = Logging.getLogger("org.geotools.arcsde.gce");
private static final WeakHashMap<String, CoordinateReferenceSystem> PE_CS_TO_EPSG = new WeakHashMap<String, CoordinateReferenceSystem>();
private ArcSDEUtils() {
// private default constructor to stress the pure utility nature of this class
}
/**
* Gets the coordinate system that will be associated to the {@link GridCoverage}.
*
* @param rasterAttributes
* @return if {@code seCoordRef.getcoordSys()} is {@code null} returns
* {@link DefaultEngineeringCRS#CARTESIAN_2D}, otherwise an equivalent CRS from the EPSG
* database if found, or a CRS built from the seCoordRef WKT otherwise.
*/
public static CoordinateReferenceSystem findCompatibleCRS(
final SeCoordinateReference seCoordRef ) throws DataSourceException {
if (seCoordRef == null) {
LOGGER.fine("SeCoordinateReference is null, "
+ "using DefaultEngineeringCRS.CARTESIAN_2D");
return DefaultEngineeringCRS.CARTESIAN_2D;
}
final PeCoordinateSystem coordSys = seCoordRef.getCoordSys();
if (coordSys == null) {
LOGGER.fine("SeCoordinateReference.getCoordSys() is null, "
+ "using DefaultEngineeringCRS.CARTESIAN_2D");
return DefaultEngineeringCRS.CARTESIAN_2D;
}
final String peCoordSysName = coordSys.getName();
CoordinateReferenceSystem crs = PE_CS_TO_EPSG.get(peCoordSysName);
if (crs == null) {
Integer epsgCode = findEpsgCode(coordSys);
try {
if (epsgCode == null) {
LOGGER.warning("Couldn't determine EPSG code for this raster."
+ " Using SDE's WKT-like coordSysDescription() instead.");
crs = CRS.parseWKT(seCoordRef.getCoordSysDescription());
} else {
crs = CRS.decode("EPSG:" + epsgCode);
}
PE_CS_TO_EPSG.put(peCoordSysName, crs);
} catch (FactoryException e) {
LOGGER.log(Level.SEVERE, "", e);
throw new DataSourceException(e);
}
}
return crs;
}
private static Integer findEpsgCode( final PeCoordinateSystem coordSys )
throws DataSourceException {
final String peCoordSysName = coordSys.getName();
Integer epsgCode = null;
try {
final int[] seEpsgCodes;
if (coordSys instanceof PeGeographicCS) {
seEpsgCodes = PeFactory.geogcsCodelist();
} else if (coordSys instanceof PeProjectedCS) {
seEpsgCodes = PeFactory.projcsCodelist();
} else {
throw new RuntimeException("Shouldnt happen!: Unnkown SeCoordSys type: "
+ coordSys.getClass().getName());
}
int seEpsgCode;
PeCoordinateSystem candidate;
for( int i = 0; i < seEpsgCodes.length; i++ ) {
try {
seEpsgCode = seEpsgCodes[i];
candidate = (PeCoordinateSystem) PeFactory.factory(seEpsgCode);
// in ArcSDE 9.2, if the PeFactory doesn't support a projection it claimed to
// support, it returns 'null'. So check for it.
if (candidate != null && candidate.getName().trim().equals(peCoordSysName)) {
epsgCode = seEpsgCode;
break;
}
} catch (PeProjectionException pe) {
// Strangely SDE includes codes in the projcsCodeList() that
// it doesn't actually support.
// Catch the exception and skip them here.
}
}
} catch (PeProjectionException e) {
LOGGER.log(Level.SEVERE, "", e);
throw new DataSourceException(e);
}
return epsgCode;
}
}