/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2004-2008, 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.referencing.crs;
// J2SE dependencies
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
// OpenGIS dependencies
import org.opengis.metadata.citation.Citation;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.IdentifiedObject;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.ObjectFactory;
import org.opengis.referencing.crs.CRSAuthorityFactory;
import org.opengis.referencing.crs.CRSFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.util.InternationalString;
// Geotools dependencies
import org.geotools.util.logging.Logging;
import org.geotools.factory.AbstractFactory;
import org.geotools.metadata.iso.citation.Citations;
import org.geotools.referencing.ReferencingFactoryFinder;
/**
* Default implementation for a coordinate reference system authority factory backed
* by the EPSG property file. This gives most of the benifits of using the EPSG
* database backed authority factory, in a nice, portable property file.
*
* @source $URL$
* @version $Id$
* @author Jody Garnett
* @author Rueben Schulz
*
* @deprecated Uses one of the other EPSG factories backed by a database instead.
*/
//not quite sure how I am going to create a new factory (what should the geoapi method be)
public class EPSGCRSAuthorityFactory extends AbstractFactory implements CRSAuthorityFactory {
private static final Logger LOGGER = Logging.getLogger("org.geotools.referencing.crs.EPSGCRSAuthorityFactory");
public static final String AUTHORITY = "EPSG";
public static final String AUTHORITY_PREFIX = "EPSG:";
//would be nice to cache crs objects for codes that have already been requested
/**
* The default coordinate system authority factory.
* Will be constructed only when first requested.
*/
protected static EPSGCRSAuthorityFactory DEFAULT;
/**
* The properties object for our properties file. Keys are the EPSG
* code for a coordinate reference system and the associated value is a
* WKT string for the CRS.
*/
protected Properties epsg = new Properties();
//object factory
protected CRSFactory crsFactory;
/** Cache of parsed CoordinateReferenceSystem WKT by EPSG_NUMBER */
private Hashtable cache = new Hashtable();
/**
* Loads from epsg.properties if the file exists, defaults to internal defintions
* exported from postgis and cubeworks.
*/
public EPSGCRSAuthorityFactory() {
this(ReferencingFactoryFinder.getCRSFactory(null));
}
/**
* Loads from epsg.properties if the file exists, defaults to internal defintions
* exported from postgis and cubeworks.
*/
protected EPSGCRSAuthorityFactory(final CRSFactory factory ) {
super(MINIMUM_PRIORITY); // Select EPSG-HSQL factory first.
this.crsFactory = factory;
try {
loadDefault();
}
catch( IOException oops ){
System.err.println("Could not load epsg.properties"+ oops );
}
}
/**
*
*/
protected EPSGCRSAuthorityFactory(final CRSFactory factory,
URL definition) throws FactoryException {
this( factory );
try {
epsg.load( definition.openStream() );
}
catch (IOException io ){
// could not load properties file
throw new FactoryException("Could not load properties file: " + definition);
}
}
/**
* Loads from epsg.properties if the file exists, defaults to internal defintions
* exported from postgis and cubeworks.
*
* @throws IOException
*/
protected void loadDefault() throws IOException {
// Check the application directory first
//
File file = new File("epsg.properties");
if( file.exists() ){
epsg.load( new FileInputStream( file ));
}
// Use the built-in property defintions
//
URL url = EPSGCRSAuthorityFactory.class.getResource("epsg.properties");
epsg.load( url.openStream() );
}
/**
* Returns a default coordinate system factory backed by the EPSG property file.
*
* @return The default factory.
* @throws SQLException if the connection to the database can't be etablished.
*/
public synchronized static CRSAuthorityFactory getDefault() {
if (DEFAULT == null) {
DEFAULT = new EPSGCRSAuthorityFactory();
}
return DEFAULT;
}
public synchronized CoordinateReferenceSystem createCoordinateReferenceSystem(String code)
throws FactoryException
{
if (code == null) {
return null;
}
if( !code.startsWith( AUTHORITY_PREFIX )){
throw new NoSuchAuthorityCodeException( "This factory only understand EPSG codes", AUTHORITY, code );
}
final String EPSG_NUMBER = code.substring( code.indexOf(':')+1 ).trim();
if( cache.containsKey( EPSG_NUMBER ) ){
Object value = cache.get( EPSG_NUMBER );
if( value instanceof Throwable ){
throw new FactoryException( "WKT for "+code+" could not be parsed", (Throwable) value );
}
if( value instanceof CoordinateReferenceSystem){
return (CoordinateReferenceSystem) value;
}
}
String wkt = epsg.getProperty( EPSG_NUMBER );
if( wkt == null ) {
throw new NoSuchAuthorityCodeException( "Unknown EPSG_NUMBER", AUTHORITY, code );
}
if( wkt.indexOf( EPSG_NUMBER ) == -1){
wkt = wkt.trim();
wkt = wkt.substring(0, wkt.length()-1 );
wkt += ",AUTHORITY[\"EPSG\",\""+EPSG_NUMBER+"\"]]";
LOGGER.log(Level.WARNING, "EPSG:"+EPSG_NUMBER+" lacks a proper identifying authority in its Well-Known Text. It is being added programmatically.");
}
try {
CoordinateReferenceSystem crs = crsFactory.createFromWKT(wkt);
cache.put(EPSG_NUMBER, crs);
return crs;
}
catch (FactoryException fex) {
cache.put(EPSG_NUMBER, fex);
throw fex;
}
}
public IdentifiedObject createObject(String code) throws FactoryException {
return createCoordinateReferenceSystem(code);
}
public ProjectedCRS createProjectedCRS(String code) throws FactoryException {
return (ProjectedCRS) createCoordinateReferenceSystem(code);
}
public GeographicCRS createGeographicCRS(String code) throws FactoryException {
return (GeographicCRS) createCoordinateReferenceSystem(code);
}
public Citation getAuthority() {
return Citations.EPSG;
}
/**
* Returns the set of authority codes of the given type. The type
* argument specify the base class. For example if this factory is
* an instance of CRSAuthorityFactory, then:
* <ul>
* <li>CoordinateReferenceSystem.class asks for all authority codes accepted
* by createGeographicCRS, createProjectedCRS, createVerticalCRS, createTemporalCRS and their friends.</li>
* <li>ProjectedCRS.class asks only for authority codes accepted by createProjectedCRS.</li>
* </ul>
*
* The following implementaiton filters the set of codes based on the
* "PROJCS" and "GEOGCS" at the start of the WKT strings. It is assumed
* that we only have GeographicCRS and ProjectedCRS's here.
*
* @param clazz The spatial reference objects type (may be Object.class).
* @return The set of authority codes for spatial reference objects of the given type.
* If this factory doesn't contains any object of the given type, then this method returns
* an empty set.
* @throws FactoryException if access to the underlying database failed.
*/
public Set getAuthorityCodes(Class clazz) throws FactoryException {
//could cashe this info if it is time consuming to filter
if (clazz.getName().equalsIgnoreCase(CoordinateReferenceSystem.class.getName())) {
Set all= new java.util.TreeSet();
for(java.util.Iterator i = epsg.keySet().iterator(); i.hasNext();) {
String code = (String) i.next();
all.add( AUTHORITY_PREFIX+code);
}
return all;
} else if (clazz.getName().equalsIgnoreCase(GeographicCRS.class.getName())) {
Set all = epsg.keySet();
Set geoCRS = new java.util.TreeSet();
for(java.util.Iterator i = all.iterator(); i.hasNext();) {
String code = (String) i.next();
String wkt = epsg.getProperty( code );
if (wkt.startsWith("GEOGCS")) {
geoCRS.add( AUTHORITY_PREFIX+code);
}
}
return geoCRS;
} else if (clazz.getName().equalsIgnoreCase(ProjectedCRS.class.getName())) {
Set all = epsg.keySet();
Set projCRS = new java.util.TreeSet();
for(java.util.Iterator i = all.iterator(); i.hasNext();) {
String code = (String) i.next();
String wkt = epsg.getProperty( code );
if (wkt.startsWith("PROJCS")) {
projCRS.add( AUTHORITY_PREFIX+code);
}
}
return projCRS;
} else {
return new java.util.TreeSet();
}
}
public ObjectFactory getObjectFactory() {
return crsFactory;
}
public Citation getVendor() {
return Citations.GEOTOOLS;
}
public InternationalString getDescriptionText(String code) throws FactoryException {
if (code == null) {
return null;
}
if (code.startsWith("EPSG:")) { // EPSG:26907
code = code.substring(5);
}
code = code.trim();
String wkt = epsg.getProperty( code );
if( wkt == null ) {
throw new FactoryException("Unknonwn EPSG code: '"+code+"'" );
}
wkt = wkt.trim();
int start = wkt.indexOf('"');
int end = wkt.indexOf('"',start + 1);
return new org.geotools.util.SimpleInternationalString(wkt.substring(start + 1, end));
}
public org.opengis.referencing.crs.CompoundCRS createCompoundCRS(String str) throws FactoryException {
throw new FactoryException("Not implemented");
}
public org.opengis.referencing.crs.DerivedCRS createDerivedCRS(String str) throws FactoryException {
throw new FactoryException("Not implemented");
}
public org.opengis.referencing.crs.EngineeringCRS createEngineeringCRS(String str) throws FactoryException {
throw new FactoryException("Not implemented");
}
public org.opengis.referencing.crs.GeocentricCRS createGeocentricCRS(String str) throws FactoryException {
throw new FactoryException("Not implemented");
}
public org.opengis.referencing.crs.ImageCRS createImageCRS(String str) throws FactoryException {
throw new FactoryException("Not implemented");
}
public org.opengis.referencing.crs.TemporalCRS createTemporalCRS(String str) throws FactoryException {
throw new FactoryException("Not implemented");
}
public org.opengis.referencing.crs.VerticalCRS createVerticalCRS(String str) throws FactoryException {
throw new FactoryException("Not implemented");
}
}