package com.revolsys.record.io.format.esri.rest;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.revolsys.collection.map.MapEx;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.io.BaseCloseable;
import com.revolsys.logging.Logs;
import com.revolsys.net.urlcache.FileResponseCache;
import com.revolsys.properties.ObjectWithProperties;
import com.revolsys.record.io.format.json.Json;
import com.revolsys.spring.resource.Resource;
import com.revolsys.spring.resource.UrlResource;
import com.revolsys.util.Exceptions;
import com.revolsys.util.Property;
import com.revolsys.util.UrlUtil;
import com.revolsys.util.WrappedException;
import com.revolsys.webservice.AbstractWebService;
import com.revolsys.webservice.WebService;
import com.revolsys.webservice.WebServiceResource;
public abstract class ArcGisResponse<V> extends AbstractWebService<V> implements CatalogElement {
public static final Map<String, ? extends Object> FORMAT_PARAMETER = Collections.singletonMap("f",
"json");
public static BoundingBox newBoundingBox(final MapEx properties, final String name) {
final MapEx extent = properties.getValue(name);
if (extent == null) {
return null;
} else {
final double minX = extent.getDouble("xmin");
final double minY = extent.getDouble("ymin");
final double maxX = extent.getDouble("xmax");
final double maxY = extent.getDouble("ymax");
final GeometryFactory geometryFactory = newGeometryFactory(extent, "spatialReference");
return geometryFactory.newBoundingBox(minX, minY, maxX, maxY);
}
}
public static GeometryFactory newGeometryFactory(final MapEx properties, final String fieldName) {
final MapEx spatialReference = properties.getValue(fieldName);
if (spatialReference == null) {
return GeometryFactory.DEFAULT_3D;
} else {
Integer srid = spatialReference.getInteger("latestWkid");
if (srid == null) {
srid = spatialReference.getInteger("wkid");
if (srid == null) {
final String wkt = spatialReference.getString("wkt");
if (Property.hasValue(wkt)) {
return GeometryFactory.getFactory(wkt);
} else {
return GeometryFactory.DEFAULT_3D;
}
} else if (srid == 102100) {
srid = 3857;
} else if (srid == 102190) {
srid = 3005;
}
}
return GeometryFactory.floating3(srid);
}
}
public static <T extends ObjectWithProperties> List<T> newList(final Class<T> clazz,
final MapEx properties, final String name) {
final List<T> objects = new ArrayList<>();
final List<MapEx> maps = properties.getValue(name);
if (maps != null) {
for (final MapEx map : maps) {
try {
final T value = clazz.newInstance();
value.setProperties(map);
objects.add(value);
} catch (final Throwable t) {
t.printStackTrace();
}
}
}
return objects;
}
public static <T extends ObjectWithProperties> T newObject(final Class<T> clazz,
final MapEx properties, final String name) {
final MapEx values = properties.getValue(name);
if (values == null) {
return null;
} else {
try {
final T value = clazz.newInstance();
value.setProperties(values);
return value;
} catch (final Throwable t) {
t.printStackTrace();
return null;
}
}
}
private CatalogElement parent;
private double currentVersion;
private boolean useProxy;
private final Object resfreshSync = new Object();
private boolean initialized = false;
private boolean hasError = false;
public ArcGisResponse() {
}
protected ArcGisResponse(final ArcGisResponse<?> parent) {
super(parent.getServiceUrl());
this.parent = parent;
this.useProxy = parent.isUseProxy();
}
protected ArcGisResponse(final ArcGisResponse<?> parent, final String name) {
super(parent.getServiceUrl().newChildResource(name));
setName(name);
this.parent = parent;
this.useProxy = parent.isUseProxy();
}
public double getCurrentVersion() {
return this.currentVersion;
}
@SuppressWarnings("unchecked")
@Override
public <R extends WebServiceResource> R getParent() {
return (R)this.parent;
}
@Override
public synchronized MapEx getProperties() {
final MapEx properties = super.getProperties();
if (Property.isEmpty(properties)) {
properties.put("initializing", true);
properties.put("initializing", false);
}
return properties;
}
public Resource getResource(final String child, final Map<String, ? extends Object> parameters) {
final UrlResource serviceUrl = getServiceUrl(child);
if (isUseProxy()) {
final StringBuilder queryUrl = new StringBuilder(serviceUrl.getUriString());
final String query = '?' + UrlUtil.getQueryString(parameters);
queryUrl.append(UrlUtil.percentEncode(query));
final String username = serviceUrl.getUsername();
final String password = serviceUrl.getPassword();
return new UrlResource(queryUrl, username, password);
} else {
return serviceUrl.newUrlResource(parameters);
}
}
@Override
public WebService<?> getWebService() {
if (this.parent == null) {
return this;
} else {
return this.parent.getWebService();
}
}
protected void initialize(final MapEx properties) {
setProperties(properties);
}
@Override
public boolean isHasError() {
return this.hasError;
}
public boolean isInitialized() {
return this.initialized;
}
@Override
public boolean isUseProxy() {
return this.useProxy;
}
@Override
public final void refresh() {
synchronized (this.resfreshSync) {
try (
BaseCloseable noCache = FileResponseCache.disable()) {
refreshDo();
this.hasError = false;
} catch (final WrappedException e) {
this.hasError = true;
final Throwable cause = Exceptions.unwrap(e);
if (cause instanceof UnknownHostException) {
Logs.error(this, "Cannot find host " + cause.getMessage());
}
} catch (final Throwable e) {
this.hasError = true;
throw Exceptions.wrap("Unable to initialize: " + this, e);
}
}
}
protected void refreshDo() {
final UrlResource serviceUrl = getServiceUrl();
final Resource resource;
if (isUseProxy()) {
final String url = serviceUrl.getUriString() + "%3ff%3djson";
final String username = serviceUrl.getUsername();
final String password = serviceUrl.getPassword();
resource = new UrlResource(url, username, password);
} else {
resource = serviceUrl.newUrlResource(Collections.singletonMap("f", "json"));
}
final MapEx newProperties = Json.toMap(resource);
initialize(newProperties);
}
public final void refreshIfNeeded() {
synchronized (this.resfreshSync) {
if (!this.initialized) {
this.initialized = true;
refresh();
}
}
}
public void setCurrentVersion(final double currentVersion) {
this.currentVersion = currentVersion;
}
protected void setInitialized(final boolean initialized) {
this.initialized = initialized;
}
public void setParent(final CatalogElement parent) {
this.parent = parent;
}
@Override
public void setServiceUrl(final UrlResource serviceUrl) {
super.setServiceUrl(serviceUrl);
this.useProxy = serviceUrl.getUriString().matches(".+\\?.+rest%2fservices.*");
}
@Override
public String toString() {
return getName() + "\t" + getServiceUrl();
}
}