/* 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 java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import com.esri.gpt.catalog.context.CatalogConfiguration;
import com.esri.gpt.catalog.search.SearchEngineCSW.Scheme;
import com.esri.gpt.control.georss.RestQueryServlet;
import com.esri.gpt.control.georss.SearchResultRecordAdapter;
import com.esri.gpt.framework.collection.StringAttribute;
import com.esri.gpt.framework.context.ApplicationContext;
import com.esri.gpt.framework.context.ConfigurationException;
import com.esri.gpt.framework.context.RequestContext;
import com.esri.gpt.framework.jsf.MessageBroker;
import com.esri.gpt.framework.search.DcList;
import com.esri.gpt.framework.search.SearchXslRecord;
import com.esri.gpt.framework.util.LogUtil;
import com.esri.gpt.framework.util.Val;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Builds the collection of bind-able links associated with a document or resource.
*/
public class ResourceLinkBuilder {
/**
* Service types.
*/
public static enum ServiceType {AGS, AIMS, WMS, WCS, WFS}
public static final String RESOURCE_TYPE = "resourceType";
private static final Logger LOG = Logger.getLogger(
ResourceLinkBuilder.class.getCanonicalName());
/** instance variables ====================================================== */
private String baseContextPath = "";
private final String externalMetadataPath = "/catalog/search/dsFullMetadata.page";
private final String imagePath = "/catalog/images";
private String mapViewerUrl = "";
private final String metadataPath = "/rest/document";
private final String previewPath = "/catalog/livedata/preview.page";
private final String resourceDetailsPath = "/catalog/search/resource/details.page";
private final String resourcePreviewPath = "/catalog/search/resource/livedata-preview.page";
private final Map<String, String> labels = new HashMap<String, String>();
private MessageBroker messageBroker;
private RequestContext requestContext;
private ResourceIdentifier resourceIdentifier;
/** constructors ============================================================ */
/** Default constructor. */
public ResourceLinkBuilder() {
}
/** properties ============================================================== */
/**
* Gets the base context path associated with the HTTP servlet request.
* <br/>(<i>http://<host:port>/<Context></i>)
* @return the base context path
*/
protected String getBaseContextPath() {
String path = this.getRelativePath();
if(path == null) {
path = this.baseContextPath;
}
return path;
}
/**
* Gets the relative path.
*
* @return the relative path
*/
private String getRelativePath() {
try {
@SuppressWarnings("unchecked")
Map<String, String> extraArgsMap = (Map<String, String>) this
.getRequestContext().getObjectMap()
.get(RestQueryServlet.EXTRA_REST_ARGS_MAP);
if (extraArgsMap == null) {
return null;
}
Object obj = extraArgsMap
.get(RestQueryServlet.PARAM_KEY_SHOW_RELATIVE_URLS);
if (obj == null) {
return null;
}
boolean showRel = Val.chkBool(obj.toString(), false);
if (showRel == false) {
return null;
}
if (Val.chkStr(this.baseContextPath).equals("")) {
return null;
}
String tmpContextPath = this.baseContextPath.replaceAll("/$", "");
tmpContextPath = tmpContextPath.replaceAll(".*/", "/");
return tmpContextPath;
} catch (Throwable e) {
LOG.log(Level.FINER, "", e);
}
return null;
}
/**
* Sets the base context path associated with the HTTP servlet request.
* <br/>(<i>http://<host:port>/<Context></i>)
* @param path the base context path
*/
protected void setBaseContextPath(String path) {
this.baseContextPath = Val.chkStr(path);
}
/**
* Gets the map viewer url.
* @return the map viewer url
*/
protected String getMapViewerUrl() {
return this.mapViewerUrl;
}
/**
* Gets the resource bundle message broker.
* @return the message broker
*/
protected MessageBroker getMessageBroker() {
return messageBroker;
}
/**
* Sets the resource bundle message broker.
* @param messageBroker the message broker
*/
protected void setMessageBroker(MessageBroker messageBroker) {
this.messageBroker = messageBroker;
}
/**
* Gets the associated request context.
* @return the request context
*/
protected RequestContext getRequestContext() {
return this.requestContext;
}
/**
* Gets the resource identifier associated with the request.
* @return the resource identifier
*/
protected ResourceIdentifier getResourceIdentifier() {
return this.resourceIdentifier;
}
/**
* Sets the resource identifier associated with the request.
* @param resourceIdentifier the resource identifier
*/
protected void setResourceIdentifier(ResourceIdentifier resourceIdentifier) {
this.resourceIdentifier = resourceIdentifier;
}
/** methods ================================================================= */
/**
* Builds the bind-able resource links associated with a resultant search record.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
public void build(SearchXslRecord xRecord, SearchResultRecord record) {
// determine the primary resource URL
this.determineResourceUrl(xRecord, record);
// build the content type and thumbnail links
this.buildContentTypeLink(xRecord, record);
this.buildThumbnailLink(xRecord, record);
// build remaining links
this.buildOpenLink(xRecord, record);
this.buildPreviewLink(xRecord, record);
this.buildAGSLinks(xRecord, record);
this.buildAddToMapLink(xRecord, record);
this.buildWebsiteLink(xRecord, record);
this.buildDetailsLink(xRecord, record);
this.buildMetadataLink(xRecord, record);
this.buildCustomLinks(xRecord, record);
}
/**
* Builds the link associated with adding a service to the map viewer.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
protected void buildAddToMapLink(SearchXslRecord xRecord, SearchResultRecord record) {
if(!xRecord.getLinks().readShowLink(ResourceLink.TAG_ADDTOMAP)) {
return;
}
String resourceUrl = Val.chkStr(record.getResourceUrl());
String serviceType = Val.chkStr(record.getServiceType()).toLowerCase();
String serviceName = Val.chkStr(record.getService());
String viewerUrl = Val.chkStr(this.getMapViewerUrl());
IMapViewer iMapViewer = null;
if ((viewerUrl.length() != 0)) {
// return if a map viewer link cannot be built
if (resourceUrl.length() == 0 || (serviceType.length() == 0)) {
return;
} else {
boolean canHandle = (serviceType.equalsIgnoreCase(ServiceType.AGS.name())
|| serviceType.equalsIgnoreCase(ServiceType.AIMS.name())
|| serviceType.equalsIgnoreCase(ServiceType.WMS.name())
|| serviceType.equalsIgnoreCase(ServiceType.WFS.name()) || serviceType
.equalsIgnoreCase(ServiceType.WCS.name()));
if (!canHandle)
return;
}
} else {
iMapViewer = MapViewerFactory.createMapViewer(resourceUrl, serviceType,
new SearchResultRecordAdapter(record), this.getRequestContext());
if (iMapViewer == null) {
return;
}
String addToMapUrl = iMapViewer.readAddToMapUrl();
if(addToMapUrl == null || "".equals(addToMapUrl)) {
return;
}
String resourceKey = "catalog.rest.addToMap";
ResourceLink link = this.makeLink(addToMapUrl, ResourceLink.TAG_ADDTOMAP,
resourceKey);
link.setTarget(iMapViewer.readTarget());
record.getResourceLinks().add(link);
return;
}
// maybe url is already an add to map url? if so no modigications are required
if ((resourceUrl.toLowerCase().startsWith("http:") || resourceUrl
.toLowerCase().startsWith("https:"))
&& resourceUrl.toLowerCase().contains("resources=map")) {
} else {
// set up an ArcGIS soap service for the viewer
if (serviceType.equals("ags")) {
resourceUrl = Val.chkStr(this.getResourceIdentifier()
.guessAgsMapServerSoapUrl(resourceUrl));
}
// set up an ArcIMS service for the viewer
int nIdx = resourceUrl.toLowerCase().indexOf(
"/servlet/com.esri.esrimap.esrimap?servicename=");
if (nIdx > 0) {
resourceUrl = resourceUrl.substring(0, nIdx) + "/"
+ resourceUrl.substring(nIdx + 46);
}
// set up an OGC service for the viewer
if (serviceType.equalsIgnoreCase("wms")
|| serviceType.equalsIgnoreCase("wfs")
|| serviceType.equalsIgnoreCase("wcs")) {
nIdx = resourceUrl.toLowerCase().indexOf("?");
if (nIdx > 0) {
resourceUrl = resourceUrl.substring(0, nIdx);
}
}
}
// TODO: explanation?
resourceUrl = resourceUrl.replaceAll("/$", "")
+ (serviceName.length() > 0 ? "/" + serviceName : "");
resourceUrl = Val.chkStr(resourceUrl);
if (resourceUrl.length() > 0) {
String url = viewerUrl + "?resources=map:" + serviceType + "@"
+ resourceUrl;
String resourceKey = "catalog.rest.addToMap";
ResourceLink link = this.makeLink(url, ResourceLink.TAG_ADDTOMAP,
resourceKey);
record.getResourceLinks().add(link);
}
String url = "";
try {
RequestContext rContext = this.getRequestContext();
ServletRequest sRequest = rContext.getServletRequest();
if (sRequest instanceof HttpServletRequest) {
HttpServletRequest hSRequest = (HttpServletRequest) sRequest;
String path = Val.chkStr(hSRequest.getPathInfo()).toLowerCase();
if (path.contains("catalog/search/search.page")
|| path.contains("catalog/main/home.page")) {
url = "javascript:GptUtils.popUp(\'" + url + "\',"
+ "GptMapViewer.TITLE," + "GptMapViewer.dimensions.WIDTH,"
+ "GptMapViewer.dimensions.HEIGHT);";
}
}
} catch (Exception e) {
}
}
/**
* Builds a set of links associated with a rest based ArcGIS map, image or globe
* service.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
protected void buildAGSLinks(SearchXslRecord xRecord, SearchResultRecord record) {
String resourceUrl = Val.chkStr(record.getResourceUrl());
String serviceType = Val.chkStr(record.getServiceType()).toLowerCase();
String restUrl = Val.chkStr(this.getResourceIdentifier()
.guessAgsServiceRestUrl(resourceUrl));
String url;
String resourceKey;
ResourceLink link;
if ((restUrl.length() > 0) && serviceType.equals("ags")) {
// kml
if (xRecord.getLinks().readShowLink(ResourceLink.TAG_AGSKML)
&& (restUrl.toLowerCase().endsWith("/mapserver") || restUrl.toLowerCase().endsWith("/imageserver"))) {
url = restUrl + "/kml/mapImage.kmz";
if (restUrl.toLowerCase().endsWith("/imageserver")) {
url = restUrl + "/kml/image.kmz";
}
resourceKey = "catalog.rest.addToGlobeKml";
link = this.makeLink(url, ResourceLink.TAG_AGSKML, resourceKey);
record.getResourceLinks().add(link);
}
// nmf
if (xRecord.getLinks().readShowLink(ResourceLink.TAG_AGSNMF)
&& (restUrl.toLowerCase().endsWith("/mapserver") || restUrl.toLowerCase().endsWith("/imageserver"))) {
url = restUrl + "?f=nmf";
resourceKey = "catalog.rest.addToGlobeNmf";
link = this.makeLink(url, ResourceLink.TAG_AGSNMF, resourceKey);
record.getResourceLinks().add(link);
}
// lyr
if (xRecord.getLinks().readShowLink(ResourceLink.TAG_AGSLYR)
&& (restUrl.toLowerCase().endsWith("/mapserver") || restUrl.toLowerCase().endsWith("/imageserver") || restUrl.toLowerCase().endsWith("/globeserver"))) {
url = restUrl + "?f=lyr";
resourceKey = "catalog.rest.addToArcMap";
link = this.makeLink(url, ResourceLink.TAG_AGSLYR, resourceKey);
record.getResourceLinks().add(link);
}
}
}
/**
* Checks if is request jsf and relative.
*
* @return true, if is request jsf and relative
*/
private boolean isRequestJsfAndRelative() {
try {
@SuppressWarnings("unchecked")
Map<String, String> extraMap =
(Map<String, String>)this.getRequestContext().getObjectMap().get(
RestQueryServlet.EXTRA_REST_ARGS_MAP);
boolean isJsfReq =
Val.chkBool(extraMap.get(
RestQueryServlet.PARAM_KEY_IS_JSFREQUEST).toString(), false);
boolean isShowRelUrls =
Val.chkBool(extraMap.get(
RestQueryServlet.PARAM_KEY_SHOW_RELATIVE_URLS).toString(), false);
return isShowRelUrls && isJsfReq;
} catch (Throwable e) {
LOG.log(Level.FINER, "This error is no big deal", e);
}
return false;
}
/**
* Builds the link associated with the content type icon.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
protected void buildContentTypeLink(SearchXslRecord xRecord,
SearchResultRecord record) {
String contentType = "";
List<String> schemeVals = xRecord.getTypes().get(
Scheme.CONTENTTYPE_FGDC.getUrn());
if (schemeVals.size() < 1) {
schemeVals = xRecord.getTypes().get(Scheme.CONTENTTYPE_ISO.getUrn());
}
if (schemeVals.size() < 1) {
schemeVals = xRecord.getTypes().get(null);
}
if (schemeVals.size() > 0) {
contentType = Val.chkStr(schemeVals.get(0));
}
if (contentType.length() > 0) {
contentType = this.getResourceIdentifier()
.guessArcIMSContentTypeFromResourceType(contentType);
}
if (contentType.length() == 0) {
String resourceUrl = record.getResourceUrl();
contentType = this.getResourceIdentifier().guessArcIMSContentTypeFromUrl(
resourceUrl);
}
if (contentType.length() == 0)
contentType = "unknown";
record.setContentType(contentType);
if (contentType.length() > 0) {
String tmpBaseContextPath = this.getBaseContextPath();
if(isRequestJsfAndRelative() == true) {
// caution! contextpath is put automatically by jsf when we put relative
// url
tmpBaseContextPath = "";
}
String url = tmpBaseContextPath + this.imagePath + "/ContentType_"
+ contentType + ".png";
String resourceKey = "catalog.search.filterContentTypes." + contentType;
ResourceLink link = this.makeLink(url, ResourceLink.TAG_CONTENTTYPE,
resourceKey);
record.getResourceLinks().setIcon(link);
}
}
/**
* Builds the link associated with the metadata details page.
* <br/>Records from an extenal repositories do not have a details link.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
protected void buildDetailsLink(SearchXslRecord xRecord, SearchResultRecord record) {
if(!xRecord.getLinks().readShowLink(ResourceLink.TAG_DETAILS)) {
return;
}
String uuid = Val.chkStr(record.getUuid());
String url = "";
String resourceUrl = "";
if (!record.isExternal() && (uuid.length() > 0)) {
/* url = this.getBaseContextPath() + this.detailsPath + "?uuid="
+ encodeUrlParam(uuid);
*/
resourceUrl = this.getBaseContextPath() + this.resourceDetailsPath + "?uuid="
+ encodeUrlParam(uuid);
}
if (resourceUrl.length() > 0) {
String resourceKey = "catalog.rest.viewDetails";
/* ResourceLink link = this.makeLink(url, ResourceLink.TAG_DETAILS,
resourceKey);*/
ResourceLink resourcePageLink = this.makeLink(resourceUrl, ResourceLink.TAG_DETAILS,
resourceKey);
// record.getResourceLinks().add(link);
record.getResourceLinks().add(resourcePageLink);
}
}
/**
* Builds the link associated with full metadata retrieval.
* <br/>Records from an extenal repositories do not have a details link.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
protected void buildMetadataLink(SearchXslRecord xRecord, SearchResultRecord record) {
if(!xRecord.getLinks().readShowLink(ResourceLink.TAG_METADATA)) {
return;
}
String uuid = Val.chkStr(record.getUuid());
String url = "";
if (uuid.length() > 0) {
if (record.isExternal()) {
// if external we need to use a different route. Because
// of authentication issues. Internal is automatically authenticated
// while if we used rest getrecord for external, the workflow to
// get the user to input username and password may be more complicated since
// we'd have to broker the authentication
url = this.getBaseContextPath() + this.externalMetadataPath + "?uuid="
+ encodeUrlParam(uuid) + "&rid="
+ encodeUrlParam(record.getExternalId());
} else {
url = this.getBaseContextPath() + this.metadataPath + "?id="
+ encodeUrlParam(uuid);
}
}
if (url.length() > 0) {
String resourceKey = "catalog.rest.viewFullMetadata";
ResourceLink link = this.makeLink(url, ResourceLink.TAG_METADATA,
resourceKey);
record.getResourceLinks().add(link);
}
}
/**
* Builds a generic Open link for the resource URL associated with the record.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
protected void buildOpenLink(SearchXslRecord xRecord, SearchResultRecord record) {
if(!xRecord.getLinks().readShowLink(ResourceLink.TAG_OPEN)) {
return;
}
String resourceUrl = Val.chkStr(record.getResourceUrl());
String serviceType = Val.chkStr(record.getServiceType()).toLowerCase();
// return if we cannot open
if ((resourceUrl.length() == 0) || serviceType.equals("aims")) {
return;
}
// possibly we should reset AGS rest services to their home URL??
/*
if (serviceType.equals("ags")) {
String agsRest = Val.chkStr(this.getResourceIdentifier().guessAgsServiceRestUrl(resourceUrl));
if (agsRest.length() > 0) {
resourceUrl = agsRest;
}
}
*/
String resourceKey = "catalog.rest.open";
ResourceLink link = this.makeLink(resourceUrl, ResourceLink.TAG_OPEN,
resourceKey);
if (serviceType.length() > 0) {
link.getParameters().add(new StringAttribute(RESOURCE_TYPE, serviceType));
}
record.getResourceLinks().add(link);
//this.makeAddToMapFromFactory(resourceUrl, null, resourceKey, record);
}
/**
* Builds the link associated with the resource preview page.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
protected void buildPreviewLink(SearchXslRecord xRecord, SearchResultRecord record) {
if(!xRecord.getLinks().readShowLink(ResourceLink.TAG_PREVIEW)) {
return;
}
String id = Val.chkStr(record.getUuid());
String rid = Val.chkStr(record.getExternalId());
String resourceUrl = Val.chkStr(record.getResourceUrl());
String serviceType = Val.chkStr(record.getServiceType()).toLowerCase();
//String previewPath = Val.chkStr(this.previewPath);
if (resourceUrl.indexOf("q=")>=0 && resourceUrl.indexOf("user=")>=0 && resourceUrl.indexOf("max=")>=0 && resourceUrl.indexOf("dest=")>=0 && resourceUrl.indexOf("destuser=")>=0) {
// look like this is AGP-2-AGP registration; don'e generate preview link
return;
}
// return if we cannot preview
String tmp = resourceUrl.toLowerCase();
if ((resourceUrl.length() == 0) || (previewPath.length() == 0)) {
return;
} else if (tmp.indexOf("?getxml=") != -1) {
return;
}
String sFilter = Val.chkStr(ApplicationContext.getInstance().getConfiguration().getCatalogConfiguration().getParameters().getValue("resourceLinkBuilder.preview.filter"));
if (sFilter.length()>0) {
try {
Pattern pattern = Pattern.compile(sFilter, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(resourceUrl);
if (matcher.matches()) {
return;
}
} catch (Exception ex) {
}
}
// possibly we should reset AGS rest services to their home URL??
/*
if (serviceType.equals("ags")) {
String agsRest = Val.chkStr(this.getResourceIdentifier().guessAgsServiceRestUrl(resourceUrl));
if (agsRest.length() > 0) {
resourceUrl = agsRest;
}
}
*/
// build the link TODO: metadata url not same as rest info url
String url ="";
if(record.isExternal()){
url = this.getBaseContextPath() + previewPath;
}else{
url = this.getBaseContextPath() + resourcePreviewPath;
}
if (id.length() > 0) {
url += "?uuid=" +encodeUrlParam(id)+"&url=" + encodeUrlParam(resourceUrl);
}else{
url += "?url=" + encodeUrlParam(resourceUrl);
}
if (serviceType.length() > 0) {
url += "&" + RESOURCE_TYPE + "=" + serviceType;
}
boolean showInfo = xRecord.getLinks().readShowLink(
ResourceLink.TAG_PREVIEW_PARAM_INFO, true);
if (id.length() > 0 && showInfo == true ) {
String infoUrl = this.getBaseContextPath() + this.metadataPath
+ "?f=html&showRelativeUrl=true&id=" + encodeUrlParam(id);
if (record.isExternal() && rid.length() > 0) {
infoUrl += "&rid=" + encodeUrlParam(rid);
}
url += "&info=" + encodeUrlParam(infoUrl);
}
String resourceKey = "catalog.rest.preview";
ResourceLink link = this.makeLink(url, ResourceLink.TAG_PREVIEW, resourceKey);
if (serviceType.length() > 0) {
link.getParameters().add(new StringAttribute(RESOURCE_TYPE, serviceType));
}
if(record.isExternal()){
link.setForExtenalRecord(true);
}
record.getResourceLinks().add(link);
}
private boolean showThumbnail() {
@SuppressWarnings("unchecked")
Map<String, String> extraArgsMap = (Map<String, String>)
this.getRequestContext().getObjectMap().get(
RestQueryServlet.EXTRA_REST_ARGS_MAP);
if(extraArgsMap == null) {
return true;
}
return Val.chkBool(extraArgsMap.get(RestQueryServlet.PARAM_KEY_SHOW_THUMBNAIL),
true);
}
/**
* Builds the link associated with the thumbnail.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
protected void buildThumbnailLink(SearchXslRecord xRecord, SearchResultRecord record) {
if(this.showThumbnail() == false) {
return;
}
String url = "";
DcList references = xRecord.getReferences();
List<String> schemeVals = references.get(Scheme.THUMBNAIL_FGDC.getUrn());
if (schemeVals.size() < 1) {
schemeVals = references.get(Scheme.THUMBNAIL_ISO.getUrn());
}
if (schemeVals.size() > 0) {
url = schemeVals.get(0);
} else {
for (DcList.Value reference : references) {
if (reference != null) {
String tmp = reference.getValue().toLowerCase();
if (tmp.endsWith(".gif") || tmp.endsWith(".jpg")
|| tmp.endsWith(".jpeg") || tmp.endsWith(".png")
|| tmp.contains("/thumbnail?uuid")) {
url = reference.getValue();
break;
}
}
}
}
url = Val.chkStr(url);
url = this.checkUrl(url);
if (url.length() > 0) {
String resourceKey = "catalog.rest.thumbNail";
ResourceLink link = this.makeLink(url, ResourceLink.TAG_THUMBNAIL,
resourceKey);
record.getResourceLinks().setThumbnail(link);
}
}
/**
* Builds the link associated with an organizational website.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
protected void buildWebsiteLink(SearchXslRecord xRecord, SearchResultRecord record) {
if(!xRecord.getLinks().readShowLink(ResourceLink.TAG_WEBSITE)) {
return;
}
String url = "";
DcList references = xRecord.getReferences();
List<String> schemeVals = references.get(Scheme.ONLINK_FGDC.getUrn());
if (schemeVals.size() < 1) {
schemeVals = references.get(Scheme.ONLINK_ISO.getUrn());
}
if (schemeVals.size() > 0) {
url = Val.chkStr(schemeVals.get(0));
}
String resourceKey = "catalog.rest.webSite";
url = this.checkUrl(url);
if (url.length() > 0) {
if (url.startsWith("www."))
url = "http://" + url;
ResourceLink link = this.makeLink(url, ResourceLink.TAG_WEBSITE,
resourceKey);
record.getResourceLinks().add(link);
}
this.makeAddToMapFromFactory(url, null, resourceKey, record);
}
/**
* Builds the custom links.
*
* @param xRecord the x record
* @param record the record
*/
protected void buildCustomLinks(SearchXslRecord xRecord,
SearchResultRecord record) {
if(!xRecord.getLinks().readShowLink(ResourceLink.TAG_CUSTOM)) {
return;
}
Map<String, List<String>> links = xRecord.getLinks().getCustomLinks();
Iterator<String> iter = links.keySet().iterator();
while(iter.hasNext()) {
String label = iter.next();
List<String> list = links.get(label);
Iterator<String> iter2 = list.iterator();
while(iter2.hasNext()) {
String url = iter2.next();
url = this.checkUrl(url);
if (url.length() > 0) {
ResourceLink link = this.makeLink(url, ResourceLink.TAG_CUSTOM, label);
record.getResourceLinks().add(link);
makeAddToMapFromFactory(url, null, label, record);
}
}
}
}
/**
* Checks a url the url to check
* <br/>Only urls beginning with www. http:// https:// ftp:// ftps:// will be returned.
* @param urlToCheck the urlToCheck
* @return the checked url (zero length if invalid)
*/
protected String checkUrl(String urlToCheck) {
urlToCheck = Val.chkStr(urlToCheck);
String url = urlToCheck.toLowerCase();
if (url.startsWith("www.")) {
return "http://"+urlToCheck;
} else {
if (url.startsWith("http://") || url.startsWith("https://") ||
url.startsWith("ftp://") || url.startsWith("ftps://")) {
return urlToCheck;
}
}
return "";
}
/**
* Determines the primary resource URL associated with the resultant record.
* <br/>The primary resource URL is associated with the resource that the
* metadata record describes.
* @param xRecord the underlying CSW record
* @param record the search result record
*/
protected void determineResourceUrl(SearchXslRecord xRecord,
SearchResultRecord record) {
// initialize
String resourceUrl = "";
String serviceType = "";
String serviceName = "";
DcList references = xRecord.getReferences();
// determine the service url, name and type
List<String> schemeVals = references.get(Scheme.SERVER.getUrn());
if (schemeVals.size() > 0) {
resourceUrl = Val.chkStr(schemeVals.get(0));
}
schemeVals = references.get(Scheme.SERVICE.getUrn());
if (schemeVals.size() > 0) {
serviceName = Val.chkStr((schemeVals.get(0)));
}
schemeVals = references.get(Scheme.SERVICE_TYPE.getUrn());
if (schemeVals.size() > 0) {
serviceType = Val.chkStr((schemeVals.get(0)));
}
if ((resourceUrl.length() > 0) && (serviceType.length() == 0)) {
serviceType = this.getResourceIdentifier().guessServiceTypeFromUrl(
resourceUrl);
}
// handle the case where an ArcIMS service has been specified with
// server/service/serviceType parameters
if ((resourceUrl.length() > 0)
&& (serviceType.equalsIgnoreCase("image")
|| serviceType.equalsIgnoreCase("feature") || serviceType
.equalsIgnoreCase("metadata"))) {
if ((serviceName.length() > 0)) {
String esrimap = "servlet/com.esri.esrimap.Esrimap";
if (resourceUrl.indexOf(esrimap) == -1) {
if (resourceUrl.indexOf("?") == -1) {
if (!resourceUrl.endsWith("/"))
resourceUrl += "/";
resourceUrl = resourceUrl + esrimap + "?ServiceName=" + serviceName;
}
} else {
if (resourceUrl.indexOf("?") == -1) {
resourceUrl = resourceUrl + "?ServiceName=" + serviceName;
} else if (resourceUrl.indexOf("ServiceName=") == -1) {
resourceUrl = resourceUrl + "&ServiceName=" + serviceName;
}
}
}
if (serviceType.equals("image")) {
serviceType = "aims";
}
}
// if the resource url has not been directly specified through a "scheme" attribute,
// then attempt to pick the best fit for the collection of references
if (resourceUrl.length() == 0) {
for (DcList.Value reference : references) {
if (reference != null) {
String url = Val.chkStr(reference.getValue());
String type = this.getResourceIdentifier().guessServiceTypeFromUrl(url);
if (type.length() > 0) {
resourceUrl = url;
serviceType = type;
break;
}
}
}
/*
if (!(server.endsWith(".gif") || server.endsWith(".jpg")
|| server.endsWith(".jpeg") || server.endsWith(".png") || server
.contains("/thumbnail?uuid") || server.contains("?getxml="))) {
if(!links.findUrlByTag(RESOURCE_LINK_KEY.gpt_openResource.toString()).equals(server)
&& !links.findUrlByTag(RESOURCE_LINK_KEY.gpt_openResource.toString()).equals("http://"+server)){
links.add(buildResourceLink(buildOpenResourceUrl(server,serviceType),
RESOURCE_LINK_KEY.gpt_openResource.toString(), "catalog.rest.open",
true));
}
*/
}
// update the record
resourceUrl = this.checkUrl(resourceUrl);
if (resourceUrl.length() > 0) {
record.setResourceUrl(resourceUrl);
record.setService(serviceName);
record.setServiceType(serviceType);
}
}
/**
* 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;
}
}
/**
* Initializes the resource link builder.
* @param context the active request context
* @param request the active HTTP servlet request (can be null)
* @param messageBroker the active message broker
*/
public void initialize(HttpServletRequest request, RequestContext context,
MessageBroker messageBroker) {
this.setMessageBroker(messageBroker);
this.setResourceIdentifier(ResourceIdentifier.newIdentifier(context));
this.mapViewerUrl = context.getCatalogConfiguration().getSearchConfig()
.getMapViewerUrl();
this.setBaseContextPath(RequestContext.resolveBaseContextPath(request));
this.requestContext = context;
}
/**
* Makes the label associated with a resource bundle key.
* @param resourceKey the resource bundle key
* @return the associated key
*/
protected String makeLabel(String resourceKey) {
String label = this.labels.get(resourceKey);
if (label == null) {
label = this.getMessageBroker().retrieveMessage(resourceKey);
this.labels.put(resourceKey, label);
}
label = Val.chkStr(label);
if (label.length() > 0) {
return label;
} else {
return resourceKey;
}
}
/**
* Makes a link.
* @param url the URL associated with the resource
* @param tag the tag idenitfying a type of link
* @param resourceKey the resource bundle key associated with the label
*/
protected ResourceLink makeLink(String url, String tag, String resourceKey) {
ResourceLink link = new ResourceLink();
link.setUrl(url);
link.setTag(tag);
link.setLabelResourceKey(resourceKey);
link.setLabel(Val.chkStr(makeLabel(resourceKey)));
return link;
}
/**
* Instantiates a new resource link builder.
* <p/>
* By default, a new instance of
* com.esri.gpt.catalog.search.ResourceLinkBuilder is returned.
* <p/>
* This can be overridden by the configuration parameter:
* /gptConfig/catalog/parameter@key="resourceLinkBuilder"
* @param context the active request context
* @param servletRequest the active HTTP servlet request
* @param messageBroker the message broker
* @return the resource link builder
*/
public static ResourceLinkBuilder 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(
"resourceLinkBuilder"));
if (className.length() == 0) {
className = com.esri.gpt.catalog.search.ResourceLinkBuilder.class.getName();
}
// instantiate the builder
try {
Class<?> cls = Class.forName(className);
Object obj = cls.newInstance();
if (obj instanceof ResourceLinkBuilder) {
ResourceLinkBuilder linkBuilder = (ResourceLinkBuilder) obj;
linkBuilder.initialize(servletRequest, context, messageBroker);
return linkBuilder;
} else {
String sMsg = "The configured resourceLinkBuilder parameter is invalid: "
+ className;
throw new ConfigurationException(sMsg);
}
} catch (ConfigurationException t) {
throw t;
} catch (Throwable t) {
String sMsg = "Error instantiating resource link builder: " + className;
throw new ConfigurationException(sMsg, t);
}
}
/**
* Make add to map from factory.
*
* @param resourceUrl the resource url
* @param serviceType the service type (could be null)
* @param prefixResource the prefix resource (Used for the label)
* @param record the record
*/
private void makeAddToMapFromFactory(String resourceUrl,
String serviceType, String prefixResource, SearchResultRecord record) {
IMapViewer iMapViewer = MapViewerFactory.createMapViewer(resourceUrl, serviceType,
new SearchResultRecordAdapter(record), this.getRequestContext());
if (iMapViewer == null) {
return;
}
String addToMapUrl = iMapViewer.readAddToMapUrl();
if(addToMapUrl == null || "".equals(addToMapUrl)) {
return;
}
String resourceKey = "catalog.rest.addToMap";
ResourceLink link = this.makeLink(addToMapUrl, ResourceLink.TAG_ADDTOMAP,
resourceKey);
String label = this.getMessageBroker().retrieveMessage(prefixResource) + " - " +
this.getMessageBroker().retrieveMessage(resourceKey);
link.setLabel(label);
link.setTarget(iMapViewer.readTarget());
record.getResourceLinks().add(link);
}
}