/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.esri.gpt.control.webharvest.client.arcims;
import com.esri.gpt.catalog.arcims.ExtendedQueryRequest;
import com.esri.gpt.catalog.arcims.ExtendedQueryRequest.SpatialOperator;
import com.esri.gpt.catalog.arcims.HarvestMetadataRequest;
import com.esri.gpt.catalog.arcims.ImsServiceException;
import com.esri.gpt.catalog.search.ISearchFilterSpatialObj.OptionsBounds;
import com.esri.gpt.framework.http.HttpClientRequest;
import com.esri.gpt.framework.http.StringHandler;
import com.esri.gpt.framework.resource.query.Criteria;
import com.esri.gpt.framework.util.Val;
import com.esri.gpt.framework.xml.DomUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* ArcIMS service proxy.
*/
class ArcImsProxy {
/** logger */
private static final Logger LOGGER = Logger.getLogger(ArcImsProxy.class.getCanonicalName());
/** service info */
private ArcImsInfo info;
/**
* Creates instance of the proxy.
* @param info service info
*/
public ArcImsProxy(ArcImsInfo info) {
if (info==null) throw new IllegalArgumentException("No info provided.");
this.info = info;
}
/**
* Gets query request based on the criteria.
* @param criteria criteria
* @return query request
*/
public ExtendedQueryRequest getQueryRequest(Criteria criteria) {
ExtendedQueryRequest queryRequest = new ExtendedQueryRequest();
queryRequest.setService(info.newService());
queryRequest.setCredentials(info.newCredentials());
queryRequest.setBBox(criteria!=null? criteria.getBBox(): null);
queryRequest.setSpatialOperator(criteria!=null? convertBBoxOptions(criteria.getBBoxOption()): null);
queryRequest.setFullText(criteria!=null && criteria.getSearchText()!=null? criteria.getSearchText().split(" "): null);
queryRequest.setMaxRec(criteria!=null && criteria.getMaxRecords()!=null? criteria.getMaxRecords(): 0);
return queryRequest;
}
public String read(String sourceUri) throws IOException {
LOGGER.finer("Reading metadata of source URI: \"" +sourceUri+ "\" through proxy: "+this);
try {
HarvestMetadataRequest harvestMetadataRequest = new HarvestMetadataRequest();
harvestMetadataRequest.setService(info.newService());
harvestMetadataRequest.setCredentials(info.newCredentials());
harvestMetadataRequest.executeHarvest(sourceUri);
String md = harvestMetadataRequest.getMetadata();
if (md.length()==0) {
LOGGER.finer("Reading metadata of source URI: \"" +sourceUri+ "\" through proxy: "+this+"; Received no METADATA response.");
return "";
}
// this section 'fixes' metadata dataset information; it happens, that some
// of the elements are having invalid XML characters and that would cause
// parsing to fail.
Pattern pattern = Pattern.compile("\"[^\"]+\"");
Matcher matcher = pattern.matcher(md);
int start = 0;
ArrayList<int[]> sections = new ArrayList<int[]>();
while (matcher.find(start)) {
int [] section = new int[]{ matcher.start()+1, matcher.end()-1 };
sections.add(section);
start = matcher.end()+1;
}
for (int i = sections.size()-1; i>=0; i--) {
int [] section = sections.get(i);
String text = md.substring(section[0], section[1]);
text = Val.escapeXml(text);
md = md.substring(0,section[0]) + text + md.substring(section[1], md.length());
}
Document doc = DomUtil.makeDomFromString(md, false);
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
String url = (String) xPath.evaluate("/METADATA/METADATA_DATASET/@url", doc, XPathConstants.STRING);
LOGGER.finer("Reading metadata of id: \"" +sourceUri+ "\" through proxy: "+this+"; Received no metadata URL within METADATA response.");
if (url.length()==0) return "";
url = Val.chkStr(url).replaceAll("\\{", "%7B").replaceAll("\\}", "%7D");
HttpClientRequest cr = new HttpClientRequest();
cr.setUrl(url);
StringHandler sh = new StringHandler();
cr.setContentHandler(sh);
cr.execute();
String mdText = sh.getContent();
LOGGER.finer("Received metadata of id: \"" +sourceUri+ "\" through proxy: "+this);
LOGGER.finest(mdText);
return mdText;
} catch (XPathExpressionException ex) {
throw new IOException("Error accessing metadata. Cause: "+ex.getMessage());
} catch (SAXException ex) {
throw new IOException("Error accessing metadata. Cause: "+ex.getMessage());
} catch (ParserConfigurationException ex) {
throw new IOException("Error accessing metadata. Cause: "+ex.getMessage());
} catch (ImsServiceException ex) {
throw new IOException("Error accessing metadata. Cause: "+ex.getMessage());
}
}
@Override
public String toString() {
return info.toString();
}
/**
* Converts bounding box options bounds to spatial operator.
* @param options bounding box options bounds
* @return spatial operator
*/
private SpatialOperator convertBBoxOptions(OptionsBounds options) {
if (options!=null) {
switch (options) {
case useGeogExtent: return SpatialOperator.overlaps;
case dataWithinExtent: return SpatialOperator.within;
default: return SpatialOperator.anywhere;
}
} else {
return SpatialOperator.anywhere;
}
}
}