/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.web.wicket;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.regex.Pattern;
import org.geotools.factory.Hints;
import org.geotools.referencing.CRS;
import org.geotools.referencing.ReferencingFactoryFinder;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CRSAuthorityFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.vfny.geoserver.crs.GeoserverCustomWKTFactory;
/**
* 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());
}
};
}
};
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;
}
}
}
}