/* 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.server.csw.provider.components;
import com.esri.gpt.framework.collection.StringSet;
import com.esri.gpt.framework.context.RequestContext;
import com.esri.gpt.framework.util.Val;
import com.esri.gpt.framework.xml.DomUtil;
import com.esri.gpt.framework.xml.XmlIoUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Generates a CSW Capabilities response.
*/
public class GetCapabilitiesResponse implements IResponseGenerator {
/** class variables ========================================================= */
/** The Logger. */
private static Logger LOGGER = Logger.getLogger(GetCapabilitiesResponse.class.getName());
/** constructors ============================================================ */
/** Default constructor */
public GetCapabilitiesResponse() {}
/** methods ================================================================= */
/**
* Generates the response.
* @param context the operation context
* @throws Exception if a processing exception occurs
*/
public void generateResponse(OperationContext context) throws Exception {
// initialize
LOGGER.finer("Generatiing csw:Capabilities response...");
CapabilityOptions cOptions = context.getRequestOptions().getCapabilityOptions();
ServiceProperties svcProps = context.getServiceProperties();
// TODO these URL's
String httpContextPath = Val.chkStr(svcProps.getHttpContextPath());
String cswBaseUrl = Val.chkStr(svcProps.getCswBaseURL());
String cswSoapUrl = "";
// check for https protocol
if (httpContextPath.length() > 0) {
RequestContext reqContext = context.getRequestContext();
if ((reqContext != null) && (reqContext.getServletRequest() != null) &&
(reqContext.getServletRequest() instanceof HttpServletRequest)) {
HttpServletRequest httpReq = (HttpServletRequest)reqContext.getServletRequest();
StringBuffer requestURL = httpReq.getRequestURL();
String s = requestURL.toString().toLowerCase();
if (s.startsWith("https://") && httpContextPath.toLowerCase().startsWith("http:")) {
httpContextPath = "https"+httpContextPath.substring(4);
}
}
}
// load the resource document
String loc = cOptions.getCapabilitiesLocation();
//loc = "gpt/metadata/cswCapabilities-INSPIRE.xml";
Document dom = DomUtil.makeDomFromResourcePath(loc,true);
//dom.getDocumentElement().normalize();
// make an XPath for the CSW name space context
CswNamespaces ns = new CswNamespaces();
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(ns.makeNamespaceContext());
// update the OperationsMetadata endpoints
NodeList nlRefs = (NodeList)xpath.evaluate("//@xlink:href",dom,XPathConstants.NODESET);
for (int i=0; i<nlRefs.getLength(); i++) {
Node ndRef = nlRefs.item(i);
String href = ndRef.getNodeValue();
Node ndParent = ((Attr)ndRef).getOwnerElement();
String nsParent = Val.chkStr(ndParent.getNamespaceURI());
String parentName = ndParent.getLocalName();
if (nsParent.equals(CswNamespaces.URI_OWS)) {
if (parentName.equals("Get") || parentName.equals("Post")) {
if ((href == null) || !href.startsWith("http")) {
href = Val.chkStr(href);
if (href.length() > 0) {
href = httpContextPath+href;
} else {
href = cswBaseUrl;
}
if (parentName.equals("Post")) {
String val = xpath.evaluate("ows:Constraint[@name='PostEncoding']/ows:Value",ndParent);
if (Val.chkStr(val).equalsIgnoreCase("SOAP")) {
href = cswSoapUrl;
}
}
ndRef.setNodeValue(href);
}
}
}
}
// remove sections that were not requested
StringSet sections = cOptions.getSections();
if ((sections != null) && (sections.size() > 0)) {
HashMap<String,String> keep = new HashMap<String,String>();
for (String section: sections) {
if (section.equalsIgnoreCase("ServiceIdentification")) {
keep.put(CswNamespaces.URI_OWS+"#ServiceIdentification","");
} else if (section.equalsIgnoreCase("ServiceProvider")) {
keep.put(CswNamespaces.URI_OWS+"#ServiceProvider","");
} else if (section.equalsIgnoreCase("OperationsMetadata")) {
keep.put(CswNamespaces.URI_OWS+"#OperationsMetadata","");
} else if (section.equalsIgnoreCase("Filter_Capabilities")) {
keep.put(CswNamespaces.URI_OGC+"#Filter_Capabilities","");
}
}
// always keep the filter capabilities
keep.put(CswNamespaces.URI_OGC+"#Filter_Capabilities","");
ArrayList<Node> remove = new ArrayList<Node>();
Node root = (Node)xpath.evaluate("/csw:Capabilities",dom,XPathConstants.NODE);
NodeList children = root.getChildNodes();
for (int i=0;i<children.getLength();i++) {
Node node = children.item(i);
String namespace = node.getNamespaceURI();
String localname = node.getLocalName();
if (!keep.containsKey(namespace+"#"+localname)) {
remove.add(node);
}
}
for (Node node: remove) {
try {
node.getParentNode().removeChild(node);
} catch (Exception e) {
LOGGER.warning("Unable to remove section, reason= "+e.toString());
}
}
}
// check for a supplied language code (INSPIRE)
String requestedLang = Val.chkStr(cOptions.getLanguageCode());
String exprLang = "/csw:Capabilities/ows:OperationsMetadata/inspire_ds:ExtendedCapabilities/inspire_common:SupportedLanguages/inspire_common:SupportedLanguage/inspire_common:Language";
String exprDef = "/csw:Capabilities/ows:OperationsMetadata/inspire_ds:ExtendedCapabilities/inspire_common:SupportedLanguages/inspire_common:DefaultLanguage/inspire_common:Language";
String exprCur = "/csw:Capabilities/ows:OperationsMetadata/inspire_ds:ExtendedCapabilities/inspire_common:ResponseLanguage/inspire_common:Language";
NodeList nlLang = (NodeList)xpath.evaluate(exprLang,dom,XPathConstants.NODESET);
Node ndDefLang = (Node)xpath.evaluate(exprDef,dom,XPathConstants.NODE);
Node ndCurLang = (Node)xpath.evaluate(exprCur,dom,XPathConstants.NODE);
if ((ndDefLang != null) && (ndCurLang != null)) {
String sDefLang = Val.chkStr(ndDefLang.getTextContent());
String sCurLang = Val.chkStr(ndCurLang.getTextContent());
String sRespLang = sDefLang;
if (sRespLang.length() == 0) sRespLang = sCurLang;
if ((requestedLang.length() > 0) && !requestedLang.equalsIgnoreCase(sRespLang)) {
if ((nlLang!= null) && (nlLang.getLength() > 0)) {
for (int i=0; i<nlLang.getLength(); i++) {
Node ndLang = nlLang.item(i);
String sLang = Val.chkStr(ndLang.getTextContent());
if (requestedLang.equalsIgnoreCase(sLang)) {
sRespLang = sLang;
break;
}
}
}
}
if (sRespLang.length() > 0) {
cOptions.setResponseLanguageCode(sRespLang);
// update the current response language
if (!sRespLang.equalsIgnoreCase(sCurLang)) {
ndCurLang.setTextContent(sRespLang);
}
// remove nodes not associated with the response language
NodeList nlLangRefs = (NodeList)xpath.evaluate("//@xml:lang",dom,XPathConstants.NODESET);
ArrayList<Node> remove = new ArrayList<Node>();
ArrayList<Attr> removeAttr = new ArrayList<Attr>();
for (int i=0;i<nlLangRefs.getLength();i++) {
Node node = nlLangRefs.item(i);
if (node instanceof Attr) {
String sLang = Val.chkStr(node.getTextContent());
if (sRespLang.equalsIgnoreCase(sLang)) {
removeAttr.add((Attr)node);
} else {
Node ndToRemode = ((Attr)node).getOwnerElement();
remove.add(ndToRemode);
}
}
}
for (Node node: remove) {
try {
node.getParentNode().removeChild(node);
} catch (Exception e) {
LOGGER.warning("Unable to remove non-requested language node, reason= "+e.toString());
}
}
for (Attr attr: removeAttr) {
try {
attr.getOwnerElement().removeAttributeNode(attr);
} catch (Exception e) {
LOGGER.warning("Unable to remove xml:lang sttribute, reason= "+e.toString());
}
}
}
}
// set the response string
String xml = XmlIoUtil.domToString(dom);
context.getOperationResponse().setResponseXml(xml);
}
}