// $Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/portal/standard/csw/control/SimpleSearchListener.java,v 1.12 2006/10/17 20:31:18 poth Exp $
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53177 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.portal.standard.csw.control;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.xml.transform.TransformerException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.deegree.enterprise.control.AbstractListener;
import org.deegree.enterprise.control.FormEvent;
import org.deegree.enterprise.control.RPCException;
import org.deegree.enterprise.control.RPCFactory;
import org.deegree.enterprise.control.RPCMember;
import org.deegree.enterprise.control.RPCMethodCall;
import org.deegree.enterprise.control.RPCParameter;
import org.deegree.enterprise.control.RPCStruct;
import org.deegree.enterprise.control.RPCWebEvent;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.util.CharsetUtils;
import org.deegree.framework.xml.DOMPrinter;
import org.deegree.framework.xml.NamespaceContext;
import org.deegree.framework.xml.XMLParsingException;
import org.deegree.framework.xml.XMLTools;
import org.deegree.ogcbase.CommonNamespaces;
import org.deegree.portal.standard.csw.CatalogClientException;
import org.deegree.portal.standard.csw.MetadataTransformer;
import org.deegree.portal.standard.csw.configuration.CSWClientConfiguration;
import org.deegree.portal.standard.csw.model.DataSessionRecord;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* A <code>${type_name}</code> class.<br/> This listener does more than just search for data. It
* searches for data *and* then searches if there are services (WMS, WFS) available, which provide
* this data.
*
* @author <a href="mailto:mays@lat-lon.de">Judit Mays</a>
* @author last edited by: $Author: poth $
*
* @version $Revision: 1.12 $, $Date: 2006/10/17 20:31:18 $
*/
public class SimpleSearchListener extends AbstractListener {
private static final ILogger LOG = LoggerFactory.getLogger( AddToShoppingCartListener.class );
// needs to be public for jsp pages
public static final String HTML_FRAGMENT = "HTML_FRAGMENT";
static final String RESULT_SEARCH = "RESULT_SEARCH";
static final String RPC_CATALOG = "catalog";
static final String RPC_FORMAT = "RPC_FORMAT"; // ISO19115, ISO19119, ...
static final String SESSION_AVAILABLESERVICECATALOGS = "AVAILABLESERVICECATALOGS";
static final String SESSION_DATARECORDS = "DATARECORDS";
static final String SESSION_REQUESTFORRESULTS = "SESSION_REQUESTFORRESULTS";
static final String SESSION_RESULTFORHITS = "SESSION_RESULTFORHITS";
protected CSWClientConfiguration config = null;
// protected Node nsNode = null;
protected NamespaceContext nsContext = CommonNamespaces.getNamespaceContext();
public void actionPerformed( FormEvent event ) {
LOG.entering();
RPCWebEvent rpcEvent = (RPCWebEvent) event;
HttpSession session = ( (HttpServletRequest) this.getRequest() ).getSession( true );
config = (CSWClientConfiguration) session.getAttribute( Constants.CSW_CLIENT_CONFIGURATION );
// try {
// nsNode = XMLTools.getNamespaceNode( config.getNamespaceBindings() );
// } catch( ParserConfigurationException e ) {
// e.printStackTrace();
// gotoErrorPage( "Could not create namespace node for SimpleSearchListener."
// + e.getMessage() );
// LOG.exiting();
// return;
// }
try {
validateRequest( rpcEvent );
} catch ( Exception e ) {
e.printStackTrace();
gotoErrorPage( "Invalid rpc request: \n" + e.getMessage() );
LOG.exiting();
return;
}
List rpcCatalogs;
RPCStruct rpcStruct;
String rpcFormat;
String rpcProtocol;
try {
rpcCatalogs = extractRPCCatalogs( rpcEvent );
rpcStruct = extractRPCStruct( rpcEvent, 1 );
rpcFormat = (String) extractRPCMember( rpcStruct, RPC_FORMAT );
rpcProtocol = (String) extractRPCMember( rpcStruct, Constants.RPC_PROTOCOL );
} catch ( Exception e ) {
e.printStackTrace();
gotoErrorPage( "Invalid rpc event: \n" + e.getMessage() );
LOG.exiting();
return;
}
// for further use in TurnPageListener
session.setAttribute( Constants.RPC_PROTOCOL, rpcProtocol );
// first "GetRecords"-request (resultType="HITS", typeNames="dataset")
String req = null;
HashMap resultHits = null;
try {
req = createRequest( rpcStruct, rpcFormat, "HITS" );
} catch ( Exception e ) {
e.printStackTrace();
gotoErrorPage( "Invalid request for hits: \n" + e.getMessage() );
LOG.exiting();
return;
}
try {
resultHits = performRequest( rpcProtocol, req, rpcCatalogs, "HITS" );
// save to session for further use in TurnPageListener
session.setAttribute( SESSION_RESULTFORHITS, resultHits );
} catch ( Exception e ) {
e.printStackTrace();
gotoErrorPage( "Server is not reachable or did not answer with valid XML: \n"
+ e.getMessage() );
LOG.exiting();
return;
}
int hits = 0;
try {
hits = numberOfMatchesInMap( resultHits );
} catch ( Exception e ) {
e.printStackTrace();
gotoErrorPage( "Invalid Result: \n" + e.getMessage() );
LOG.exiting();
return;
}
HashMap resultResults = null;
List dsrListSearch = null;
Map availableServiceCatalogsMap = null;
if ( hits > 0 ) {
// second "GetRecords"-request (resultType="RESULTS", typeNames="dataset")
req = null;
try {
req = createRequest( rpcStruct, rpcFormat, "RESULTS" );
// if resultType="RESULT", then save request to session to be able to perform
// the request again and again for more of the google-like pages (TurnPageListener)
session.setAttribute( SESSION_REQUESTFORRESULTS, req );
} catch ( Exception e ) {
e.printStackTrace();
gotoErrorPage( "Invalid request for results: \n" + e.getMessage() );
LOG.exiting();
return;
}
try {
resultResults = performRequest( rpcProtocol, req, rpcCatalogs, "RESULTS" );
} catch ( Exception e ) {
e.printStackTrace();
gotoErrorPage( "Server is not reachable or did not answer with valid XML: \n"
+ e.getMessage() );
LOG.exiting();
return;
}
// create data session records for results and store them in the session
try {
dsrListSearch = createDataSessionRecords( resultResults );
} catch ( CatalogClientException e ) {
e.printStackTrace();
gotoErrorPage( "Could not create list of DataSessionRecords." + e.getMessage() );
LOG.exiting();
return;
}
try {
// TODO make usable for other formats, not only "ISO19119"
availableServiceCatalogsMap = doServiceSearch( resultResults, "ISO19119", "HITS",
null );
} catch ( CatalogClientException e ) {
e.printStackTrace();
gotoErrorPage( "Error creating relevant search result list: \n" + e.getMessage() );
LOG.exiting();
return;
}
}
// save List of data session records to session (may be null or empty)
session.setAttribute( SESSION_DATARECORDS, dsrListSearch );
// save Map of available service catalogs to session (may be null or empty)
session.setAttribute( SESSION_AVAILABLESERVICECATALOGS, availableServiceCatalogsMap );
// handle result: take result and transform it to produce html output
String fileName = "metaList2html.xsl"; // default value
// FIXME replace format with current value
HashMap xslMap = config.getProfileXSL( "Profiles." + rpcFormat );
if ( xslMap != null ) {
if ( xslMap.get( "brief" ) != null ) {
fileName = (String) xslMap.get( "brief" );
}
}
try {
String pathToFile = "file:" + getHomePath() + "WEB-INF/conf/igeoportal/" + fileName;
handleResult( resultHits, resultResults, pathToFile );
} catch ( Exception e ) {
e.printStackTrace();
gotoErrorPage( "Error handling result: " + e.getMessage() );
LOG.exiting();
return;
}
LOG.exiting();
return;
}
// /**
// *
// * @param session
// * @param dsrListSearch
// */
// private void addDataSessionRecordsToSessionAttrib( HttpSession session, List dsrListSearch ) {
// LOG.entering();
//
// List dsrListSession;
// if ( session.getAttribute( Constants.SESSION_DATARECORDS ) != null ) {
// dsrListSession = (ArrayList)session.getAttribute( Constants.SESSION_DATARECORDS );
// for( int i = 0; i < dsrListSearch.size(); i++ ) {
// if ( ! dsrListSession.contains( dsrListSearch.get(i) ) ) {
// dsrListSession.add( dsrListSearch );
// }
// }
// } else {
// dsrListSession = new ArrayList( dsrListSearch.size() );
// dsrListSession.addAll( dsrListSearch );
// }
// session.setAttribute( Constants.SESSION_DATARECORDS, dsrListSession );
//
// LOG.exiting();
// }
/**
*
* @param rpcEvent
* @throws CatalogClientException
*/
protected void validateRequest( RPCWebEvent rpcEvent )
throws CatalogClientException {
LOG.entering();
RPCParameter[] params = extractRPCParameters( rpcEvent );
// validity check for number of parameters in RPCMethodCall
if ( params.length != 2 ) {
throw new CatalogClientException( "Request/Method Call must contain two parameters, not: "
+ params.length );
}
RPCStruct rpcStruct = extractRPCStruct( rpcEvent, 1 );
String rpcFormat = (String) extractRPCMember( rpcStruct, RPC_FORMAT );
String rpcProtocol = (String) extractRPCMember( rpcStruct, Constants.RPC_PROTOCOL );
if ( rpcFormat == null || rpcProtocol == null ) {
throw new CatalogClientException( "Format and protocol must be set in the rpcEvent." );
}
// go through each catalog of the rpc and validate
List rpcCatalogs = extractRPCCatalogs( rpcEvent );
String rpc_catalog = null;
for ( int i = 0; i < rpcCatalogs.size(); i++ ) {
rpc_catalog = (String) rpcCatalogs.get( i );
// validity check for catalog
String[] catalogs = config.getCatalogNames();
boolean containsCatalog = false;
for ( int j = 0; j < catalogs.length; j++ ) {
if ( catalogs[j].equals( rpc_catalog ) ) {
containsCatalog = true;
}
}
if ( !containsCatalog ) {
throw new CatalogClientException( "The catalog " + rpc_catalog + " is not "
+ "configured for this client." );
}
// validity check for format
// is requested catalog capable to serve requested metadata format?
List formats = config.getCatalogFormats( rpc_catalog );
if ( formats == null || !formats.contains( rpcFormat ) ) {
throw new CatalogClientException( "The catalog " + rpc_catalog + " does not "
+ "provide the requested format " + rpcFormat );
}
// validity check for protocol
// is requested catalog reachable through requested protocol?
List protocols = config.getCatalogProtocols( rpc_catalog );
if ( !protocols.contains( rpcProtocol ) ) {
throw new CatalogClientException( "The catalog " + rpc_catalog + " does not "
+ "provide the requested protocol " + rpcProtocol );
}
}
LOG.exiting();
return;
}
/**
* This method creates a csw request with the RequestFactory of the passed format, using the
* paramter values passed in the rpcStruct. (csw:GetRecords request, if the passed resultType is
* HITS or RESULTS, and csw:GetRecordsById request, if the passed resultType is null).
*
* @param rpcStruct
* The struct contains parameter values to be used in the RequestFactory.
* @param format
* The format determines the RequestFactory to be used.
* @param resultType
* The type of desired result. Possible values are HITS or RESULTS or null.
* @return Returns the xml encoded request as <code>String</code>.
* @throws CatalogClientException
*/
protected String createRequest( RPCStruct rpcStruct, String format, String resultType )
throws CatalogClientException {
LOG.entering();
CSWRequestFactory fac = RequestFactoryFinder.findFactory( format );
fac.setConfiguration( config );
String request = fac.createRequest( rpcStruct, resultType );
LOG.exiting();
return request;
}
/**
*
* @param protocol
* @param request
* @param catalogs
* @param type
* @return Returns a <code>HashMap</code>, which contains one key-value-pair for each
* catalogue, that has been searched. The key is the name of the catalogue. The value is
* the doc Document, that contains the number of matches (resultType="HITS"), or 1 to n
* metadata entries (resultType="RESULTS")
* @throws CatalogClientException
*/
protected HashMap performRequest( String protocol, String request, List catalogs, String type )
throws CatalogClientException {
LOG.entering();
HashMap<String, Document> result = new HashMap<String, Document>();
// loop for all catalogues contained in catalogs
for ( int i = 0; i < catalogs.size(); i++ ) {
boolean useSOAP = false;
List list = config.getCatalogProtocols( (String) catalogs.get( i ) );
if ( protocol != null ) {
if ( !list.contains( protocol ) ) {
throw new CatalogClientException( "The catalog configuration does not support " +
"the requested protocol.\n" );
}
useSOAP = "SOAP".equals( protocol );
} else {
for ( int j = 0; j < list.size(); j++ ) {
if ( "SOAP".equals( list.get( j ) ) ) {
useSOAP = true;
break;
}
}
}
String cswAddress = config.getCatalogServerAddress( (String) catalogs.get( i ) );
if ( cswAddress == null ) {
throw new CatalogClientException( "The catalog configuration does not support the " +
"requested server address.\n" );
}
try {
if ( useSOAP ) {
// TODO test if this SOAP is working properly
StringBuffer soapRequest = new StringBuffer( 5000 );
soapRequest.append( "<soap:Envelope " )
.append( "xmlns:soap=\"http://www.w3.org/2001/12/soap-envelope\" " )
.append( "soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">" )
.append( request )
.append( "</soap:Envelope>" );
request = soapRequest.toString();
}
// send post request
HttpClient httpclient = new HttpClient();
httpclient.getHttpConnectionManager().getParams().setSoTimeout( 30000 );
PostMethod postMethod = new PostMethod( cswAddress );
postMethod.setRequestEntity( new StringRequestEntity( request ) );
httpclient.executeMethod( postMethod );
String resp = postMethod.getResponseBodyAsString();
Document doc = XMLTools.parse( new StringReader( resp ) );
// write key-value-pair to HashMap
result.put( (String) catalogs.get( i ), doc );
} catch ( Exception e ) {
e.printStackTrace();
throw new CatalogClientException( e.getMessage() );
}
}
LOG.exiting();
return result;
}
/**
*
* @param resultHits
* @param resultResults
* @param pathToXslFile (
* e.g. file://$iGeoPortal_home$/WEB-INF/conf/igeoportal/metaList2html.xsl );
* @throws XMLParsingException
* if the documents contained in resultHits don't have the expected structure.
* @throws CatalogClientException
*/
protected void handleResult( Object resultHits, Object resultResults, String pathToXslFile )
throws XMLParsingException, CatalogClientException {
LOG.entering();
Map map = ( resultResults != null ) ? (HashMap) resultResults : (HashMap) resultHits;
Iterator it = map.keySet().iterator();
URL u = null;
StringBuffer htmlFragment = new StringBuffer( 5000 );
MetadataTransformer mt = null;
try {
u = new URL( pathToXslFile );
mt = new MetadataTransformer( u.getFile() );
} catch ( Exception e ) {
throw new CatalogClientException( e.getMessage() );
}
String catalog = null;
Document doc = null;
String docString = null;
// one loop for each catalog in result ( where resultType="RESULTS" )
while ( it.hasNext() ) {
catalog = (String) it.next();
doc = (Document) map.get( catalog );
docString = DOMPrinter.nodeToString( doc, CharsetUtils.getSystemCharset() );
Reader reader = new StringReader( docString );
// need to get numberOfRecordsMatched from the document where resultType is "HITS",
// because only there the number is correct.
// In document where resultType="RESULTS" the numberOfRecordsMatched is always equal to
// numberOfRecordReturned, which is LESS OR EQUAL to the correct numberOfRecordsMatched.
int matches = numberOfMatchesInDoc( (Document) ( (HashMap) resultHits ).get( catalog ) );
// need to get startPosition from the request, because the value 'nextRec' in
// GetRecordsResponse is always '0', which is not always correct ;o)
int startPos = 0;
// load request from session
HttpSession session = ( (HttpServletRequest) this.getRequest() ).getSession( true );
String req = (String) session.getAttribute( SESSION_REQUESTFORRESULTS );
if ( req != null ) {
try {
StringReader sr = new StringReader( req );
Document docReq = XMLTools.parse( sr );
startPos =
Integer.parseInt( docReq.getDocumentElement().getAttribute( "startPosition" ) );
} catch ( Exception e ) {
e.printStackTrace();
throw new CatalogClientException( e.getMessage() );
}
}
// transformation
try {
htmlFragment.append( mt.transformMetadata( reader, catalog, null, matches, startPos,
"list" ) );
} catch ( Exception e ) {
throw new CatalogClientException( e.getMessage() );
}
}
this.getRequest().setAttribute( RESULT_SEARCH, resultResults );
this.getRequest().setAttribute( HTML_FRAGMENT, htmlFragment.toString() );
LOG.exiting();
}
/**
* @param results
* @return Returns a List of distinct DataSessionRecords for all metadata elements within the
* passed results.
* @throws CatalogClientException
* if the identifier or the title of a metadata element could not be extracted.
*/
protected List<DataSessionRecord> createDataSessionRecords( HashMap results )
throws CatalogClientException {
LOG.entering();
List<DataSessionRecord> dsrList = new ArrayList<DataSessionRecord>();
Iterator it = results.keySet().iterator();
while ( it.hasNext() ) {
String catalog = (String) it.next();
Document doc = (Document) results.get( catalog );
List mdList; // list of unique metadata element nodes
try {
mdList = extractMetadata( doc );
} catch ( Exception e ) {
throw new CatalogClientException( "Cannot extract metadata elements: "
+ e.getMessage() );
}
String xPathToId = config.getXPathToDataIdentifier();
String xPathToTitle = config.getXPathToDataTitle();
for ( int j = 0; j < mdList.size(); j++ ) {
Node mdNode = (Node) mdList.get( j );
String id = null;
String title = null;
try {
id = extractValue( mdNode, xPathToId );
title = extractValue( mdNode, xPathToTitle );
} catch ( Exception e ) {
throw new CatalogClientException( "could not extract title and/or identifier: "
+ e.getMessage() );
}
DataSessionRecord dsr = new DataSessionRecord( id, catalog, title );
if ( !dsrList.contains( dsr ) ) {
// this should be a redundant check. testing just in case...
dsrList.add( dsr );
}
}
}
LOG.exiting();
return dsrList;
}
/**
* Extracts all Metadata nodes from the passed csw:GetRecordsResponse Document.
*
* @param doc
* The csw:GetRecordsResponse Document from which to extract the Metadata nodes.
* @return Returns a NodeList of Metadata Elements for the passed Document.
* @throws CatalogClientException
* if metadata nodes could not be extracted from the passed Document.
* @throws XMLParsingException
*/
protected List extractMetadata( Document doc )
throws CatalogClientException, XMLParsingException {
List nl = null;
String xPathToMetadata = "csw:GetRecordsResponse/csw:SearchResults/child::*";
// nl = XMLTools.getXPath( xPathToMetadata, doc, nsNode ); // old
nl = XMLTools.getNodes( doc, xPathToMetadata, nsContext ); // new
if ( nl == null || nl.size() < 1 ) {
throw new CatalogClientException( "could not extract metadata nodes." );
}
return nl;
}
/**
* @param node
* @param xPath
* @return Returns the value for the passed node and xPath.
* @throws TransformerException
* @throws CatalogClientException
* @throws XMLParsingException
*/
protected String extractValue( Node node, String xPath )
throws CatalogClientException, XMLParsingException {
LOG.entering();
String s = XMLTools.getNodeAsString( node, xPath, nsContext, null );
if ( s == null ) {
throw new CatalogClientException( "no value could be found using xPath: " + xPath );
}
LOG.exiting();
return s;
}
/**
* The number of matches returned is the number of matches for all catalogs added together.
*
* @param result
* The HashMap containing the result document from the performed request.
* @return Returns the number of matches indicated in the result.
* @throws XMLParsingException,
* if the result document in the passed HashMap does not contain the expected nodes
* and attributes.
*/
private int numberOfMatchesInMap( HashMap result )
throws XMLParsingException {
LOG.entering();
int hits = 0;
Iterator iterator = result.keySet().iterator();
while ( iterator.hasNext() ) {
String catalog = (String) iterator.next();
Document doc = (Document) result.get( catalog ); // result(value)
int matches = numberOfMatchesInDoc( doc );
hits += matches;
}
LOG.exiting();
return hits;
}
/**
* The number of matches returned is the number for one single catalog.
*
* @param doc
* The Document containing the result for one catalog.
* @return Returns the number of matches for one catalog only.
* @throws XMLParsingException
*/
private int numberOfMatchesInDoc( Document doc )
throws XMLParsingException {
LOG.entering();
Element docElement = doc.getDocumentElement(); // root element
Element searchResults = (Element) XMLTools.getRequiredNode( docElement,
"csw:SearchResults", nsContext );
String matches = XMLTools.getRequiredAttrValue( "numberOfRecordsMatched", null,
searchResults );
LOG.exiting();
return Integer.parseInt( matches );
}
/**
*
* @param result
* HashMap containing data catalog names (as keys) and GetRecordResponse Documents
* (as values).
* @param format
* some service format like "ISO19119"
* @param resultType
* either "HITS" or "RESULTS".
* @param elementSet
* The elementSetName to use ("brief", "full"). Default is "brief".
* @return Returns a Map that contains the title extracted from the passed document (as key) and
* a List of all corresponding available service catalogs (as value).
* @throws CatalogClientException
*/
protected Map doServiceSearch( HashMap result, String format, String resultType,
String elementSet )
throws CatalogClientException {
LOG.entering();
List serviceCatalogs = config.getServiceMetadataCatalogs();
Map<String, List<String>> availableServiceCatalogsMap =
new HashMap<String, List<String>>( 10 );
// for each kvp (i.e. for each data catalog) in result do the following loop
Iterator iterator = result.keySet().iterator();
while ( iterator.hasNext() ) {
String catalog = (String) iterator.next(); // result(key)
Document doc = (Document) result.get( catalog ); // result(value)
List nl; // list of unique metadata element nodes
try {
nl = extractMetadata( doc );
} catch ( Exception e ) {
e.printStackTrace();
throw new CatalogClientException( "Cannot extract metadata: \n" + e.getMessage() );
}
List<String> titles = new ArrayList<String>( nl.size() );
String xPathToTitle = config.getXPathToDataTitle();
;
if ( "full".equals( elementSet ) ) {
xPathToTitle = config.getXPathToDataTitleFull();
}
// get list of titles for current catalog
// REASON: the link between iso19115 and iso19119 is the "title".
// TODO make this work for other formats where the link is something else completely.
try {
for ( int i = 0; i < nl.size(); i++ ) {
titles.add( extractValue( (Node) nl.get( i ), xPathToTitle ) );
}
} catch ( Exception e ) {
e.printStackTrace();
throw new CatalogClientException( "Cannot extract titles: \n" + e.getMessage() );
}
// for each title
for ( int i = 0; i < titles.size(); i++ ) {
// DO SERVICE SEARCH
// simple search had results (number of hits > 0), so a getRecords request with
// resulttype=RESULTS was done and now a service search is needed for those results.
// get the service info: search a service for the current title
RPCStruct serviceStruct = null;
String template = "CSWServiceSearchRPCMethodCallTemplate.xml";
try {
serviceStruct = createRpcStructForServiceSearch( template, titles.get( i ) );
} catch ( Exception e ) {
e.printStackTrace();
throw new CatalogClientException( "Invalid RPCStruct: \n" + e.getMessage() );
}
String serviceReq = null;
try {
serviceReq = createRequest( serviceStruct, format, resultType );
} catch ( Exception e ) {
e.printStackTrace();
throw new CatalogClientException( "Invalid Request: \n" + e.getMessage() );
}
HashMap serviceResult = null;
try {
serviceResult = performRequest( null, serviceReq, serviceCatalogs, resultType );
} catch ( Exception e ) {
e.printStackTrace();
throw new CatalogClientException(
"The server is not reachable or did not answer with valid XML: \n"
+ e.getMessage() );
}
List<String> availableServiceCatalogs = null;
// get service catalogs that are available for the current dataTitle
try {
availableServiceCatalogs = extractAvailableServiceCatalogs( serviceResult );
} catch ( XMLParsingException e ) {
e.printStackTrace();
throw new CatalogClientException( "Invalid Result: \n" + e.getMessage() );
}
availableServiceCatalogsMap.put( titles.get( i ), availableServiceCatalogs );
} // end for each dataTitle
} // end for each kvp in result
LOG.exiting();
return availableServiceCatalogsMap;
}
/**
* Extract all catalogs from serviceResult that actually do have the service available (= where
* number of records matched is greater than 0) and add them to the returned List.
*
* @param serviceResult
* @return Returns a <code>List</code> of all available service catalogs. May be null.
* @throws XMLParsingException
*/
private List<String> extractAvailableServiceCatalogs( Map serviceResult )
throws XMLParsingException {
LOG.entering();
List<String> availableServiceCatalogs = new ArrayList<String>( serviceResult.size() );
// one loop for each catalog in serviceResult
Iterator it = serviceResult.keySet().iterator();
while ( it.hasNext() ) {
String servCatalog = (String) it.next();
Document servDoc = (Document) serviceResult.get( servCatalog );
int matches = numberOfMatchesInDoc( servDoc );
if ( matches > 0 ) {
availableServiceCatalogs.add( servCatalog );
}
}
LOG.exiting();
return ( availableServiceCatalogs.size() == 0 ) ? null : availableServiceCatalogs;
}
/**
* @param template
* @param title
* @return Returns the new rpcStruct.
* @throws CatalogClientException
* @throws RPCException
*/
protected RPCStruct createRpcStructForServiceSearch( String template, String title )
throws CatalogClientException, RPCException {
LOG.entering();
RPCStruct rpcStruct = null;
InputStream is = SimpleSearchListener.class.getResourceAsStream( template );
String rpc = null;
try {
InputStreamReader ireader = new InputStreamReader( is );
BufferedReader br = new BufferedReader( ireader );
StringBuffer sb = new StringBuffer( 50000 );
while ( ( rpc = br.readLine() ) != null ) {
sb.append( rpc );
}
rpc = sb.toString();
br.close();
} catch ( Exception e ) {
throw new CatalogClientException( "Could not read template or transform it to String: "
+ e.getMessage() );
}
// replace templates in struct with passed values
rpc = rpc.replaceAll( "\\$TITLE", title );
StringReader reader = new StringReader( rpc );
RPCMethodCall mc = RPCFactory.createRPCMethodCall( reader );
try {
RPCParameter[] params = mc.getParameters();
rpcStruct = (RPCStruct) params[0].getValue();
} catch ( Exception e ) {
throw new CatalogClientException( "Cannot extract struct from RPCMethodCall: \n"
+ e.getMessage() );
}
LOG.exiting();
return rpcStruct;
}
/**
* Extracts the parameters from the method call element within the passed rpcEvent.
*
* @param rpcEvent
* @return Returns the parameters as array of <code>RPCParameter</code>.
* @throws CatalogClientException
*/
protected RPCParameter[] extractRPCParameters( RPCWebEvent rpcEvent )
throws CatalogClientException {
RPCParameter[] params;
try {
RPCMethodCall mc = rpcEvent.getRPCMethodCall();
params = mc.getParameters();
} catch ( Exception e ) {
throw new CatalogClientException( "Cannot extract parameters from RPCWebEvent: "
+ e.getMessage() );
}
return params;
}
/**
* Extracts the catalog names from the first parameter of the params element within the passed
* rpcEvent.
*
* @param rpcEvent
* @return Returns the catalogue names as array of <code>String</code>.
* @throws CatalogClientException
*/
protected List extractRPCCatalogs( RPCWebEvent rpcEvent )
throws CatalogClientException {
List<String> catalogs = new ArrayList<String>( 10 );
try {
RPCParameter[] params = extractRPCParameters( rpcEvent );
RPCParameter[] rpcCatalogs = (RPCParameter[]) params[0].getValue();
for ( int i = 0; i < rpcCatalogs.length; i++ ) {
catalogs.add( (String) rpcCatalogs[i].getValue() );
}
} catch ( Exception e ) {
throw new CatalogClientException( "Cannot extract catalog names from RPCWebEvent: "
+ e.getMessage() );
}
return catalogs;
}
/**
* Extracts the <code>RPCStruct</code> from the indicated parameter in the params element of
* the passed <code>RPCWebEvent</code>.
*
* @param rpcEvent
* The RPCWebEvent, that contains the RPCStruct to extract.
* @param index
* The index of the parameter from which to extract the RPCStruct (starting with 0).
* @return Returns the <code>RPCStruct</code> from the indicated params element.
* @throws CatalogClientException
*/
protected RPCStruct extractRPCStruct( RPCWebEvent rpcEvent, int index )
throws CatalogClientException {
RPCStruct rpcStruct;
try {
RPCParameter[] params = extractRPCParameters( rpcEvent );
rpcStruct = (RPCStruct) params[index].getValue();
} catch ( Exception e ) {
throw new CatalogClientException( "Cannot extract struct from RPCWebEvent: "
+ e.getMessage() );
}
return rpcStruct;
}
/**
* Extracts the member of the passed name from the passed struct.
*
* @param struct
* The rpcStruct to extract the passed member from.
* @param member
* The Member to extract from the passed rpcStruct.
* @return Returns the member value object.
* @throws CatalogClientException
*/
protected Object extractRPCMember( RPCStruct struct, String member )
throws CatalogClientException {
RPCMember rpcMember;
try {
rpcMember = struct.getMember( member );
} catch ( Exception e ) {
throw new CatalogClientException( "Cannot extract member " + member
+ " from RPCStruct: " + e.getMessage() );
}
return rpcMember.getValue();
}
// /**
// * Extracts the member of the passed name from the passed struct.
// *
// * @param struct The rpcStruct to extract the passed member from.
// * @param memberName The Member to extract from the passed rpcStruct.
// * @return Returns the member value object.
// * @throws CatalogClientException
// */
// protected Object extractRPCMemberValue( RPCStruct struct, String memberName )
// throws CatalogClientException {
// String memberValue = null;
// try {
// memberValue = (String) struct.getMember( memberName ).getValue();
// } catch (Exception e) {
// throw new CatalogClientException( "Cannot extract member value "+ memberName +" from RPCStruct: "
// + e.getMessage() );
// }
// return memberValue;
// }
}
/* ********************************************************************
Changes to this class. What the people have been up to:
$Log: SimpleSearchListener.java,v $
Revision 1.12 2006/10/17 20:31:18 poth
*** empty log message ***
Revision 1.11 2006/10/12 13:09:50 mays
bugfix: avoid NullPointerException
Revision 1.10 2006/08/02 14:10:26 poth
*** empty log message ***
Revision 1.9 2006/07/31 11:02:44 mays
move constants from class Constants to the classes where they are needed
Revision 1.8 2006/07/31 09:33:58 mays
move Constants to package control, update imports
Revision 1.7 2006/06/30 08:43:19 mays
clean up code and java doc
Revision 1.6 2006/06/23 13:38:25 mays
add/update csw control files
Revision 1.15 2006/05/31 17:05:50 mays
add elementSet to parameter list of doServiceSearch()
Revision 1.14 2006/05/15 13:28:05 mays
get xsl file name for transformation from configuration file
Revision 1.13 2006/04/20 15:39:21 mays
made path to xsl file relativ;
some cleanup
Revision 1.12 2006/04/11 09:41:54 mays
changing return type of extractRPCMember from String to Object for wider usability
Revision 1.11 2006/04/11 08:20:07 mays
adapting header
Revision 1.10 2006/04/10 15:20:51 mays
make sure that SESSION_DATARECORDS are set under all circumstances
Revision 1.9 2006/04/07 07:29:54 mays
major restructuring
Revision 1.8 2006/03/28 15:45:14 mays
clean up
Revision 1.7 2006/03/27 18:40:25 mays
WIP. major changes
Revision 1.6 2006/03/16 18:10:23 mays
add new methods, add params to method calls, clean up, and more
Revision 1.5 2006/03/14 18:37:11 mays
major restructuring according to ap
Revision 1.4 2006/03/10 16:11:47 mays
restructuring of service search
Revision 1.3 2006/03/09 17:12:59 mays
WIP: add handling of service search (not finished yet)
Revision 1.2 2006/03/03 17:17:54 mays
change return type of createRequest from HashMap to String.
change parameter list of performeRequest because of this.
Revision 1.1 2006/03/02 12:35:37 poth
*** empty log message ***
Revision 1.11 2006/02/14 17:26:18 mays
structural changes
Revision 1.10 2006/02/10 16:50:21 mays
minor changes
Revision 1.9 2006/02/09 16:43:15 mays
only two prameters are passed to csw
Revision 1.8 2006/02/09 10:58:36 mays
minor changes, check new param from cws config file
Revision 1.7 2006/02/08 14:27:31 mays
Fixed CVS keyword expansion mode.
Revision 1.6 2006/02/08 12:41:01 mays
make use of csw-classes instead of wcasclient-classes
make use of RequestFactoryFinder
Revision 1.5 2006/02/03 15:20:45 mays
minor cleanup. more to do
Revision 1.4 2006/01/31 17:28:38 mays
work in progress
Revision 1.3 2006/01/27 15:29:10 mays
first implementation of various methods
Revision 1.2 2006/01/18 16:47:43 mays
WIP - change fake search result
Revision 1.1 2006/01/13 15:18:00 mays
first implementation of new empty classes for csw metadata
********************************************************************** */