/* 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.discovery.DiscoveryException;
import com.esri.gpt.framework.collection.StringSet;
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.util.Val;
import com.esri.gpt.server.csw.client.CswRecord;
import com.esri.gpt.server.csw.client.CswRecords;
import com.esri.gpt.server.csw.client.Utils;
import com.esri.gpt.server.csw.provider.components.IOriginalXmlProvider;
import com.esri.gpt.server.csw.provider.components.OperationContext;
import com.esri.gpt.server.csw.provider.components.OperationResponse;
import com.esri.gpt.server.csw.provider.components.RequestHandler;
import com.esri.gpt.server.csw.provider.local.ProviderFactory;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* CSW based search engine that executes against the local GPT catalog.
*/
public class SearchEngineLocal extends SearchEngineCSW {
/** class variables ========================================================= */
/** The Logger. */
private static final Logger LOGGER = Logger.getLogger(SearchEngineLocal.class.getName());
/** The ID that can be associated with the search factory hint. */
public static final String ID = "local";
/** instance variables ====================================================== */
// private RequestContext requestContext;
/** constructors ============================================================ */
private SearchEngineLocal() {
}
public SearchEngineLocal(RequestContext context) {
super(context);
//this.requestContext = context;
}
// methods =================================================================.
/*
* Ignoring init
*
* @throws SearchException the search exception
*/
@Override
public void init() throws SearchException {
// We do not want to contact the urls
}
/**
* Sends a CSW GetRecordByID request to CSW service.
* @param uuid the document UUID
* @return the resultant record
* @throws SearchException the search exception
*/
@Override
protected CswRecord getMetadata(String uuid) throws SearchException {
String cswResponse = "";
CswRecord record = null;
CswRecords records = null;
// send the GetRecordsById request
try {
GetRecordsGenerator generator = new GetRecordsGenerator(this.getRequestContext());
String cswRequest = generator.generateCswByIdRequest(uuid);
RequestHandler handler = ProviderFactory.newHandler(this.getRequestContext());
OperationResponse resp = handler.handleXML(cswRequest);
cswResponse = resp.getResponseXml();
records = this.parseResponse(cswResponse);
} catch (DiscoveryException e) {
throw new SearchException("Error quering GetRecordById: "+e.getMessage(),e);
} catch (Exception e) {
throw new SearchException("Error generating GetRecordById: "+e.getMessage(),e);
}
// get the first record
if (records != null) {
Iterator iter = records.iterator();
if (iter.hasNext()) {
Object obj = iter.next();
if(obj instanceof CswRecord ) {
record = (CswRecord)obj;
}
}
}
// parse the GetRecordsById response
if (record != null) {
record.setId(uuid);
try {
getCswProfile().readCSWGetMetadataByIDResponseLocal(cswResponse, record);
} catch (Exception e) {
throw new SearchException("Error parsing GetRecordById: "+e.getMessage(),e);
}
if (record != null) {
// read the full metadata XML (acl was already processed by above CSW request)
String fullMetadataXml = "";
try {
RequestHandler handler = ProviderFactory.newHandler(this.getRequestContext());
OperationContext ctx = handler.getOperationContext();
IOriginalXmlProvider oxp = ctx.getProviderFactory().makeOriginalXmlProvider(ctx);
fullMetadataXml = oxp.provideOriginalXml(ctx,uuid);
} catch (Exception e) {
throw new SearchException("Error accessing full metadata xml for: "+uuid);
}
record.setFullMetadata(fullMetadataXml);
if (fullMetadataXml.length() == 0) {
record = null;
}
}
}
if (record == null) {
throw new SearchException("No associated record was located for: "+uuid);
}
return record;
}
/**
* Specific parse for sitemap only response.
* @param cswResponse the CSW response
* @return the resultant records
* @throws SearchException the search exception
*/
private CswRecords parseResponseForSitemap(String cswResponse) throws SearchException {
CswRecords cswRecords = new CswRecords();
try {
//System.err.println(cswResponse);
InputSource src = new InputSource(new StringReader(Val.chkStr(cswResponse)));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
org.w3c.dom.Document dom = builder.parse(src);
String cswNamespace = "http://www.opengis.net/cat/csw/2.0.2";
String dcNamespace = "http://purl.org/dc/elements/1.1/";
String dctNamespace = "http://purl.org/dc/terms/";
String idScheme = "urn:x-esri:specification:ServiceType:ArcIMS:Metadata:DocID";
NodeList resultNodes = dom.getElementsByTagNameNS(cswNamespace,"SearchResults");
if (resultNodes.getLength() == 1) {
Node searchResultsNode = resultNodes.item(0);
if (searchResultsNode != null) {
Node ndHits = searchResultsNode.getAttributes().getNamedItem("numberOfRecordsMatched");
//Node ndHits = searchResultsNode.getAttributes().getNamedItemNS(cswNamespace,"numberOfRecordsMatched");
if (ndHits != null) {
int nHits = Val.chkInt(Val.chkStr(ndHits.getNodeValue()),-1);
cswRecords.setMaximumQueryHits(nHits);
}
}
}
NodeList recordNodes = dom.getElementsByTagNameNS(cswNamespace,"Record");
int nLen = recordNodes.getLength();
for (int i=0; i<nLen; i++) {
CswRecord record = new CswRecord();
String id = "";
String modified = "";
Node recordNode = recordNodes.item(i);
NodeList nlChildren = recordNode.getChildNodes();
int nChildren = nlChildren.getLength();
for (int nChild=0; nChild<nChildren; nChild++) {
Node ndChild = nlChildren.item(nChild);
String namespace = ndChild.getNamespaceURI();
String localname = ndChild.getLocalName();
if ((namespace != null) && (localname != null)) {
if (namespace.equals(dcNamespace) && localname.equals("identifier")) {
String scheme = "";
Node ndScheme = ndChild.getAttributes().getNamedItem("scheme");
if (ndScheme != null) {
scheme = Val.chkStr(ndScheme.getNodeValue());
}
if (scheme.equals(idScheme)) {
id = Val.chkStr(ndChild.getTextContent());
}
} else if (namespace.equals(dctNamespace) && localname.equals("modified")) {
modified = Val.chkStr(ndChild.getTextContent());
}
}
}
record.setId(id);
//System.err.println("id="+id+" modified="+modified);
if (modified.length() > 0) {
record.setModifiedDate(modified);
}
cswRecords.add(record);
}
} catch (Exception e) {
throw new SearchException(e);
}
return cswRecords;
}
/**
* Sends a CSW GetRecords request to the local CSW service.
* @param cswRequest the CSW XML request
* @return the resultant records
* @throws SearchException the search exception
*/
@Override
protected CswRecords sendRequest(String cswRequest) throws SearchException {
try {
LOGGER.log(Level.FINER, "Executing local CSW 2.0.2 Discovery request:\n{0}", cswRequest);
boolean isSitemapRequest = false;
Object obj = this.getRequestContext().getObjectMap().get("com.esri.gpt.catalog.search.isSitemapRequest");
if ((obj != null) && (obj instanceof String)) {
isSitemapRequest = ((String)obj).equalsIgnoreCase("true");
}
RequestHandler handler = ProviderFactory.newHandler(this.getRequestContext());
OperationResponse resp = handler.handleXML(cswRequest);
String cswResponse = resp.getResponseXml();
LOGGER.log(Level.FINER, "cswResponse:\n{0}", cswResponse);
//return this.parseResponse(cswResponse);
CswRecords parsedRecords = null;
if (!isSitemapRequest) {
parsedRecords = this.parseResponse(cswResponse);
} else {
parsedRecords = this.parseResponseForSitemap(cswResponse);
}
return parsedRecords;
} catch (Exception e) {
throw new SearchException("Error quering GetRecords: "+e.getMessage(),e);
}
}
/**
* Gets the abstract associated with the key
*
* @return the abstract
* @throws SearchException
*/
@Override
public String getKeyAbstract() throws SearchException {
Map<String, String> map = this.getFactoryAttributes();
String absKey = null;
if(map != null) {
absKey = map.get("abstractResourceKey");
}
if(absKey == null || "".equals(absKey.trim())) {
absKey = "catalog.search.searchSite.defaultsite.abstract";
}
MessageBroker bundle = new MessageBroker();
bundle.setBundleBaseName(MessageBroker.DEFAULT_BUNDLE_BASE_NAME);
return bundle.retrieveMessage(absKey);
}
/**
*
* Creates instances
*@param rids
*@return Map with engine
*/
@Override
public Map<String, Object> createInstances(StringSet rids) {
Map<String, Object> mapRid2Engine = new HashMap<String, Object>();
for(String rid:rids) {
ASearchEngine engine = new SearchEngineLocal();
try {
engine.setKey(rid);
mapRid2Engine.put(rid, engine);
} catch (SearchException e) {
mapRid2Engine.put(rid,"Error while intializing id " + rid + " "
+ e.getMessage());
LOGGER.log(Level.WARNING,"Error while intializing id " + rid,e);
}
}
return mapRid2Engine;
}
}