001 //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/portal/owswatch/validator/AbstractValidator.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.owswatch.validator;
038
039 import java.io.BufferedReader;
040 import java.io.ByteArrayInputStream;
041 import java.io.ByteArrayOutputStream;
042 import java.io.IOException;
043 import java.io.InputStream;
044 import java.io.InputStreamReader;
045
046 import javax.servlet.http.HttpServletResponse;
047 import javax.xml.parsers.DocumentBuilder;
048 import javax.xml.parsers.DocumentBuilderFactory;
049 import javax.xml.parsers.ParserConfigurationException;
050
051 import org.apache.commons.httpclient.HttpMethodBase;
052 import org.deegree.framework.log.ILogger;
053 import org.deegree.framework.log.LoggerFactory;
054 import org.deegree.framework.util.StringTools;
055 import org.deegree.framework.xml.XMLParsingException;
056 import org.deegree.framework.xml.XMLTools;
057 import org.w3c.dom.Document;
058
059 import org.deegree.portal.owswatch.Status;
060 import org.deegree.portal.owswatch.ValidatorResponse;
061
062 /**
063 * Abstract class implementing the method validate.
064 *
065 * @author <a href="mailto:elmasry@lat-lon.de">Moataz Elmasry</a>
066 * @author last edited by: $Author: jmays $
067 *
068 * @version $Revision: 20271 $, $Date: 2009-10-21 13:07:15 +0200 (Mi, 21. Okt 2009) $
069 */
070 public abstract class AbstractValidator implements Validator {
071
072 private static final ILogger LOG = LoggerFactory.getLogger( AbstractValidator.class );
073
074 /*
075 * (non-Javadoc)
076 *
077 * @see org.deegree.portal.owswatch.validator.Validator#validateAnswer(org.apache.commons.httpclient.HttpMethodBase, int,
078 * int)
079 */
080 public ValidatorResponse validateAnswer( HttpMethodBase method, int statusCode ) {
081 if ( isValidHttpResponse( statusCode ) ) {
082 return validateXml( method );
083 } else {
084 return validateErrorHttpResponse( statusCode );
085 }
086 }
087
088 /**
089 * Validates the HttpMethodBase and checks if the execution was successful or not
090 *
091 * @param method
092 * the httpmethod after executing it
093 * @return an instance of ValidatorResponse with the necessary information after validation
094 */
095 protected ValidatorResponse validateXml( HttpMethodBase method ) {
096
097 String lastMessage = null;
098 Status status = null;
099
100 String contentType = method.getResponseHeader( "Content-Type" ).getValue();
101 if ( !contentType.contains( "xml" ) ) {
102 status = Status.RESULT_STATE_UNEXPECTED_CONTENT;
103 lastMessage = StringTools.concat( 100, "Error: Response Content is ", contentType, " not xml" );
104 return new ValidatorResponse( lastMessage, status );
105 }
106
107 String xml = null;
108 try {
109 InputStream stream = copyStream( method.getResponseBodyAsStream() );
110 stream.reset();
111 xml = parseStream( stream );
112 } catch ( IOException e ) {
113 status = Status.RESULT_STATE_BAD_RESPONSE;
114 lastMessage = status.getStatusMessage();
115 return new ValidatorResponse( lastMessage, status );
116 }
117
118 if ( xml.length() == 0 ) {
119 status = Status.RESULT_STATE_BAD_RESPONSE;
120 lastMessage = "Error: XML Response is empty";
121 return new ValidatorResponse( lastMessage, status );
122 }
123 if ( xml.contains( "ServiceException" ) ) {
124 return validateXmlServiceException( method );
125 }
126 // If its an xml, and there's no service exception, then don't really parse the xml,
127 // we assume that its well formed, since there might be huge xmls, which would take time to be parsed
128 status = Status.RESULT_STATE_AVAILABLE;
129 lastMessage = status.getStatusMessage();
130 return new ValidatorResponse( lastMessage, status );
131 }
132
133 /**
134 * This method is called To read the ServiceExceptionReport from the xml file
135 *
136 * @param method
137 * the httpmethod after executing it
138 * @return an instance of ValidatorResponse with the necessary information after validation
139 */
140 protected ValidatorResponse validateXmlServiceException( HttpMethodBase method ) {
141
142 Document doc = null;
143 String lastMessage = null;
144 Status status = null;
145 try {
146 InputStream stream = method.getResponseBodyAsStream();
147 stream.reset();
148 doc = instantiateParser().parse( stream );
149 } catch ( Exception e ) {
150 status = Status.RESULT_STATE_INVALID_XML;
151 lastMessage = "Error: MalFormed XML Response";
152 return new ValidatorResponse( lastMessage, status );
153 }
154 try {
155 status = Status.RESULT_STATE_SERVICE_UNAVAILABLE;
156 lastMessage = XMLTools.getNodeAsString( doc.getDocumentElement(), "./ServiceException", null,
157 "Service Unavailable. Unknown error" );
158 return new ValidatorResponse( lastMessage, status );
159 } catch ( XMLParsingException e ) {
160 status = Status.RESULT_STATE_SERVICE_UNAVAILABLE;
161 lastMessage = status.getStatusMessage();
162 return new ValidatorResponse( lastMessage, status );
163 }
164 }
165
166 /**
167 * Makes sure that the HttpResponse is not a critical error
168 *
169 * @param statusCode
170 */
171 protected boolean isValidHttpResponse( int statusCode ) {
172
173 if ( statusCode >= 100 && statusCode < 400 ) {
174 return true;
175 }
176 return false;
177 }
178
179 /**
180 * @param statusCode
181 * @return instance of the validatorresponse with the error
182 */
183 protected ValidatorResponse validateErrorHttpResponse( int statusCode ) {
184
185 String lastMessage = null;
186 Status status = null;
187
188 if ( statusCode == HttpServletResponse.SC_REQUEST_TIMEOUT ) {
189 status = Status.RESULT_STATE_TIMEOUT;
190 lastMessage = status.getStatusMessage();
191 } else {
192 status = Status.RESULT_STATE_PAGE_UNAVAILABLE;
193 lastMessage = status.getStatusMessage();
194 }
195
196 return new ValidatorResponse( lastMessage, status );
197 }
198
199 /**
200 * Parses a given InputStream to a String
201 *
202 * @param stream
203 * @return String
204 * @throws IOException
205 */
206 protected String parseStream( InputStream stream )
207 throws IOException {
208 stream.reset();
209 InputStreamReader reader = new InputStreamReader( stream );
210 BufferedReader bufReader = new BufferedReader( reader );
211 StringBuilder builder = new StringBuilder();
212 String line = null;
213
214 line = bufReader.readLine();
215 while ( line != null ) {
216 builder.append( line );
217 line = bufReader.readLine();
218 }
219
220 String answer = builder.toString();
221 return answer;
222 }
223
224 /**
225 * Creates a new instance of DocumentBuilder
226 *
227 * @return DocumentBuilder
228 * @throws IOException
229 */
230 protected DocumentBuilder instantiateParser()
231 throws IOException {
232
233 DocumentBuilder parser = null;
234
235 try {
236 DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance();
237 fac.setNamespaceAware( true );
238 fac.setValidating( false );
239 fac.setIgnoringElementContentWhitespace( false );
240 parser = fac.newDocumentBuilder();
241 return parser;
242 } catch ( ParserConfigurationException e ) {
243 throw new IOException( "Unable to initialize DocumentBuilder: " + e.getMessage() );
244 }
245 }
246
247 protected boolean closeStream( InputStream stream ) {
248 try {
249 stream.close();
250 } catch ( IOException e ) {
251 LOG.logError( e.getLocalizedMessage() );
252 return false;
253 }
254 return true;
255 }
256
257 /**
258 * Creates a new copy of the given InputStream
259 *
260 * @param stream
261 * @return InputStream
262 * @throws IOException
263 */
264 protected InputStream copyStream( InputStream stream )
265 throws IOException {
266 ByteArrayOutputStream out = new ByteArrayOutputStream();
267 int read;
268 byte[] bs = new byte[16384];
269 while ( ( read = stream.read( bs ) ) != -1 ) {
270 out.write( bs, 0, read );
271 }
272 return new ByteArrayInputStream( out.toByteArray() );
273 }
274 }