001: /*---------------- FILE HEADER ------------------------------------------
002: This file is part of adv ebrim project.
003: Copyright (C) 2007 by:
004:
005: Andreas Poth
006: lat/lon GmbH
007: Aennchenstr. 19
008: 53177 Bonn
009: Germany
010: E-Mail: poth@lat-lon.de
011:
012: ---------------------------------------------------------------------------*/
013: package de.latlon.adv;
014:
015: import java.io.IOException;
016: import java.io.OutputStreamWriter;
017: import java.io.PrintWriter;
018: import java.net.MalformedURLException;
019: import java.net.URI;
020: import java.net.URISyntaxException;
021: import java.net.URL;
022: import java.security.InvalidParameterException;
023: import java.util.HashMap;
024: import java.util.Map;
025:
026: import javax.servlet.Filter;
027: import javax.servlet.FilterChain;
028: import javax.servlet.FilterConfig;
029: import javax.servlet.ServletException;
030: import javax.servlet.ServletRequest;
031: import javax.servlet.ServletResponse;
032: import javax.servlet.http.HttpServletRequest;
033: import javax.servlet.http.HttpServletResponse;
034:
035: import org.deegree.datatypes.QualifiedName;
036: import org.deegree.enterprise.servlet.ServletRequestWrapper;
037: import org.deegree.enterprise.servlet.ServletResponseWrapper;
038: import org.deegree.framework.log.ILogger;
039: import org.deegree.framework.log.LoggerFactory;
040: import org.deegree.framework.util.IDGenerator;
041: import org.deegree.framework.util.WebappResourceResolver;
042: import org.deegree.framework.xml.InvalidConfigurationException;
043: import org.deegree.framework.xml.XMLFragment;
044: import org.deegree.framework.xml.XMLParsingException;
045: import org.deegree.framework.xml.XMLTools;
046: import org.deegree.io.datastore.PropertyPathResolvingException;
047: import org.deegree.model.feature.Feature;
048: import org.deegree.model.feature.FeatureCollection;
049: import org.deegree.model.feature.FeatureProperty;
050: import org.deegree.model.filterencoding.ComplexFilter;
051: import org.deegree.model.filterencoding.Expression;
052: import org.deegree.model.filterencoding.Literal;
053: import org.deegree.model.filterencoding.OperationDefines;
054: import org.deegree.model.filterencoding.PropertyIsCOMPOperation;
055: import org.deegree.model.filterencoding.PropertyName;
056: import org.deegree.ogcbase.CommonNamespaces;
057: import org.deegree.ogcbase.ExceptionCode;
058: import org.deegree.ogcbase.PropertyPath;
059: import org.deegree.ogcbase.PropertyPathFactory;
060: import org.deegree.ogcwebservices.OGCRequestFactory;
061: import org.deegree.ogcwebservices.OGCWebServiceException;
062: import org.deegree.ogcwebservices.OGCWebServiceRequest;
063: import org.deegree.ogcwebservices.csw.CSWExceptionCode;
064: import org.deegree.ogcwebservices.csw.CatalogueService;
065: import org.deegree.ogcwebservices.csw.configuration.CatalogueConfiguration;
066: import org.deegree.ogcwebservices.csw.discovery.GetRepositoryItem;
067: import org.deegree.ogcwebservices.csw.manager.Manager;
068: import org.deegree.ogcwebservices.wfs.WFService;
069: import org.deegree.ogcwebservices.wfs.XMLFactory;
070: import org.deegree.ogcwebservices.wfs.operation.FeatureResult;
071: import org.deegree.ogcwebservices.wfs.operation.GetFeature;
072: import org.deegree.ogcwebservices.wfs.operation.GetFeatureDocument;
073: import org.deegree.ogcwebservices.wfs.operation.Query;
074: import org.deegree.ogcwebservices.wfs.operation.GetFeature.RESULT_TYPE;
075: import org.deegree.security.GeneralSecurityException;
076: import org.deegree.security.drm.model.User;
077: import org.w3c.dom.Document;
078: import org.w3c.dom.Element;
079: import org.xml.sax.SAXException;
080:
081: /**
082: * The <code>CSWGetRepositoryItem</code> class, is a servlet filter, which can handle incoming GetRepositoryItem
083: * requests (defined tobe a Http-GET request). This filter directly talks to the wfs-backend of the csw and requests for
084: * a given rim:ExtrinsicObject it's app:RegistryObject/app:extrinsicObject/app:ExtrinsicObject/app:object. The value
085: * returned from the localwfs is then send (according to the mimetype) back to the requester.
086: *
087: * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
088: *
089: * @author last edited by: $Author: bezema $
090: *
091: * @version $Revision: 1.6 $, $Date: 2007-06-21 13:53:15 $
092: *
093: */
094:
095: public class CSWGetRepositoryItemFilter implements Filter {
096:
097: private static ILogger LOG = LoggerFactory
098: .getLogger(CSWGetRepositoryItemFilter.class);
099:
100: private WFService localWFS = null;
101:
102: private URI appURI;
103:
104: private OWSProxyHandler proxyHandler = null;
105:
106: /**
107: * Inits this filter, it reads the configuration file (given by the <filter-param> 'csw.config' and with it
108: * constructs a transaction manager. This manager can deliver a localwfs, to which this filter will do a direct
109: * communication.
110: */
111: public void init(FilterConfig config) throws ServletException {
112: String configLocation = config.getInitParameter("csw.config");
113: try {
114: URL configURL = WebappResourceResolver.resolveFileLocation(
115: configLocation, config.getServletContext(), LOG);
116: CatalogueConfiguration cswConfig = CatalogueConfiguration
117: .createConfiguration(configURL);
118: CatalogueService cswService = CatalogueService
119: .create(cswConfig);
120: Manager transactionManager = cswService.getManager();
121: if (transactionManager.getWfsService() == null) {
122: LOG
123: .logError("The GetRepositoryItemFilter has no access to the localWFS");
124: } else {
125: localWFS = transactionManager.getWfsService();
126: }
127:
128: } catch (MalformedURLException e) {
129: LOG.logError("Could not initiate GetRepositoryItemFilter: "
130: + e.getMessage());
131: } catch (IOException e) {
132: LOG.logError("Could not initiate GetRepositoryItemFilter: "
133: + e.getMessage());
134: } catch (SAXException e) {
135: LOG.logError("Could not initiate GetRepositoryItemFilter: "
136: + e.getMessage());
137: } catch (InvalidConfigurationException e) {
138: LOG.logError("Could not initiate GetRepositoryItemFilter: "
139: + e.getMessage());
140: } catch (OGCWebServiceException e) {
141: LOG.logError("Could not initiate GetRepositoryItemFilter: "
142: + e.getMessage());
143: }
144: if (localWFS != null) {
145: try {
146: appURI = new URI("http://www.deegree.org/app");
147: proxyHandler = new OWSProxyHandler(config);
148: } catch (URISyntaxException e) {
149: // This never happens but whatever
150: } catch (InvalidParameterException ipe) {
151: LOG
152: .logInfo("CSW (Ebrim) GetRepositoryItem Servlet Filter: couldn't create an OWSProxyHandler, so no user authentification available, because: "
153: + ipe.getMessage());
154: }
155: LOG
156: .logInfo("CSW (Ebrim) GetRepositoryItem Servlet Filter: successfully initialized");
157: } else {
158: LOG
159: .logInfo("CSW (Ebrim) GetRepositoryItem Servlet Filter: was not initialized");
160: }
161: }
162:
163: public void destroy() {
164: // nottin to do
165: }
166:
167: /**
168: * The actual doFilter method, will check if the incoming request is a wrs:GetRepositoryItem request (by checking
169: * the service parameter of the httpGet request.
170: */
171: public void doFilter(ServletRequest request,
172: ServletResponse response, FilterChain chain)
173: throws IOException, ServletException {
174: if (localWFS == null) {
175: LOG
176: .logInfo("CSW (Ebrim) GetRepositoryItem-Filter: Local Catalogue service is not instantiated, therefore the CSW-GetRepositoryItem filter can not be used");
177: // chain.doFilter( request, response );
178: sendException(
179: response,
180: new OGCWebServiceException(
181: "The backend is not configured so not accepting any requests.",
182: CSWExceptionCode.WRS_NOTIMPLEMENTED));
183: return;
184: }
185: Map<String, String[]> parameters = request.getParameterMap();
186: if (parameters.size() != 0) {
187: Map<String, String> params = new HashMap<String, String>();
188: for (String key : parameters.keySet()) {
189: String[] tmp = parameters.get(key);
190: for (int i = 0; i < tmp.length; i++) {
191: tmp[i] = tmp[i].trim();
192: LOG.logDebug("for key: " + key + " found param: "
193: + tmp[i]);
194: }
195: //params.put( key.toUpperCase(), StringTools.arrayToString( tmp, ',' ) );
196: if (tmp.length > 0) {
197: params.put(key.toUpperCase(), tmp[0]);
198: }
199: }
200: String service = params.get("SERVICE");
201: if (service == null) {
202: // a profile of a service will be treated as a service
203: service = params.get("PROFILE");
204: if (service == null) {
205: sendException(
206: response,
207: new OGCWebServiceException(
208: "The SERVICE or PROFILE keyword isn't set.",
209: CSWExceptionCode.WRS_INVALIDREQUEST));
210: //chain.doFilter( request, response );
211: return;
212: }
213: }
214:
215: ServletRequestWrapper requestWrapper = null;
216: if (request instanceof ServletRequestWrapper) {
217: LOG
218: .logDebug("the incoming request is actually an org.deegree.enterprise.servlet.RequestWrapper, so not creating new instance.");
219: requestWrapper = (ServletRequestWrapper) request;
220: } else {
221: requestWrapper = new ServletRequestWrapper(
222: (HttpServletRequest) request);
223: }
224:
225: OGCWebServiceRequest owsProxyRequest = null;
226: User user = null;
227: //put them to uppercase *sigh*
228: String userName = params.get("USER");
229: String password = params.get("PASSWORD");
230:
231: if (this .proxyHandler != null) {
232: try {
233: LOG
234: .logDebug("trying to get authentication for user: "
235: + userName
236: + " with password: "
237: + password);
238: user = proxyHandler.authentificateFromUserPw(
239: userName, password);
240: owsProxyRequest = proxyHandler
241: .createOWSRequest(requestWrapper);
242: authorizeRequest(user, owsProxyRequest,
243: requestWrapper);
244: } catch (GeneralSecurityException e) {
245: LOG
246: .logDebug("User: "
247: + userName
248: + " with password: "
249: + password
250: + " couldn't get authentification because: "
251: + e.getMessage());
252: sendException(response, new OGCWebServiceException(
253: e.getMessage(),
254: CSWExceptionCode.WRS_INVALIDREQUEST));
255: return;
256: } catch (OGCWebServiceException e) {
257: sendException(response, e);
258: return;
259: }
260: } else {
261: LOG
262: .logDebug("CSW (Ebrim) Insert-Filter: the proxyHandler is not defined so no user Authentification.");
263: sendException(
264: response,
265: new OGCWebServiceException(
266: "The proxyHandler is not defined so not accepting any requests.",
267: CSWExceptionCode.WRS_NOTIMPLEMENTED));
268: return;
269: }
270: if (!OGCRequestFactory.CSW_SERVICE_NAME_EBRIM
271: .equals(service)) {
272: //sendException( response, new OGCWebServiceException( "This service only supplies ", CSWExceptionCode.WRS_INVALIDREQUEST ) );
273: chain.doFilter(request, response);
274: return;
275: }
276: LOG
277: .logDebug("The CSWGetRepositoryItemFilter is handling the request with following parameters: "
278: + params);
279: String id = Long.toString(IDGenerator.getInstance()
280: .generateUniqueID());
281: params.put("REQUESTID", id);
282: GetRepositoryItem getReposItem = null;
283: try {
284: getReposItem = GetRepositoryItem.create(params);
285: handleGetRepositoryItem(response, getReposItem, user);
286: } catch (OGCWebServiceException e) {
287: sendException(response, e);
288: return;
289: }
290: }
291: if (!response.isCommitted()) {
292: chain.doFilter(request, response);
293: }
294: }
295:
296: private void authorizeRequest(User user,
297: OGCWebServiceRequest owsProxyRequest,
298: ServletRequestWrapper requestWrapper)
299: throws OGCWebServiceException {
300: // checking the authorization of the user.
301: if (this .proxyHandler != null) {
302: try {
303: // owsProxyRequest = proxyHandler.createOWSRequest( requestWrapper );
304: proxyHandler.doRequestValidation(requestWrapper, user,
305: owsProxyRequest);
306: } catch (GeneralSecurityException e) {
307: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
308: Thread.dumpStack();
309: }
310: String userName = null;
311: String password = null;
312: if (user != null) {
313: userName = user.getName();
314: password = user.getPassword();
315: }
316: LOG.logDebug("User: " + userName + " with password: "
317: + password
318: + " couldn't get authentification because: "
319: + e.getMessage());
320: throw new OGCWebServiceException(e.getMessage(),
321: CSWExceptionCode.WRS_INVALIDREQUEST);
322: }
323: }
324: }
325:
326: private void authorizeResponse(User user,
327: OGCWebServiceRequest owsProxyRequest,
328: ServletResponseWrapper responseWrapper)
329: throws OGCWebServiceException {
330: // checking the authorization of the user.
331: if (this .proxyHandler != null) {
332: try {
333: proxyHandler.doResponseValidation(responseWrapper,
334: user, owsProxyRequest);
335: } catch (GeneralSecurityException e) {
336: String userName = null;
337: String password = null;
338: if (user != null) {
339: userName = user.getName();
340: userName = user.getPassword();
341: }
342: LOG.logDebug("User: " + userName + " with password: "
343: + password
344: + " couldn't get authentification because: "
345: + e.getMessage());
346: throw new OGCWebServiceException(e.getMessage(),
347: CSWExceptionCode.WRS_INVALIDREQUEST);
348: } catch (IOException e) {
349: LOG
350: .logDebug("couldn't get an outputstream for the response because: "
351: + e.getMessage());
352: throw new OGCWebServiceException(e.getMessage(),
353: CSWExceptionCode.WRS_INVALIDREQUEST);
354: }
355: }
356: }
357:
358: /**
359: * Contacts the localWFS to find a rim:ExtrinsicObject which contains the
360: * {@link GetRepositoryItem#getRepositoryItemID()} and retrieves it's
361: * app:RegistryObject/app:extrinsicObject/app:ExtrinsicObject/app:object. The value in this property will then be
362: * written to the response stream (e.g. sent to the requester).
363: *
364: * @param response
365: * the response object to which the data will be returned
366: * @param reposItem
367: * the created OGCRequest
368: * @throws IOException
369: * if the stream cannot be retrieved from the resonse
370: * @throws OGCWebServiceException
371: * if something went wrong while processing the request.
372: */
373: private void handleGetRepositoryItem(ServletResponse response,
374: GetRepositoryItem reposItem, User user) throws IOException,
375: OGCWebServiceException {
376: // Some properterypaths which are used for the creation of a complex filter.
377: QualifiedName registryObject = new QualifiedName("app",
378: "RegistryObject", appURI);
379: Expression iduriExpr = new PropertyName(new QualifiedName(
380: "app", "iduri", appURI));
381: Expression idLiteral = new Literal(reposItem
382: .getRepositoryItemID().toString());
383: PropertyIsCOMPOperation idOperator = new PropertyIsCOMPOperation(
384: OperationDefines.PROPERTYISEQUALTO, iduriExpr,
385: idLiteral);
386: ComplexFilter idFilter = new ComplexFilter(idOperator);
387:
388: FeatureCollection featureCollectionOnId = null;
389: try {
390: FeatureResult fr = sendWFSGetFeature(registryObject,
391: idFilter);
392: if (fr != null) {
393: featureCollectionOnId = (FeatureCollection) fr
394: .getResponse();
395: }
396: } catch (OGCWebServiceException e) {
397: throw new OGCWebServiceException("The requested item "
398: + reposItem.getRepositoryItemID()
399: + " could not be retrieved from the csw backend: "
400: + e.getMessage(), CSWExceptionCode.WRS_NOTFOUND);
401: }
402: String numbOfFeatures = featureCollectionOnId
403: .getAttribute("numberOfFeatures");
404: int featureCount = 0;
405: try {
406: featureCount = Integer.parseInt(numbOfFeatures);
407: LOG
408: .logDebug("the number of features in the GetFeature was: "
409: + featureCount);
410: } catch (NumberFormatException nfe) {
411: // nottin
412: }
413: // Check the number of hits we've found, if the id allready exists it means we want to set the status of the
414: // object to invalid.
415: // String newID = id;
416: if (featureCount > 1) {
417: throw new OGCWebServiceException(
418: "The id : "
419: + reposItem.getRepositoryItemID()
420: + " is not unique. This repositoryItem can therefore not be retrieved.",
421: CSWExceptionCode.WRS_NOTFOUND);
422: } else if (featureCount == 0) {
423: throw new OGCWebServiceException(
424: "The id: "
425: + reposItem.getRepositoryItemID()
426: + " corresponds to no rim:ExtrinsicObject. This repositoryItem can therefore not be retrieved.",
427: CSWExceptionCode.WRS_NOTFOUND);
428:
429: } else {
430: Feature f = featureCollectionOnId.getFeature(0);
431: if (f != null) {
432: PropertyPath pp = PropertyPathFactory
433: .createPropertyPath(registryObject);
434: pp.append(PropertyPathFactory
435: .createPropertyPathStep(new QualifiedName(
436: "app", "extrinsicObject", appURI)));
437: pp.append(PropertyPathFactory
438: .createPropertyPathStep(new QualifiedName(
439: "app", "ExtrinsicObject", appURI)));
440: pp.append(PropertyPathFactory
441: .createPropertyPathStep(new QualifiedName(
442: "app", "object", appURI)));
443: FeatureProperty retrievedObject = null;
444: try {
445: retrievedObject = f.getDefaultProperty(pp);
446: } catch (PropertyPathResolvingException ppre) {
447: throw new OGCWebServiceException(
448: "The id: "
449: + reposItem.getRepositoryItemID()
450: + " has no repository item stored, there is nothing to be retrieved.",
451: CSWExceptionCode.WRS_NOTFOUND);
452:
453: }
454: if (retrievedObject == null
455: || retrievedObject.getValue() == null) {
456: throw new OGCWebServiceException(
457: "The id: "
458: + reposItem.getRepositoryItemID()
459: + " has no repository item stored, there is nothing to be retrieved.",
460: CSWExceptionCode.WRS_NOTFOUND);
461: }
462:
463: String repositoryItem = (String) retrievedObject
464: .getValue();
465: LOG.logDebug("found the repositoryItem: "
466: + repositoryItem);
467:
468: pp = PropertyPathFactory
469: .createPropertyPath(registryObject);
470: pp.append(PropertyPathFactory
471: .createPropertyPathStep(new QualifiedName(
472: "app", "extrinsicObject", appURI)));
473: pp.append(PropertyPathFactory
474: .createPropertyPathStep(new QualifiedName(
475: "app", "ExtrinsicObject", appURI)));
476: pp.append(PropertyPathFactory
477: .createPropertyPathStep(new QualifiedName(
478: "app", "mimeType", appURI)));
479: FeatureProperty mimeType = null;
480: try {
481: mimeType = f.getDefaultProperty(pp);
482: } catch (PropertyPathResolvingException ppre) {
483: LOG
484: .logError("The mimetype value (of the GetRepositoryItem: "
485: + reposItem.getRepositoryItemID()
486: + ") was not set, setting content header to 'application/xml' ");
487: }
488: if (mimeType == null || mimeType.getValue() == null) {
489: LOG
490: .logError("The mimetype value (of the GetRepositoryItem: "
491: + reposItem.getRepositoryItemID()
492: + ") was not set, setting content header to 'application/xml' ");
493: } else {
494: response.setContentType((String) mimeType
495: .getValue());
496: }
497: ServletResponseWrapper wrapper = new ServletResponseWrapper(
498: (HttpServletResponse) response);
499: authorizeResponse(user, reposItem, wrapper);
500: PrintWriter writer = new PrintWriter(
501: new OutputStreamWriter(response
502: .getOutputStream()));
503: writer.write(repositoryItem);
504: writer.flush();
505: writer.close();
506: }
507: }
508:
509: }
510:
511: /**
512: * Generates and sends a GetFeature to the localwfs (which was instantiated in the init method).
513: *
514: * @param registryObject
515: * the QName of the registryObject e.g. app:RegistryObject (xmlns:app="http://www.deegree.org/app")
516: * @param filter
517: * a ogc:Filter representation containing the (app:iduri isequal requestID) mapping.
518: * @return the FeatureResult of the given filter or <code>null</code> if something went wrong.
519: * @throws OGCWebServiceException
520: * thrown if the localWFS encounters any problems
521: */
522: private FeatureResult sendWFSGetFeature(
523: QualifiedName registryObject, ComplexFilter filter)
524: throws OGCWebServiceException {
525: Query q = Query.create(registryObject, filter);
526: GetFeature gfwl = GetFeature.create("1.1.0", "0",
527: RESULT_TYPE.RESULTS, "text/xml; subtype=gml/3.1.1",
528: "no_handle", -1, 0, -1, -1, new Query[] { q });
529: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
530: try {
531: GetFeatureDocument gd = XMLFactory.export(gfwl);
532: LOG.logDebug(" The getFeature:\n"
533: + gd.getAsPrettyString());
534: } catch (IOException e) {
535: LOG
536: .logError("CSW (Ebrim) GetRepositoryItem-Filter: An error occurred while trying to get a debugging output for the generated GetFeatureDocument: "
537: + e.getMessage());
538: } catch (XMLParsingException e) {
539: LOG
540: .logError("CSW (Ebrim) GetRepositoryItem-Filter: An error occurred while trying to get a debugging output for the generated GetFeatureDocument: "
541: + e.getMessage());
542: }
543: }
544:
545: Object response = localWFS.doService(gfwl);
546: if (response instanceof FeatureResult) {
547: return (FeatureResult) response;
548: }
549: LOG
550: .logDebug(" got no valid response from the localwfs, returning null");
551: return null;
552: }
553:
554: /**
555: * Sends the passed <tt>OGCWebServiceException</tt> to the calling client and flushes/closes the writer.
556: *
557: * @param responseWriter
558: * to write the message of the exception to
559: * @param e
560: * the exception to 'send' e.g. write to the stream.
561: * @throws IOException
562: * if a writer could not be created from the response.
563: */
564: private void sendException(ServletResponse response,
565: OGCWebServiceException e) throws IOException {
566: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
567: Thread.dumpStack();
568: }
569: response.setContentType("application/xml");
570: LOG
571: .logDebug("Sending OGCWebServiceException to client with message: "
572: + e.getMessage());
573: Document doc = XMLTools.create();
574:
575: XMLFragment frag = new XMLFragment(doc.createElementNS(
576: CommonNamespaces.OWSNS.toString(),
577: "ows:ExceptionReport"));
578: Element message = null;
579: ExceptionCode code = e.getCode();
580: if (code == null) {
581: code = CSWExceptionCode.WRS_INVALIDREQUEST;
582: }
583: if (code == CSWExceptionCode.WRS_INVALIDREQUEST) {
584: message = XMLTools.appendElement(frag.getRootElement(),
585: CommonNamespaces.WRS_EBRIMNS, code.value);
586: } else {
587: message = XMLTools.appendElement(frag.getRootElement(),
588: CommonNamespaces.WRS_EBRIMNS,
589: CSWExceptionCode.WRS_NOTFOUND.value);
590: }
591: XMLTools.setNodeValue(message, e.getMessage());
592: PrintWriter writer = response.getWriter();
593: writer.write(frag.getAsPrettyString());
594: writer.flush();
595: writer.close();
596: }
597:
598: }
|