001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/portal/standard/csw/control/OverviewMetadataListener.java $
002 /*----------------------------------------------------------------------------
003 This file is part of deegree, http://deegree.org/
004 Copyright (C) 2001-2009 by:
005 Department of Geography, University of Bonn
006 and
007 lat/lon GmbH
008
009 This library is free software; you can redistribute it and/or modify it under
010 the terms of the GNU Lesser General Public License as published by the Free
011 Software Foundation; either version 2.1 of the License, or (at your option)
012 any later version.
013 This library is distributed in the hope that it will be useful, but WITHOUT
014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016 details.
017 You should have received a copy of the GNU Lesser General Public License
018 along with this library; if not, write to the Free Software Foundation, Inc.,
019 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020
021 Contact information:
022
023 lat/lon GmbH
024 Aennchenstr. 19, 53177 Bonn
025 Germany
026 http://lat-lon.de/
027
028 Department of Geography, University of Bonn
029 Prof. Dr. Klaus Greve
030 Postfach 1147, 53001 Bonn
031 Germany
032 http://www.geographie.uni-bonn.de/deegree/
033
034 e-mail: info@deegree.org
035 ----------------------------------------------------------------------------*/
036
037 package org.deegree.portal.standard.csw.control;
038
039 import java.io.FileNotFoundException;
040 import java.io.IOException;
041 import java.io.Reader;
042 import java.io.StringReader;
043 import java.net.MalformedURLException;
044 import java.net.URL;
045 import java.util.ArrayList;
046 import java.util.HashMap;
047 import java.util.Iterator;
048 import java.util.List;
049 import java.util.Map;
050
051 import javax.servlet.http.HttpServletRequest;
052 import javax.servlet.http.HttpSession;
053 import javax.xml.transform.TransformerException;
054
055 import org.deegree.enterprise.control.FormEvent;
056 import org.deegree.enterprise.control.RPCParameter;
057 import org.deegree.enterprise.control.RPCStruct;
058 import org.deegree.enterprise.control.RPCWebEvent;
059 import org.deegree.framework.log.ILogger;
060 import org.deegree.framework.log.LoggerFactory;
061 import org.deegree.framework.util.CharsetUtils;
062 import org.deegree.framework.xml.DOMPrinter;
063 import org.deegree.framework.xml.XMLFragment;
064 import org.deegree.framework.xml.XMLParsingException;
065 import org.deegree.framework.xml.XMLTools;
066 import org.deegree.i18n.Messages;
067 import org.deegree.ogcbase.CommonNamespaces;
068 import org.deegree.portal.standard.csw.CatalogClientException;
069 import org.deegree.portal.standard.csw.MetadataTransformer;
070 import org.deegree.portal.standard.csw.configuration.CSWClientConfiguration;
071 import org.w3c.dom.Document;
072 import org.w3c.dom.Node;
073
074 /**
075 * A <code>${type_name}</code> class.<br/> TODO class description
076 *
077 * @author <a href="mailto:mays@lat-lon.de">Judit Mays</a>
078 * @author last edited by: $Author: mschneider $
079 *
080 * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
081 */
082 public class OverviewMetadataListener extends SimpleSearchListener {
083
084 private static final ILogger LOG = LoggerFactory.getLogger( OverviewMetadataListener.class );
085
086 static final String SESSION_METADATA = "SESSION_METADATA";
087
088 @Override
089 public void actionPerformed( FormEvent event ) {
090
091 HttpSession session = ( (HttpServletRequest) this.getRequest() ).getSession( true );
092 config = (CSWClientConfiguration) session.getAttribute( Constants.CSW_CLIENT_CONFIGURATION );
093
094 nsContext = CommonNamespaces.getNamespaceContext();
095
096 RPCWebEvent rpcEvent = (RPCWebEvent) event;
097 RPCParameter[] params;
098 try {
099 params = extractRPCParameters( rpcEvent );
100 } catch ( Exception e ) {
101 gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_INVALID_RPC_EVENT", e.getMessage() ) );
102 LOG.logError( e.getMessage(), e );
103 return;
104 }
105
106 // get transformation file name
107 String fileName = "csw/metaOverview2html.xsl"; // default value
108 // FIXME replace format with current value
109 String format = "Profiles.ISO19115";
110 HashMap xslMap = config.getProfileXSL( format );
111 if ( xslMap != null ) {
112 if ( xslMap.get( "full" ) != null ) {
113 fileName = (String) xslMap.get( "full" );
114 }
115 }
116 String pathToXslFile = "file:" + getHomePath() + "WEB-INF/conf/igeoportal/" + fileName;
117 LOG.logDebug( "path to xslFile: ", pathToXslFile );
118
119 if ( params == null || params.length == 0 ) {
120 // get Metadata from the users session
121 session = ( (HttpServletRequest) this.getRequest() ).getSession( true );
122 Object o = session.getAttribute( SESSION_METADATA );
123
124 if ( o != null ) {
125 try {
126 handleResult( o, pathToXslFile, "overview" );
127 } catch ( Exception e ) {
128 gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_ERROR_HANDLE_RESULT", e.getMessage() ) );
129 LOG.logError( e.getMessage() );
130 return;
131 }
132 }
133 } else {
134 try {
135 validateRequest( rpcEvent );
136 } catch ( Exception e ) {
137 gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_INVALID_REQ", e.getMessage() ) );
138 LOG.logError( e.getMessage() );
139 return;
140 }
141
142 String rpcCatalog;
143 RPCStruct rpcStruct;
144 String rpcFormat;
145 String rpcProtocol;
146
147 try {
148 rpcStruct = extractRPCStruct( rpcEvent, 0 );
149 rpcCatalog = (String) extractRPCMember( rpcStruct, RPC_CATALOG );
150 rpcFormat = (String) extractRPCMember( rpcStruct, RPC_FORMAT );
151 rpcProtocol = (String) extractRPCMember( rpcStruct, Constants.RPC_PROTOCOL );
152 } catch ( Exception e ) {
153 gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_INVALID_RPC_EVENT", e.getMessage() ) );
154 LOG.logError( e.getMessage() );
155 return;
156 }
157
158 // "GetRecordById"-request
159 String req = null;
160 HashMap result = null;
161 try {
162 req = createRequest( rpcStruct, rpcFormat, null );
163 } catch ( Exception e ) {
164 gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_INVALID_REQ", e.getMessage() ) );
165 LOG.logError( e.getMessage() );
166 return;
167 }
168 try {
169 List<String> dataCatalogs = new ArrayList<String>( 1 );
170 dataCatalogs.add( rpcCatalog );
171
172 // key = data catalog name; value = csw:GetRecordByIdResponse
173 result = performRequest( rpcProtocol, req, dataCatalogs );
174 // result is a HashMap that contains only one key-value-pair,
175 // because dataCatalogs contains only one catalog.
176 } catch ( Exception e ) {
177 gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_SERVER_ERROR", e.getMessage() ) );
178 LOG.logError( e.getMessage() );
179 return;
180 }
181
182 // handle result: take result and transform it to produce html output
183 try {
184 handleResult( result, pathToXslFile, "overview" );
185 } catch ( Exception e ) {
186 gotoErrorPage( Messages.getMessage( "IGEO_STD_CSW_ERROR_HANDLE_RESULT", e.getMessage() ) );
187 LOG.logError( e.getMessage() );
188 return;
189 }
190
191 }
192
193 }
194
195 /*
196 * (non-Javadoc)
197 *
198 * @see org.deegree.portal.standard.csw.control.SimpleSearchListener#validateRequest(org.deegree.enterprise.control.RPCWebEvent)
199 */
200 @Override
201 protected void validateRequest( RPCWebEvent rpcEvent )
202 throws CatalogClientException {
203
204 RPCParameter[] params = extractRPCParameters( rpcEvent );
205 if ( params.length != 1 ) {
206 throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_WRONG_PARAMS_NUMBER", "1",
207 params.length ) );
208 }
209
210 RPCStruct struct = extractRPCStruct( rpcEvent, 0 );
211
212 // validity check for catalog
213 String rpcCatalog = (String) extractRPCMember( struct, RPC_CATALOG );
214 String[] catalogs = config.getCatalogNames();
215 boolean containsCatalog = false;
216 for ( int i = 0; i < catalogs.length; i++ ) {
217 if ( catalogs[i].equals( rpcCatalog ) ) {
218 containsCatalog = true;
219 break;
220 }
221 }
222 if ( !containsCatalog ) {
223 throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_WRONG_CAT", rpcCatalog ) );
224 }
225
226 // validity check for format
227 // is requested catalog capable to serve requested metadata format?
228 List formats = config.getCatalogFormats( rpcCatalog );
229 String rpcFormat = (String) extractRPCMember( struct, RPC_FORMAT );
230 if ( !formats.contains( rpcFormat ) ) {
231 throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_WRONG_FORMAT", rpcCatalog, rpcFormat ) );
232 }
233
234 // validity check for protocol
235 // is requested catalog reachable through requested protocol?
236 List protocols = config.getCatalogProtocols( rpcCatalog );
237 String rpcProtocol = (String) extractRPCMember( struct, Constants.RPC_PROTOCOL );
238 if ( !protocols.contains( rpcProtocol ) ) {
239 throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_WRONG_PROTOCOL", rpcCatalog,
240 rpcProtocol ) );
241 }
242
243 try {
244 struct.getMember( Constants.RPC_IDENTIFIER ).getValue();
245 } catch ( Exception e ) {
246 throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_MISSING_ID" ) );
247 }
248
249 // validity check for bounding box values
250 RPCStruct bBox;
251 try {
252 bBox = (RPCStruct) struct.getMember( Constants.RPC_BBOX ).getValue();
253 } catch ( Exception e ) {
254 throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_MISSING_BBOX" ) );
255 }
256 double minx, miny, maxx, maxy;
257 try {
258 minx = ( (Double) bBox.getMember( Constants.RPC_BBOXMINX ).getValue() ).doubleValue();
259 miny = ( (Double) bBox.getMember( Constants.RPC_BBOXMINY ).getValue() ).doubleValue();
260 maxx = ( (Double) bBox.getMember( Constants.RPC_BBOXMAXX ).getValue() ).doubleValue();
261 maxy = ( (Double) bBox.getMember( Constants.RPC_BBOXMAXY ).getValue() ).doubleValue();
262 } catch ( Exception e ) {
263 throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_INVALID_BBOX_NOT_DECIMAL" ) );
264 }
265 if ( minx > maxx || miny > maxy ) {
266 throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_INVALID_BBOX_VALUES" ) );
267 }
268 }
269
270 // super.createRequest();
271
272 // super.performeRequest();
273
274 /**
275 * @param result
276 * @param pathToXslFile
277 * e.g. file://$iGeoPortal_home$/WEB-INF/conf/igeoportal/metaOverview2html.xsl
278 * @param metaVersion
279 * e.g. overview, detailed
280 * @throws XMLParsingException
281 * @throws CatalogClientException
282 * @throws TransformerException
283 * @throws IOException
284 */
285 protected void handleResult( Object result, String pathToXslFile, String metaVersion )
286 throws XMLParsingException, CatalogClientException, TransformerException, IOException {
287
288 HttpSession session = ( (HttpServletRequest) this.getRequest() ).getSession( true );
289
290 // result is a very short hashmap with only one entry!
291 Map map = (HashMap) result;
292 // key = data catalog name; value = csw:GetRecordByIdResponse
293 Iterator it = map.keySet().iterator();
294
295 String catalog = null;
296 Document doc = null;
297 String docString = null;
298
299 URL u = null;
300 StringBuffer htmlFragment = new StringBuffer( 5000 );
301 MetadataTransformer mt = null;
302 try {
303 u = new URL( pathToXslFile );
304 mt = new MetadataTransformer( u.getFile() );
305 } catch ( MalformedURLException e ) {
306 LOG.logError( e.getMessage(), e );
307 } catch ( FileNotFoundException e ) {
308 LOG.logError( e.getMessage(), e );
309 }
310
311 while ( it.hasNext() ) {
312 catalog = (String) it.next();
313 doc = (Document) map.get( catalog );
314 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
315 LOG.logDebug( "xml doc to transform:\n",
316 new XMLFragment( doc.getDocumentElement() ).getAsPrettyString() );
317 }
318 docString = DOMPrinter.nodeToString( doc, CharsetUtils.getSystemCharset() );
319 Reader reader = new StringReader( docString );
320
321 List nl = extractMetadata( doc );
322 if ( nl.size() > 1 ) {
323 throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_ERROR_TOO_MANY_NODES" ) );
324 }
325
326 String xPathToId = config.getXPathToDataIdentifier();
327 String identifier = extractValue( (Node) nl.get( 0 ), xPathToId );
328 String[] serviceCatalogs = null;
329 Map catalogsMap = (HashMap) session.getAttribute( SESSION_AVAILABLESERVICECATALOGS );
330 if ( catalogsMap != null ) {
331 serviceCatalogs = extractServiceCatalogs( catalogsMap, identifier );
332 }
333
334 // transformation
335 htmlFragment.append( mt.transformMetadata( reader, catalog, serviceCatalogs, 0, 0, metaVersion ) );
336 LOG.logDebug( "Transformed html", htmlFragment.toString() );
337 }
338
339 this.getRequest().setAttribute( HTML_FRAGMENT, htmlFragment.toString() );
340 session.setAttribute( SESSION_METADATA, result );
341 }
342
343 /**
344 * Extracts all Metadata nodes from the passed csw:GetRecordByIdResponse Document.
345 *
346 * @param doc
347 * The csw:GetRecordByIdResponse Document from which to extract the Metadata nodes.
348 * @return Returns a NodeList of Metadata Elements for the passed Document.
349 * @throws CatalogClientException
350 * if metadata nodes could not be extracted from the passed Document.
351 * @throws XMLParsingException
352 */
353 @Override
354 protected List extractMetadata( Document doc )
355 throws CatalogClientException, XMLParsingException {
356
357 List nl = null;
358
359 String xPathToMetadata = "csw202:GetRecordByIdResponse/child::*";
360
361 nl = XMLTools.getNodes( doc, xPathToMetadata, nsContext );
362
363 if ( nl == null || nl.size() < 1 ) {
364 throw new CatalogClientException( Messages.getMessage( "IGEO_STD_CSW_ERROR_EXTRACT_MD_NODES" ) );
365 }
366
367 return nl;
368 }
369
370 /**
371 * Extracts a List of available service catalogues from the Map in the session and returns its contents as an Array
372 * of Strings.
373 *
374 * @param catalogsMap
375 * The Map containing the data title (as key) and the List of available service catalogues names (as
376 * value)
377 * @param title
378 * The key for the value in the passed Map.
379 * @return Returns an Array of Strings for the available service catalogues. If no service catalogues are available,
380 * an Array of one empty String is returned.
381 */
382 protected String[] extractServiceCatalogs( Map catalogsMap, String title ) {
383
384 String[] catalogs = null;
385
386 List catalogsList = (ArrayList) catalogsMap.get( title );
387
388 if ( catalogsList != null ) {
389 catalogs = new String[catalogsList.size()];
390 for ( int i = 0; i < catalogsList.size(); i++ ) {
391 catalogs[i] = (String) catalogsList.get( i );
392 }
393 } else {
394 catalogs = new String[] { "" };
395 }
396
397 return catalogs;
398 }
399
400 }