/* 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.search;
import com.esri.gpt.catalog.context.CatalogConfiguration;
import com.esri.gpt.framework.context.ConfigurationException;
import com.esri.gpt.framework.context.RequestContext;
import com.esri.gpt.framework.geometry.Envelope;
import com.esri.gpt.framework.jsf.MessageBroker;
import com.esri.gpt.framework.util.LogUtil;
import com.esri.gpt.framework.util.Val;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
/**
* Builds the query parameters for a rest query URL.
*/
public class RestUrlBuilder {
/** class variables ========================================================= */
private static final SimpleDateFormat DF = new SimpleDateFormat("yyyy-MM-dd");
/** constructors ============================================================ */
/** Default constructor. */
public RestUrlBuilder() {}
/** methods ================================================================= */
/**
* Appends a parameter to the query parameters buffer.
* <br/>The parameter will not be appended if the value is null or empty.
* <br/>The parameter value will be URLEncoded prior to appending.
* @param parameters the query parameters buffer
* @param name the parameter name
* @param value the parameter value
*/
protected void appendParam(StringBuffer parameters, String name, String value) {
if ((value != null) && (value.length() > 0)) {
if (parameters.length() > 0) parameters.append("&");
parameters.append(name).append("=").append(this.encodeUrlParam(value));
}
}
/**
* Appends parameter value list to the query parameters buffer.
* <br/>The parameter will not be appended if the value list is null or empty.
* <br/>The parameter values will be concatenated with the delimiter prior to appending.
* <br/>The parameter values will be URLEncoded prior to appending.
* @param parameters the query parameters buffer
* @param name the parameter name
* @param delimiter the values delimiter
* @param values the parameter values
*/
protected void appendParam(StringBuffer parameters, String name, String delimiter, List<String> values) {
if ((values != null) && (values.size() > 0)) {
StringBuffer sb = new StringBuffer();
for (String value: values) {
value = Val.chkStr(value);
if (value.length() > 0) {
if (sb.length() > 0) sb.append(delimiter);
sb.append(value);
}
}
if (sb.length() > 0) {
this.appendParam(parameters,name,sb.toString());
}
}
}
/**
* Builds the rest URL query parameters string.
* @param criteria the search criteria from which the query parameters will be built.
* @param format the response format
* @param rid the repository id
* @return the query parameters string
*/
public String buildParameters(SearchCriteria criteria, String format, String rid) {
StringBuffer sb = new StringBuffer();
// keyword filter
if (criteria.getSearchFilterKeyword() != null) {
this.appendParam(sb,"searchText",criteria.getSearchFilterKeyword().getSearchText());
}
// spatial filter
ISearchFilterSpatialObj fSpatial = criteria.getSearchFilterSpatial();
if (fSpatial != null) {
Envelope env = fSpatial.getEnvelope();
if ((env != null) && env.isValid()) {
String sSpatialRel = "";
SearchFilterSpatial.OptionsBounds bounds = fSpatial.getSelectedBoundsAsEnum();
switch (bounds) {
case useGeogExtent:
sSpatialRel = "esriSpatialRelOverlaps";
break;
case dataWithinExtent:
sSpatialRel = "esriSpatialRelWithin";
break;
}
if (sSpatialRel.length() > 0) {
String sEnv = env.getMinX()+","+env.getMinY()+","+env.getMaxX()+","+env.getMaxY();
this.appendParam(sb,"bbox",sEnv);
if (sSpatialRel.equals("esriSpatialRelWithin")) {
this.appendParam(sb,"spatialRel",sSpatialRel);
}
}
}
}
// content type filter
if (criteria.getSearchFilterContentTypes() != null) {
this.appendParam(sb,"contentType",criteria.getSearchFilterContentTypes().getSelectedContentType());
}
// data category filter
if (criteria.getSearchFilterThemes() != null) {
this.appendParam(sb,"dataCategory",",",criteria.getSearchFilterThemes().getSelectedThemes());
}
// temporal filter
ISearchFilterTemporal fTemporal = criteria.getSearchFilterTemporal();
if (fTemporal != null) {
Date dtAfter = fTemporal.getDateModifiedFromAsDate();
Date dtBefore = fTemporal.getDateModifiedToAsDate();
if (dtAfter != null) {
this.appendParam(sb,"after",DF.format(dtAfter));
}
if (dtBefore != null) {
this.appendParam(sb,"before",DF.format(dtBefore));
}
}
// pagination filter (max only)
if (criteria.getSearchFilterPageCursor() != null) {
//this.appendParam(sb,"max",""+criteria.getSearchFilterPageCursor().getRecordsPerPage());
}
// sort filter
ISearchFilterSort fSort = criteria.getSearchFilterSort();
if (fSort != null) {
String sSort = fSort.getSelectedSort();
if ((sSort != null) && !sSort.equalsIgnoreCase(SearchFilterSort.OptionsSort.relevance.name())) {
this.appendParam(sb,"orderBy",sSort);
}
}
// repository id
this.appendParam(sb,"rid",Val.chkStr(rid));
// format
this.appendParam(sb,"f",Val.chkStr(format));
return sb.toString();
}
/**
* Encodes a URL parameter value.
* @param value the URL parameter value to encode
* @return the encoded parameter value
*/
protected String encodeUrlParam(String value) {
value = Val.chkStr(value);
try {
return URLEncoder.encode(value,"UTF-8");
} catch (UnsupportedEncodingException ex) {
LogUtil.getLogger().severe("Unsupported encoding: UTF-8");
return value;
}
}
/**
* Instantiates a new rest url builder.
* <p/>
* By default, a new instance of
* com.esri.gpt.catalog.search.RestUrlBuilder is returned.
* <p/>
* This can be overridden by the configuration parameter:
* /gptConfig/catalog/parameter@key="restUrlBuilder"
* @param context the active request context
* @param servletRequest the active HTTP servlet request
* @param messageBroker the message broker
* @return the rest url builder
*/
public static RestUrlBuilder newBuilder(RequestContext context,
HttpServletRequest servletRequest, MessageBroker messageBroker) {
// initialize
if (context == null) {
context = RequestContext.extract(servletRequest);
}
if (messageBroker == null) {
messageBroker = new MessageBroker();
messageBroker.setBundleBaseName("gpt.resources.gpt");
}
CatalogConfiguration catCfg = context.getCatalogConfiguration();
// look for a configured class name for the resource link builder
String className = Val.chkStr(catCfg.getParameters().getValue("restUrlBuilder"));
if (className.length() == 0) {
className = com.esri.gpt.catalog.search.RestUrlBuilder.class.getName();
}
// instantiate the builder
try {
Class<?> cls = Class.forName(className);
Object obj = cls.newInstance();
if (obj instanceof RestUrlBuilder) {
RestUrlBuilder builder = (RestUrlBuilder)obj;
return builder;
} else {
String sMsg = "The configured restUrlBuilder parameter is invalid: "+className;
throw new ConfigurationException(sMsg);
}
} catch (ConfigurationException t) {
throw t;
} catch (Throwable t) {
String sMsg = "Error instantiating rest url builder: "+className;
throw new ConfigurationException(sMsg, t);
}
}
}