/* 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.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.transform.TransformerException;
import com.esri.gpt.catalog.harvest.protocols.HarvestProtocolCsw;
import com.esri.gpt.catalog.harvest.repository.HrRecord;
import com.esri.gpt.control.rest.repositories.CswRepository;
import com.esri.gpt.control.webharvest.protocol.Protocol;
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.server.csw.client.CswCatalogCapabilities;
import com.esri.gpt.server.csw.client.CswClient;
import com.esri.gpt.server.csw.client.CswProfile;
import com.esri.gpt.server.csw.client.CswRecord;
import com.esri.gpt.server.csw.client.CswRecords;
import com.esri.gpt.server.csw.client.CswSearchRequest;
import com.esri.gpt.server.csw.client.InvalidOperationException;
import com.esri.gpt.server.csw.client.NullReferenceException;
/**
*
* The Class SearchEngineExternalCsw. Request based. For searching
* Harvest Site CSWs in our repositories. Parameters that can be used
* are is "uuid" of harvest site
*/
public class SearchEngineExternalCsw
extends SearchEngineCSW {
// class variables =============================================================
/** The class LOG. */
private static final Logger LOG = Logger.getLogger(
SearchEngineExternalCsw.class.getCanonicalName());
// instance variables ==========================================================
/** Tracks The former id we inited on. */
private String formerId = "";
/** The harvest record **/
private HrRecord hrRecord = null;
private boolean hasBeenInited = false;
// constructors ================================================================
/**
*
* Instantiates a new search engine external csw.
*/
public SearchEngineExternalCsw(){}
// properties ==================================================================
/**
* Gets the former hint.
*
* @return the former hint
*/
public String getFormerId() {
return formerId;
}
/**
* Sets the former hint.
*
* @param formerHint the new former hint
*/
public void setFormerId(String formerHint) {
this.formerId = formerHint;
}
/**
* Gets the hr record.
*
* @return the hr record (possibly null)
*/
public HrRecord getHrRecord() {
return hrRecord;
}
/**
* Sets the hr record.
*
* @param hrRecord the new hr record
*/
public void setHrRecord(HrRecord hrRecord) {
this.hrRecord = hrRecord;
}
// methods =====================================================================
/**
* Tells us if the search is external to GPT9 or Internal
* @return true
*/
@Override
protected boolean readIsExternalSearch() {
return true;
}
/**
* Sends a CSW GetRecords request to 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 {
if(hasBeenInited == false) {
hasBeenInited = true;
init(false);
}
InputStream cswInput = null;
try {
String username = Val.chkStr(this.getCredentials().getUsername());
String password = Val.chkStr(this.getCredentials().getPassword());
if("".equals(username)) {
return super.sendRequest(cswRequest);
}
// submit the request
String url = this.getGetRecordsUrl();
try {
cswInput = this.getCswClient().submitHttpRequest(
"POST", url,cswRequest,username,password);
} catch (Exception e) {
LOG.log(Level.SEVERE, "Exception when Posting CSW query to "+url,e);
if (e instanceof java.net.SocketTimeoutException) {
throw new SearchException("catalog.search.error.searchTimeOut",e,
new String[] {String.valueOf(SearchConfig.getConfiguredInstance()
.getTimeOut()/1000)});
}
throw new SearchException("ERROR while searching authenticating end point " +
url + " : " +e.getMessage()
,e);
}
// parse the response
try {
return this.parseResponse(this.readInputCharacters(cswInput, "UTF-8"));
} catch (IOException e) {
throw new SearchException("Could not get response for send request", e);
}
} finally {
try {if (cswInput != null) cswInput.close();} catch (Exception ef) {}
}
}
/**
* Marshalls csw records
* @param cswRecords CSW records
* @throws SearchException
*/
@Override
protected void marshallRecords(final CswRecords cswRecords)
throws SearchException {
CswProfile profile = this.getCswProfile();
SearchResult result = this.getRequestDefinition().getResult();
//result.setSupportsContentTypeQuery(profile.isSupportsContentTypeQuery());
//result.setSupportsSpatialDisplay(profile.isSupportsSpatialBoundary());
super.marshallRecords(cswRecords);
}
/**
* Gets the metadata as a csw client api record.
*
* @param uuid the uuid
*
* @return the metadata
*
* @throws SearchException the search exception
*/
@Override
protected CswRecord getMetadata(String uuid) throws SearchException {
CswRecord record = new CswRecord();
Exception exc = null;
try {
CswProfile profile = getCswProfile();
CswSearchRequest request = new CswSearchRequest();
CswClient client = this.getCswClient();
//client.setReadTimeout(SearchConfig.getConfiguredInstance().getTimeOut());
request.setCswClient(client);
String username = Val.chkStr(this.getCredentials().getUsername());
String password = Val.chkStr(this.getCredentials().getPassword());
if("".equals(username)) {
record = request.getRecordById(this.getGetMetadataRecordUrl(),
uuid, profile);
} else {
record = request.getRecordById(this.getGetMetadataRecordUrl(),
uuid, profile, username, password);
}
} catch (SearchException e) {
exc = e;
} catch (IOException e) {
exc = e;
} catch (TransformerException e) {
exc = e;
} catch (NullReferenceException e) {
exc = e;
} catch (InvalidOperationException e) {
exc = e;
}
if(exc != null) {
throw new
SearchException("Could not get metadata record object uuid=" + uuid + " : "
+ exc.getMessage(), exc);
}
return record;
}
/**
* Initialization
*
*@throws SearchException
*/
@Override
public void init() throws SearchException {
init(true);
}
/**
* Looks for the id in the repository then fills in
* other information e.g. profile, capabilities url, post url
* @throws SearchException
*/
private void init(boolean calledByFactory) throws SearchException {
HrRecord record = this.getHrRecord();
if(record != null && calledByFactory == true) {
if(record.getProtocol() instanceof HarvestProtocolCsw) {
HarvestProtocolCsw hpCsw = (HarvestProtocolCsw) record.getProtocol();
this.setProfileId(hpCsw.getProfile());
}
return;
}
boolean doCapabilities = false;
// get uuid for this search
String uuid = "";
Map<String, String> map = super.getFactoryAttributes();
if(map != null) {
uuid = Val.chkStr(super.getFactoryAttributes().get("uuid"));
}
if("".equals(uuid)) {
uuid = this.getKey();
}
try {
// Extracting getRecordByID and GetRecordsUrl associated with uuid in
// session
RequestContext reqContext = this.getRequestContext();
if(reqContext == null) {
throw new NullPointerException("RequestContext in search engine is null");
}
String sessionKeyPrfx = this.getClass().getCanonicalName() + ":uuid:"
+ uuid;
String sessionGetMetadataKey = sessionKeyPrfx + ":GetMetadataRecord:url";
String sessionGetRecordsKey = sessionKeyPrfx + ":GetRecords:url";
String sessionProfileId = sessionKeyPrfx + ":profileId";
String sessionCapabUrl = sessionKeyPrfx + ":capabilities:url";
String sessionCapObject = sessionKeyPrfx + ":capabilities:object";
Object objCapObject = reqContext.extractFromSession(sessionCapObject);
if(objCapObject instanceof CswCatalogCapabilities) {
this.setCapabilities((CswCatalogCapabilities)objCapObject);
}
Object objGetMetadataUrl = reqContext.extractFromSession(
sessionGetMetadataKey);
Object objGetRecordsUrl = reqContext.extractFromSession(
sessionGetRecordsKey);
Object objProfileId = reqContext.extractFromSession(
sessionProfileId);
Object objGetCapabUrl = reqContext.extractFromSession(
sessionCapabUrl);
if (objGetMetadataUrl == null
|| "".equals(objGetMetadataUrl.toString().trim())
|| objGetRecordsUrl == null
|| "".equals(objGetRecordsUrl.toString().trim())
|| objProfileId == null
|| "".equals(objProfileId.toString().trim())
|| objGetCapabUrl == null
|| "".equals(objGetCapabUrl.toString().trim())) {
doCapabilities = true;
} else {
this.setGetRecordsUrl(objGetRecordsUrl.toString());
this.setGetMetadataRecordUrl(objGetMetadataUrl.toString());
this.setProfileId(objProfileId.toString());
this.setGetCapabiltiesUrl(objGetCapabUrl.toString());
}
// Checking the db to check if profile and url are still the same
GptRepository repos = new GptRepository();
try {
if (record == null) {
record = repos.readHarvestRecord(uuid, this.getRequestContext());
}
Protocol harvestProtocol = record.getProtocol();
if (harvestProtocol instanceof HarvestProtocolCsw) {
HarvestProtocolCsw harvestProtocolCsw = (HarvestProtocolCsw) harvestProtocol;
if (!this.getProfileId().equals(harvestProtocolCsw.getProfile())
|| !this.getGetCapabiltiesUrl().equals(record.getHostUrl())) {
doCapabilities = true;
this.setProfileId(harvestProtocolCsw.getProfile());
this.setGetCapabiltiesUrl(record.getHostUrl());
}
} else {
throw new SearchException("repository id " + uuid + " is not expected"
+ " CSW protocol");
}
} catch (SearchException e) {
// T.M. accomodates gpt.xml values
String url = Val.chkStr(this.getFactoryAttributes().get("url"));
String profileId = Val.chkStr(this.getFactoryAttributes()
.get("profileid"));
if(!"".equals(url) && !"".equals(profileId)) {
doCapabilities = true;
this.setProfileId(profileId);
this.setGetCapabiltiesUrl(url);
} else {
throw e;
}
}
// Do the capabilities if requested
if (doCapabilities) {
super.init();
// Add info to session
reqContext.addToSession(sessionGetMetadataKey,
this.getGetMetadataRecordUrl());
reqContext.addToSession(sessionGetRecordsKey, this.getGetRecordsUrl());
reqContext.addToSession(sessionCapabUrl, this.getGetCapabiltiesUrl());
reqContext.addToSession(sessionProfileId, this.getProfileId());
reqContext.addToSession(sessionCapObject, this.getCapabilities());
}
} catch (Throwable e) {
throw new SearchException("Error while getting items from repository "
+ " with id of " + uuid + e.getMessage(), e);
}
}
/**
* Gets the abstract associated with the key
*
* @return the abstract
* @throws SearchException
*/
@Override
public String getKeyAbstract() throws SearchException {
CswCatalogCapabilities cap = this.getCapabilities();
if(cap != null) {
return Val.chkStr(cap.getTitle()) + " : "
+ Val.chkStr(cap.getAbstractText());
}
String abs = null;
String uuid = this.getKey();
try {
GptRepository repos = new GptRepository();
HrRecord record = this.getHrRecord();
if(record == null) {
record = repos.readHarvestRecord(uuid, this.getRequestContext());
}
String url = record.getHostUrl();
CswRepository csw = new CswRepository();
if (url.length() > 0) {
abs = csw.transformToHtml(url);
}
} catch (Exception e) {
throw new SearchException("Could not get abstract for uuid =" + uuid, e);
}
return Val.chkStr(abs);
}
/**
* Creates the instances.
*
* @param rids the rids
* @return the array list
* @throws SearchException
* @throws SearchException the search exception
*/
@Override
public Map<String, Object> createInstances(StringSet rids) throws SearchException {
Map<String, Object> mRidEngine =
new HashMap<String, Object>();
GptRepository repos = new GptRepository();
Map<String, HrRecord> repositoryRecord =
repos.readHarvestRecords(rids, this.getRequestContext());
// Check if any rids are missing
String msgErr = null;
for(String rid:rids) {
if(repositoryRecord.containsKey(rid)) {
continue;
}
ASearchEngine engine = SearchEngineFactory.createSearchEngine(
new SearchCriteria(),
new SearchResult(),
this.getRequestContext(), rid, this.getMessageBroker());
if(engine != null) {
mRidEngine.put(rid, engine);
continue;
}
if(msgErr == null) {
msgErr = this.getMessageBroker().retrieveMessage(
"catalog.search.distributedSearch.ridDbEntryNotFound");
}
msgErr = msgErr.replaceAll("\\{0\\}", rid);
mRidEngine.put(rid, msgErr);
}
// Create search engines for existing rids
Iterator<Entry<String, HrRecord>> iter = repositoryRecord.entrySet().iterator();
while(iter.hasNext()) {
Entry<String, HrRecord> entry = iter.next();
String rid = entry.getKey();
HrRecord hrRecord = entry.getValue();
SearchEngineExternalCsw sEngine = new SearchEngineExternalCsw();
sEngine.setKey(rid);
sEngine.setHrRecord(hrRecord);
mRidEngine.put(rid, sEngine);
}
return mRidEngine;
}
}