001    //$HeadURL: http://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/enterprise/servlet/ServletRequestWrapper.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.enterprise.servlet;
038    
039    import static java.net.URLDecoder.decode;
040    
041    import java.io.BufferedInputStream;
042    import java.io.BufferedReader;
043    import java.io.ByteArrayInputStream;
044    import java.io.ByteArrayOutputStream;
045    import java.io.IOException;
046    import java.io.InputStream;
047    import java.io.InputStreamReader;
048    import java.io.UnsupportedEncodingException;
049    import java.security.Principal;
050    import java.util.HashMap;
051    import java.util.Iterator;
052    import java.util.Map;
053    import java.util.ResourceBundle;
054    
055    import javax.servlet.ServletInputStream;
056    import javax.servlet.http.HttpServletRequest;
057    import javax.servlet.http.HttpServletRequestWrapper;
058    
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.util.StringTools;
063    
064    /**
065     * TODO describe function and usage of the class here.
066     * 
067     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
068     * @author last edited by: $Author: mays$
069     * 
070     * @version $Revision: 31357 $, $Date: 23.05.2007 18:09:52$
071     */
072    public class ServletRequestWrapper extends HttpServletRequestWrapper {
073    
074        private static ILogger LOG = LoggerFactory.getLogger( ServletRequestWrapper.class );
075    
076        private static final String BUNDLE_NAME = "org.deegree.enterprise.servlet.ServletRequestWrapper";
077    
078        /**
079         * The resource to load the users from.
080         */
081        static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle( BUNDLE_NAME );
082    
083        private HttpServletRequest origReq = null;
084    
085        private byte[] bytes = null;
086    
087        private Map<String, String[]> paramMap;
088    
089        private String queryString;
090    
091        private String method;
092    
093        /**
094         * @param request
095         */
096        public ServletRequestWrapper( HttpServletRequest request ) {
097            super( request );
098    
099            this.origReq = request;
100            this.method = request.getMethod();
101    
102            ByteArrayOutputStream bos = new ByteArrayOutputStream( 10000 );
103            try {
104                InputStream is = origReq.getInputStream();
105                int c = 0;
106                while ( ( c = is.read() ) > -1 ) {
107                    bos.write( c );
108                }
109                bytes = bos.toByteArray();
110                LOG.logDebug( "The constructor created a new bytearray in the HttpServletRequestWrapper" );
111            } catch ( IOException ioe ) {
112                LOG.logError( "An error occured while creating a byte-buffered inputstream from the HttpServletRequest "
113                              + "inputstream because: " + ioe.getMessage(), ioe );
114                bytes = null;
115            }
116            queryString = request.getQueryString();
117            // init parameter map
118            getParameterMap();
119        }
120    
121        @SuppressWarnings("unchecked")
122        public void reinitParameterMap() {
123            paramMap = new HashMap<String, String[]>();
124    
125            // encoding heuristics for URL encoding
126            // if %c3 is found (a sign of UTF-8 encoding) parse it manually, setting the encoding right
127            if ( queryString != null && queryString.toLowerCase().indexOf( "%c3" ) != -1 ) {
128                try {
129                    for ( String kv : queryString.split( "&" ) ) {
130                        String[] pair = kv.split( "=", 2 );
131                        if ( pair.length == 2 ) {
132                            paramMap.put( decode( pair[0], "UTF-8" ), decode( pair[1], "UTF-8" ).split( "," ) );
133                        }
134                    }
135                } catch ( UnsupportedEncodingException e ) {
136                    LOG.logError( "Unknown error", e );
137                }
138            } else {
139                paramMap = super.getParameterMap();
140            }
141        }
142    
143        @Override
144        public Map<String, String[]> getParameterMap() {
145            if ( paramMap == null ) {
146                reinitParameterMap();
147            }
148            return paramMap;
149        }
150    
151        @Override
152        public String getParameter( String key ) {
153            if ( paramMap == null ) {
154                paramMap = getParameterMap();
155            }
156            String[] o = paramMap.get( key );
157            String tmp = null;
158            if ( o != null ) {
159                tmp = StringTools.arrayToString( o, ',' );
160            }
161            return tmp;
162        }
163    
164        @Override
165        public String[] getParameterValues( String arg0 ) {
166            if ( paramMap == null ) {
167                paramMap = getParameterMap();
168            }
169            return paramMap.get( arg0 );
170        }
171    
172        /**
173         * 
174         * @param param
175         */
176        public void setParameter( Map<String, String> param ) {
177            this.paramMap = new HashMap<String, String[]>( param.size() );
178    
179            Iterator<String> iter = param.keySet().iterator();
180            StringBuffer sb = new StringBuffer( 500 );
181            while ( iter.hasNext() ) {
182                String key = iter.next();
183                String value = param.get( key );
184                sb.append( key ).append( '=' ).append( value );
185                if ( iter.hasNext() ) {
186                    sb.append( '&' );
187                }
188                this.paramMap.put( key, StringTools.toArray( value, ",", false ) );
189            }
190            this.queryString = sb.toString();
191        }
192    
193        @Override
194        public String getQueryString() {
195            return queryString;
196        }
197    
198        /**
199         * marks an instance of a {@link #ServletRequestWrapper(HttpServletRequest)} as using HTTP POST. This method just
200         * should be invoked if a request body as an @see {@link InputStream} (byte array) is available
201         */
202        public void markAsPostRequest() {
203            method = "POST";
204            if ( bytes == null || bytes.length == 0 ) {
205                LOG.logWarning( "no request body as an InputStream (byte array) is available" );
206            }
207            // a post request shall not have a parameter string
208            this.queryString = null;
209            this.paramMap = new HashMap<String, String[]>();
210        }
211    
212        @Override
213        public String getMethod() {
214            return method;
215        }
216    
217        /**
218         * sets the content of the @see {@link InputStream} returned by the
219         * 
220         * @see #getReader() and the
221         * @see #getInputStream() method as a byte array. Calling this method will override the content that may has been
222         *      read from the <code>HttpServletRequest</code> that has been passed to the constructor
223         * 
224         * @param b
225         */
226        public void setInputStreamAsByteArray( byte[] b ) {
227            LOG.logDebug( "ServletRequestWrapper: setting inputstream#byteArray to given byte array" );
228            this.bytes = b;
229            markAsPostRequest();
230        }
231    
232        @Override
233        public BufferedReader getReader()
234                                throws IOException {
235            return new BufferedReader( new InputStreamReader( getInputStream(), CharsetUtils.getSystemCharset() ) );
236        }
237    
238        /**
239         * @see javax.servlet.ServletRequest#getInputStream()
240         */
241        @Override
242        public ServletInputStream getInputStream()
243                                throws IOException {
244            if ( bytes == null ) {
245                LOG.logDebug( "Creating new bytearray in the HttpServletRequestWrapper#getInputStream" );
246                ByteArrayOutputStream bos = new ByteArrayOutputStream( 10000 );
247                InputStream is = origReq.getInputStream();
248                int c = 0;
249                while ( ( c = is.read() ) > -1 ) {
250                    bos.write( c );
251                }
252                bytes = bos.toByteArray();
253            }
254    
255            return new ProxyServletInputStream( new ByteArrayInputStream( bytes ), bytes.length );
256        }
257    
258        @Override
259        public Principal getUserPrincipal() {
260            if ( origReq.getUserPrincipal() != null ) {
261                return origReq.getUserPrincipal();
262            }
263            return new Principal() {
264                public String getName() {
265                    return RESOURCE_BUNDLE.getString( "defaultuser" );
266                }
267            };
268    
269        }
270    
271        // ///////////////////////////////////////////////////////////////////////
272        // inner classes //
273        // ///////////////////////////////////////////////////////////////////////
274    
275        /**
276         * @author Administrator
277         * 
278         *         TODO To change the template for this generated type comment go to Window - Preferences - Java - Code
279         *         Style - Code Templates
280         */
281        private class ProxyServletInputStream extends ServletInputStream {
282    
283            private BufferedInputStream buffered;
284    
285            /**
286             * @param in
287             *            the InputStream which will be buffered.
288             * @param length
289             */
290            public ProxyServletInputStream( InputStream in, int length ) {
291                if ( length > 0 )
292                    buffered = new BufferedInputStream( in, length );
293                else
294                    buffered = new BufferedInputStream( in );
295            }
296    
297            @Override
298            public synchronized int read()
299                                    throws IOException {
300                return buffered.read();
301            }
302    
303            @Override
304            public synchronized int read( byte b[], int off, int len )
305                                    throws IOException {
306                return buffered.read( b, off, len );
307            }
308    
309            @Override
310            public synchronized long skip( long n )
311                                    throws IOException {
312                return buffered.skip( n );
313            }
314    
315            @Override
316            public synchronized int available()
317                                    throws IOException {
318                return buffered.available();
319            }
320    
321            @Override
322            public synchronized void mark( int readlimit ) {
323                buffered.mark( readlimit );
324            }
325    
326            @Override
327            public synchronized void reset()
328                                    throws IOException {
329                buffered.reset();
330            }
331    
332            @Override
333            public boolean markSupported() {
334                return buffered.markSupported();
335            }
336    
337            @Override
338            public void close()
339                                    throws IOException {
340                buffered.close();
341            }
342        }
343    
344    }