/* 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.catalog.arcims;
import com.esri.gpt.framework.geometry.Envelope;
import com.esri.gpt.framework.security.credentials.UsernamePasswordCredentials;
import com.esri.gpt.framework.util.Val;
import com.esri.gpt.framework.xml.DomUtil;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.TreeSet;
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.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Extended Arc IMS query request. Provides capability to specify additional
* search/query parameters: text, bounding box, bounding box bounds.
*/
public class ExtendedQueryRequest extends QueryRequest {
/** date format */
private static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat("yyyy-MM-dd");
/** full text */
private String [] fullText = new String[]{};
/** bounding box */
private Envelope bbox;
/** spatial operator */
private SpatialOperator spatialOperator = SpatialOperator.anywhere;
/** folders */
private TreeSet<String> folders = new TreeSet<String>();
/**
* Creates instance of the request.
*/
public ExtendedQueryRequest() {
super();
}
/**
* Creates instance of the request.
* @param credentials credentials
*/
public ExtendedQueryRequest(UsernamePasswordCredentials credentials) {
super(credentials);
}
/**
* Sets full text to search.
* @param fullText full text to search
*/
public void setFullText(String [] fullText) {
this.fullText = fullText!=null? fullText: new String[]{};
}
/**
* Gets full text to search.
* @return full text to search
*/
public String [] getFullText() {
return fullText;
}
/**
* Sets bounding box.
* @param bbox bounding box
*/
public void setBBox(Envelope bbox) {
this.bbox = bbox;
}
/**
* Gets bounding box.
* @return bounding box
*/
public Envelope getBBox() {
return bbox;
}
/**
* Sets spatial operator.
* @param spatialOperator spatial operator
*/
public void setSpatialOperator(SpatialOperator spatialOperator) {
this.spatialOperator = spatialOperator!=null? spatialOperator: SpatialOperator.anywhere;
}
/**
* Gets spatial operator.
* @return spatial operator
*/
public SpatialOperator getSpatialOperator() {
return spatialOperator;
}
/**
* Gets folders.
* @return folders
*/
private TreeSet<String> getFolders() {
return folders;
}
/**
* Makes AXL request.
* @return AXL request
*/
private String makeAxlRequest() {
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.append("\r\n<ARCXML version=\"1.1\">");
sb.append("\r\n<REQUEST>");
sb.append("\r\n<GET_METADATA>");
sb.append("\r\n<SEARCH_METADATA fulloutput=\"false\"");
if (getMaxRec() > 0) {
sb.append(" maxresults=\"");
sb.append(Integer.toString(getMaxRec()));
sb.append("\"");
}
sb.append(">");
if (!getFolders().isEmpty()) {
String folderUuid = getFolders().first();
getFolders().remove(folderUuid);
sb.append("\r\n<SEARCH_METADATA><SUBSET type=\"children\" docid=\"" +folderUuid+ "\"/></SEARCH_METADATA>");
}
if (getBBox()!=null && getSpatialOperator()!=SpatialOperator.anywhere) {
sb.append("\r\n<ENVELOPE");
sb.append(" minx=\"" +getBBox().getMinX()+ "\"");
sb.append(" miny=\"" +getBBox().getMinY()+ "\"");
sb.append(" maxx=\"" +getBBox().getMaxX()+ "\"");
sb.append(" maxy=\"" +getBBox().getMaxY()+ "\"");
sb.append(" spatialoperator=\"" +getSpatialOperator()+ "\"");
sb.append("/>");
} else {
sb.append("\r\n<ENVELOPE");
sb.append(" minx=\"-180\"");
sb.append(" miny=\"-90\"");
sb.append(" maxx=\"180\"");
sb.append(" maxy=\"90\"");
sb.append(" spatialoperator=\"overlaps\"");
sb.append("/>");
}
if (getFullText()!=null && getFullText().length>0) {
for (String word : getFullText()) {
word = Val.chkStr(word);
if (word.length()>0) {
sb.append("\r\n<FULLTEXT word=\"" +word+ "\"/>");
}
}
}
if (getUpdatedAfterDate() != null || getUpdatedAfterDate() != null) {
sb.append("\r\n<SEARCH_METADATA");
if (getUpdatedAfterDate() != null) {
sb.append(" after=\"");
sb.append(DATE_FORMAT.format(getUpdatedAfterDate()));
sb.append("\"");
}
if (getUpdatedBeforeDate() != null) {
sb.append(" before=\"");
sb.append(DATE_FORMAT.format(getUpdatedBeforeDate()));
sb.append("\"");
}
sb.append("/>");
}
sb.append("\r\n</SEARCH_METADATA>");
sb.append("\r\n</GET_METADATA>");
sb.append("\r\n</REQUEST>");
sb.append("\r\n</ARCXML>");
return sb.toString();
}
/**
* Executes query.
* @throws ImsServiceException if error executing query
*/
@Override
public void execute() throws ImsServiceException {
getUuids().clear();
getFolders().clear();
do {
setAxlRequest(makeAxlRequest());
executeRequest();
if (wasActionOK()) {
try {
Document document =
DomUtil.makeDomFromString(getAxlResponse(), false);
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList) xPath.evaluate(
"ARCXML/RESPONSE/METADATA/METADATA_DATASET",
document, XPathConstants.NODESET);
for (int i=0; i<nodeList.getLength(); i++) {
if (Thread.currentThread().isInterrupted()) break;
if (getMaxRec()>0 && getUuids().size()>=getMaxRec()) break;
Node node = nodeList.item(i);
String docid = (String) xPath.evaluate("@docid", node, XPathConstants.STRING);
String name = (String) xPath.evaluate("@name", node, XPathConstants.STRING);
boolean folder = Val.chkBool((String) xPath.evaluate("@folder", node, XPathConstants.STRING), false);
if (!folder)
getUuids().add(docid);
else
getFolders().add(docid);
}
} catch (XPathExpressionException ex) {
throw new ImsResponseException("Response parse error.", ex);
} catch (ParserConfigurationException ex) {
throw new ImsResponseException("Response parse error.", ex);
} catch (SAXException ex) {
throw new ImsResponseException("Response parse error.", ex);
} catch (IOException ex) {
throw new ImsResponseException("Response parse error.", ex);
}
}
} while (!getFolders().isEmpty() && (getMaxRec()<=0 || getUuids().size()<getMaxRec()));
}
/**
* Spatial operator.
*/
public static enum SpatialOperator {
/** anywhere in the World */
anywhere,
/** may overlap specified bounding box */
overlaps,
/** has to completly contain within specified bounding box */
within
}
}