001 /*
002 * Copyright 1996-2005 Mort Bay Consulting Pty. Ltd.
003 * Copyright 2006 Stephen McConnell.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package net.dpml.test.http;
019
020 import java.io.IOException;
021 import java.io.OutputStream;
022 import java.io.PrintWriter;
023 import java.lang.reflect.Field;
024 import java.util.Enumeration;
025 import java.util.Locale;
026
027 import javax.servlet.ServletConfig;
028 import javax.servlet.ServletException;
029 import javax.servlet.ServletRequest;
030 import javax.servlet.ServletRequestWrapper;
031 import javax.servlet.UnavailableException;
032 import javax.servlet.http.Cookie;
033 import javax.servlet.http.HttpServlet;
034 import javax.servlet.http.HttpServletRequest;
035 import javax.servlet.http.HttpServletRequestWrapper;
036 import javax.servlet.http.HttpServletResponse;
037
038 /**
039 * Dump Servlet Request.
040 */
041 public class Dump extends HttpServlet
042 {
043 /**
044 * Servlet initialization.
045 * @param config the servlet configuration
046 * @exception ServletException if a configuration error occurs
047 */
048 public void init( ServletConfig config ) throws ServletException
049 {
050 super.init( config );
051 }
052
053 /**
054 * Process an incomming post request.
055 * @param request the http request
056 * @param response the http response
057 * @exception ServletException if a servlet processing error occurs
058 * @exception IOException if an IO error occurs
059 */
060 public void doPost( HttpServletRequest request, HttpServletResponse response )
061 throws ServletException, IOException
062 {
063 doGet( request, response );
064 }
065
066 /**
067 * Process an incomming get request.
068 * @param request the http request
069 * @param response the http response
070 * @exception ServletException if a servlet processing error occurs
071 * @exception IOException if an IO error occurs
072 */
073 public void doGet( HttpServletRequest request, HttpServletResponse response )
074 throws ServletException, IOException
075 {
076 request.setAttribute( "Dump", this );
077 getServletContext().setAttribute( "Dump", this );
078 getServletContext().log( "dump " + request.getRequestURI() );
079
080 // Force a content length response
081 String length = request.getParameter( "length" );
082 if( ( length != null ) && ( length.length() > 0 ) )
083 {
084 response.setContentLength( Integer.parseInt( length ) );
085 }
086
087 handleDataDump( request, response );
088 String info = handleException( request, response );
089 handleRedirect( request, response );
090
091 // handle an error
092 String error= request.getParameter( "error" );
093 if( error != null && error.length() > 0 )
094 {
095 response.getOutputStream().println( "THIS SHOULD NOT BE SEEN!" );
096 response.sendError( Integer.parseInt( error ) );
097 response.getOutputStream().println( "THIS SHOULD NOT BE SEEN!" );
098 return;
099 }
100
101 String buffer= request.getParameter( "buffer" );
102 if( buffer != null && buffer.length() > 0 )
103 {
104 response.setBufferSize( Integer.parseInt( buffer ) );
105 }
106
107 request.setCharacterEncoding( "UTF-8" );
108 response.setContentType( "text/html" );
109
110 if( info != null && info.indexOf( "Locale/" ) >= 0 )
111 {
112 try
113 {
114 String localeName = info.substring( info.indexOf( "Locale/" ) + 7 );
115 Field f = java.util.Locale.class.getField( localeName );
116 response.setLocale( (Locale) f.get( null ) );
117 }
118 catch( Exception e )
119 {
120 e.printStackTrace();
121 response.setLocale( Locale.getDefault() );
122 }
123 }
124
125 String cn = request.getParameter( "cookie" );
126 String cv =request.getParameter( "value" );
127 String v =request.getParameter( "version" );
128 if( cn!=null && cv!=null )
129 {
130 Cookie cookie = new Cookie( cn, cv );
131 cookie.setComment( "Cookie from dump servlet" );
132 if( v!=null )
133 {
134 cookie.setMaxAge( 300 );
135 cookie.setPath( "/" );
136 cookie.setVersion( Integer.parseInt( v ) );
137 }
138 response.addCookie( cookie );
139 }
140
141 String pi = request.getPathInfo();
142 if( pi != null && pi.startsWith( "/ex" ) )
143 {
144 OutputStream out = response.getOutputStream();
145 out.write( "</H1>This text should be reset</H1>".getBytes() );
146 if( "/ex0".equals( pi ) )
147 {
148 throw new ServletException( "test ex0", new Throwable() );
149 }
150 if( "/ex1".equals( pi ) )
151 {
152 throw new IOException( "test ex1" );
153 }
154 if( "/ex2".equals( pi ) )
155 {
156 throw new UnavailableException( "test ex2" );
157 }
158 throw new RuntimeException( "test" );
159 }
160
161 PrintWriter pout = null;
162 try
163 {
164 pout = response.getWriter();
165 }
166 catch( IllegalStateException e )
167 {
168 pout = new PrintWriter( response.getOutputStream() );
169 }
170 writeDumpContent( request, response, pout );
171 pout.close();
172
173 if( pi != null )
174 {
175 if( "/ex4".equals( pi ) )
176 {
177 throw new ServletException( "test ex4", new Throwable() );
178 }
179 if( "/ex5".equals( pi ) )
180 {
181 throw new IOException( "test ex5" );
182 }
183 if( "/ex6".equals( pi ) )
184 {
185 throw new UnavailableException( "test ex6" );
186 }
187 }
188 }
189
190 private void handleDataDump( HttpServletRequest request, HttpServletResponse response )
191 throws IOException
192 {
193 // Handle a dump of data
194 String data = request.getParameter( "data" );
195 String block = request.getParameter( "block" );
196 if( ( data != null ) && ( data.length() > 0 ) )
197 {
198 int d = Integer.parseInt( data );
199 int b = 50;
200 if( block != null && block.length() > 0 )
201 {
202 b = Integer.parseInt( block );
203 }
204 byte[] buf = new byte[b];
205 for( int i=0; i<b; i++ )
206 {
207 buf[i] = (byte) ( '0' + ( i%10 ) );
208 if( i%10 == 9 )
209 {
210 buf[i] = (byte) '\n';
211 }
212 }
213 buf[0] = 'o';
214 OutputStream out = response.getOutputStream();
215 response.setContentType( "text/plain" );
216 while( d > 0 )
217 {
218 if( d >= b )
219 {
220 out.write( buf );
221 d = d-b;
222 }
223 else
224 {
225 out.write( buf, 0, d );
226 d = 0;
227 }
228 }
229 return;
230 }
231 }
232
233 private String handleException( HttpServletRequest request, HttpServletResponse response )
234 throws ServletException
235 {
236 // handle an exception
237 String info = request.getPathInfo();
238 if( info != null && info.endsWith( "Exception" ) )
239 {
240 try
241 {
242 throw (Throwable) Thread.currentThread().getContextClassLoader().loadClass( info.substring( 1 ) ).newInstance();
243 }
244 catch( Throwable th )
245 {
246 throw new ServletException( th );
247 }
248 }
249 else
250 {
251 return info;
252 }
253 }
254
255 private void handleRedirect( HttpServletRequest request, HttpServletResponse response )
256 throws IOException
257 {
258 // handle an redirect
259 String redirect = request.getParameter( "redirect" );
260 if( redirect != null && redirect.length() > 0 )
261 {
262 response.getOutputStream().println( "THIS SHOULD NOT BE SEEN!" );
263 response.sendRedirect( redirect );
264 response.getOutputStream().println( "THIS SHOULD NOT BE SEEN!" );
265 return;
266 }
267 }
268
269
270 private void writeDumpContent(
271 HttpServletRequest request, HttpServletResponse response, PrintWriter pout )
272 {
273 try
274 {
275 pout.write( "<html>\n<body>\n" );
276 writeBasicContent( request, response, pout );
277 pout.write( "</body>\n</html>\n" );
278 }
279 catch( Exception e )
280 {
281 getServletContext().log( "dump", e );
282 }
283 }
284
285 private void writeBasicContent( HttpServletRequest request, HttpServletResponse response, PrintWriter pout )
286 {
287 try
288 {
289 pout.write( "<h1>Dump Servlet</h1>\n" );
290 pout.write( "<table>" );
291 pout.write( "<tr>\n" );
292 pout.write( "<th align=\"right\">getMethod: </th>" );
293 pout.write( "<td>" + request.getMethod() + "</td>" );
294 pout.write( "</tr><tr>\n" );
295 pout.write( "<th align=\"right\">getContentLength: </th>" );
296 pout.write( "<td>" + Integer.toString( request.getContentLength() ) + "</td>" );
297 pout.write( "</tr><tr>\n" );
298 pout.write( "<th align=\"right\">getContentType: </th>" );
299 pout.write( "<td>" + request.getContentType() + "</td>" );
300 pout.write( "</tr><tr>\n" );
301 pout.write( "<th align=\"right\">getRequestURI: </th>" );
302 pout.write( "<td>" + request.getRequestURI() + "</td>" );
303 pout.write( "</tr><tr>\n" );
304 pout.write( "<th align=\"right\">getRequestURL: </th>" );
305 pout.write( "<td>" + request.getRequestURL() + "</td>" );
306 pout.write( "</tr><tr>\n" );
307 pout.write( "<th align=\"right\">getContextPath: </th>" );
308 pout.write( "<td>" + request.getContextPath() + "</td>" );
309 pout.write( "</tr><tr>\n" );
310 pout.write( "<th align=\"right\">getServletPath: </th>" );
311 pout.write( "<td>" + request.getServletPath() + "</td>" );
312 pout.write( "</tr><tr>\n" );
313 pout.write( "<th align=\"right\">getPathInfo: </th>" );
314 pout.write( "<td>" + request.getPathInfo() + "</td>" );
315 pout.write( "</tr><tr>\n" );
316 pout.write( "<th align=\"right\">getPathTranslated: </th>" );
317 pout.write( "<td>" + request.getPathTranslated() + "</td>" );
318 pout.write( "</tr><tr>\n" );
319 pout.write( "<th align=\"right\">getQueryString: </th>" );
320 pout.write( "<td>" + request.getQueryString() + "</td>" );
321
322 pout.write( "</tr><tr>\n" );
323 pout.write( "<th align=\"right\">getProtocol: </th>" );
324 pout.write( "<td>" + request.getProtocol() + "</td>" );
325 pout.write( "</tr><tr>\n" );
326 pout.write( "<th align=\"right\">getScheme: </th>" );
327 pout.write( "<td>" + request.getScheme() + "</td>" );
328 pout.write( "</tr><tr>\n" );
329 pout.write( "<th align=\"right\">getServerName: </th>" );
330 pout.write( "<td>" + request.getServerName() + "</td>" );
331 pout.write( "</tr><tr>\n" );
332 pout.write( "<th align=\"right\">getServerPort: </th>" );
333 pout.write( "<td>" + Integer.toString( request.getServerPort() ) + "</td>" );
334 pout.write( "</tr><tr>\n" );
335 pout.write( "<th align=\"right\">getLocalName: </th>" );
336 pout.write( "<td>" + request.getLocalName() + "</td>" );
337 pout.write( "</tr><tr>\n" );
338 pout.write( "<th align=\"right\">getLocalAddr: </th>" );
339 pout.write( "<td>" + request.getLocalAddr() + "</td>" );
340 pout.write( "</tr><tr>\n" );
341 pout.write( "<th align=\"right\">getLocalPort: </th>" );
342 pout.write( "<td>"+ Integer.toString( request.getLocalPort() ) + "</td>" );
343 pout.write( "</tr><tr>\n" );
344 pout.write( "<th align=\"right\">getRemoteUser: </th>" );
345 pout.write( "<td>" + request.getRemoteUser() + "</td>" );
346 pout.write( "</tr><tr>\n" );
347 pout.write( "<th align=\"right\">getRemoteAddr: </th>" );
348 pout.write( "<td>" + request.getRemoteAddr() + "</td>" );
349 pout.write( "</tr><tr>\n" );
350 pout.write( "<th align=\"right\">getRemoteHost: </th>" );
351 pout.write( "<td>" + request.getRemoteHost() + "</td>" );
352 pout.write( "</tr><tr>\n" );
353 pout.write( "<th align=\"right\">getRemotePort: </th>" );
354 pout.write( "<td>" + request.getRemotePort() + "</td>" );
355 pout.write( "</tr><tr>\n" );
356 pout.write( "<th align=\"right\">getRequestedSessionId: </th>" );
357 pout.write( "<td>" + request.getRequestedSessionId() + "</td>" );
358 pout.write( "</tr><tr>\n" );
359 pout.write( "<th align=\"right\">isSecure(): </th>" );
360 pout.write( "<td>" + request.isSecure() + "</td>" );
361
362 pout.write( "</tr><tr>\n" );
363 pout.write( "<th align=\"right\">isUserInRole(admin): </th>" );
364 pout.write( "<td>" + request.isUserInRole( "admin" )+"</td>" );
365
366 pout.write( "</tr><tr>\n" );
367 pout.write( "<th align=\"right\">getLocale: </th>" );
368 pout.write( "<td>" + request.getLocale() + "</td>" );
369 }
370 catch( Exception e )
371 {
372 getServletContext().log( "dump", e );
373 }
374 }
375
376 private void writeExtendedContent( HttpServletRequest request, HttpServletResponse response, PrintWriter pout )
377 {
378 try
379 {
380 Enumeration locales= request.getLocales();
381 while( locales.hasMoreElements() )
382 {
383 pout.write( "</tr><tr>\n" );
384 pout.write( "<th align=\"right\">getLocales: </th>" );
385 pout.write( "<td>" + locales.nextElement() + "</td>" );
386 }
387 pout.write( "</tr><tr>\n" );
388 pout.write( "<th align=\"left\" colspan=\"2\"><big><br/>Other HTTP Headers:</big></th>" );
389 Enumeration h= request.getHeaderNames();
390 String name;
391 while( h.hasMoreElements() )
392 {
393 name = (String) h.nextElement();
394
395 Enumeration h2 = request.getHeaders( name );
396 while( h2.hasMoreElements() )
397 {
398 String hv = (String) h2.nextElement();
399 pout.write( "</tr><tr>\n" );
400 pout.write( "<th align=\"right\">" + name + ": </th>" );
401 pout.write( "<td>" + hv + "</td>" );
402 }
403 }
404 pout.write( "</tr><tr>\n" );
405 pout.write( "<th align=\"left\" colspan=\"2\"><big><br/>Request Parameters:</big></th>" );
406 h = request.getParameterNames();
407 while( h.hasMoreElements() )
408 {
409 name = (String) h.nextElement();
410 pout.write( "</tr><tr>\n" );
411 pout.write( "<th align=\"right\">" + name + ": </th>" );
412 pout.write( "<td>" + request.getParameter( name ) + "</td>" );
413 String[] values= request.getParameterValues( name );
414 if( values == null )
415 {
416 pout.write( "</tr><tr>\n" );
417 pout.write( "<th align=\"right\">" + name + " Values: </th>" );
418 pout.write( "<td>" + "NULL!" + "</td>" );
419 }
420 else if( values.length > 1 )
421 {
422 for( int i=0; i<values.length; i++ )
423 {
424 pout.write( "</tr><tr>\n" );
425 pout.write( "<th align=\"right\">" + name + "[" + i + "]: </th>" );
426 pout.write( "<td>" + values[i] + "</td>" );
427 }
428 }
429 }
430 pout.write( "</tr><tr>\n" );
431 writeCookies( request, response, pout );
432 pout.write( "</tr><tr>\n" );
433 pout.write( "<th align=\"left\" colspan=\"2\"><big><br/>Request Attributes:</big></th>" );
434 Enumeration a = request.getAttributeNames();
435 while( a.hasMoreElements() )
436 {
437 name= (String) a.nextElement();
438 pout.write( "</tr><tr>\n" );
439 pout.write( "<th align=\"right\">" + name + ": </th>" );
440 pout.write( "<td>" + "<pre>" + toString( request.getAttribute( name ) ) + "</pre>"+"</td>" );
441 }
442 pout.write( "</tr><tr>\n" );
443 pout.write( "<th align=\"left\" colspan=\"2\"><big><br/>Servlet InitParameters:</big></th>" );
444 a = getInitParameterNames();
445 while( a.hasMoreElements() )
446 {
447 name = (String) a.nextElement();
448 pout.write( "</tr><tr>\n" );
449 pout.write( "<th align=\"right\">" + name + ": </th>" );
450 pout.write( "<td>"+"<pre>" + toString( getInitParameter( name ) ) + "</pre>"+"</td>" );
451 }
452 pout.write( "</tr><tr>\n" );
453 pout.write( "<th align=\"left\" colspan=\"2\"><big><br/>Context InitParameters:</big></th>" );
454 a = getServletContext().getInitParameterNames();
455 while( a.hasMoreElements() )
456 {
457 name = (String) a.nextElement();
458 pout.write( "</tr><tr>\n" );
459 pout.write( "<th align=\"right\">" + name + ": </th>" );
460 pout.write( "<td>" + "<pre>" + toString( getServletContext().getInitParameter( name ) ) + "</pre>" + "</td>" );
461 }
462 pout.write( "</tr><tr>\n" );
463 pout.write( "<th align=\"left\" colspan=\"2\"><big><br/>Context Attributes:</big></th>" );
464 a = getServletContext().getAttributeNames();
465 while( a.hasMoreElements() )
466 {
467 name = (String) a.nextElement();
468 pout.write( "</tr><tr>\n" );
469 pout.write( "<th align=\"right\">" + name + ": </th>" );
470 pout.write( "<td>"+"<pre>" + toString( getServletContext().getAttribute( name ) ) + "</pre>" + "</td>" );
471 }
472 String res= request.getParameter( "resource" );
473 if( res != null && res.length() > 0 )
474 {
475 pout.write( "</tr><tr>\n" );
476 pout.write( "<th align=\"left\" colspan=\"2\"><big><br/>Get Resource:</big></th>" );
477
478 pout.write( "</tr><tr>\n" );
479 pout.write( "<th align=\"right\">this.getClass(): </th>" );
480 pout.write( "<td>" + this.getClass().getResource( res ) + "</td>" );
481
482 pout.write( "</tr><tr>\n" );
483 pout.write( "<th align=\"right\">this.getClass().getClassLoader(): </th>" );
484 pout.write( "<td>" + this.getClass().getClassLoader().getResource( res ) + "</td>" );
485
486 pout.write( "</tr><tr>\n" );
487 pout.write( "<th align=\"right\">Thread.currentThread().getContextClassLoader(): </th>" );
488 pout.write( "<td>" + Thread.currentThread().getContextClassLoader().getResource( res ) + "</td>" );
489
490 pout.write( "</tr><tr>\n" );
491 pout.write( "<th align=\"right\">getServletContext(): </th>" );
492 try
493 {
494 pout.write( "<td>" + getServletContext().getResource( res ) + "</td>" );
495 }
496 catch( Exception e )
497 {
498 pout.write( "<td>" + "" + e + "</td>" );
499 }
500 }
501 pout.write( "</tr></table>\n" );
502 writeRequestWrappers( request, response, pout );
503 pout.write( "<br/>" );
504 writeInternationalCharacter( pout );
505 pout.write( "<br/>" );
506 writeGetForm( request, response, pout );
507 pout.write( "<br/>" );
508 writePostForm( request, response, pout );
509 pout.write( "<br/>" );
510 writeResourceForm( request, response, pout );
511 }
512 catch( Exception e )
513 {
514 getServletContext().log( "dump", e );
515 }
516 }
517
518 private void writeCookies( HttpServletRequest request, HttpServletResponse response, PrintWriter pout )
519 throws IOException
520 {
521 pout.write( "<th align=\"left\" colspan=\"2\"><big><br/>Cookies:</big></th>" );
522 Cookie[] cookies = request.getCookies();
523 for( int i=0; cookies!=null && i<cookies.length; i++ )
524 {
525 Cookie cookie = cookies[i];
526 pout.write( "</tr><tr>\n" );
527 pout.write( "<th align=\"right\">" + cookie.getName() + ": </th>" );
528 pout.write( "<td>" + cookie.getValue() + "</td>" );
529 }
530 }
531
532 private void writeRequestWrappers( HttpServletRequest request, HttpServletResponse response, PrintWriter pout ) throws IOException
533 {
534 pout.write( "<h2>Request Wrappers</h2>\n" );
535 ServletRequest rw = request;
536 int w=0;
537 while( rw != null )
538 {
539 pout.write( ( w++ ) + ": " + rw.getClass().getName() + "<br/>" );
540 if( rw instanceof HttpServletRequestWrapper )
541 {
542 rw = ( (HttpServletRequestWrapper) rw ).getRequest();
543 }
544 else if( rw instanceof ServletRequestWrapper )
545 {
546 rw = ( (ServletRequestWrapper) rw ).getRequest();
547 }
548 else
549 {
550 rw=null;
551 }
552 }
553 }
554
555 private void writeInternationalCharacter( PrintWriter pout ) throws IOException
556 {
557 pout.write( "<h2>International Characters</h2>" );
558 pout.write( "Directly encoced: Dürst<br/>" );
559 pout.write( "HTML reference: Dürst<br/>" );
560 pout.write( "Decimal (252) 8859-1: Dürst<br/>" );
561 pout.write( "Hex (xFC) 8859-1: Dürst<br/>" );
562 pout.write( "Javascript unicode (00FC) : <script language='javascript'>document.write(\"D\u00FCrst\" );</script><br/>" );
563 }
564
565 private void writeGetForm(
566 HttpServletRequest request, HttpServletResponse response, PrintWriter pout ) throws IOException
567 {
568 pout.write( "<h2>Form to generate GET content</h2>" );
569 pout.write( "<form method=\"GET\" action=\"" + response.encodeURL( getURI( request ) ) + "\">" );
570 pout.write( "TextField: <input type=\"text\" name=\"TextField\" value=\"value\"/><br/>\n" );
571 pout.write( "<input type=\"submit\" name=\"Action\" value=\"Submit\">" );
572 pout.write( "</form>" );
573 }
574
575 private void writePostForm(
576 HttpServletRequest request, HttpServletResponse response, PrintWriter pout ) throws IOException
577 {
578 pout.write( "<h2>Form to generate POST content</h2>" );
579 pout.write( "<form method=\"POST\" action=\"" + response.encodeURL( getURI( request ) ) + "\">" );
580 pout.write( "TextField: <input type=\"text\" name=\"TextField\" value=\"value\"/><br/>\n" );
581 pout.write( "Select: <select multiple name=\"Select\">\n" );
582 pout.write( "<option>ValueA</option>" );
583 pout.write( "<option>ValueB1,ValueB2</option>" );
584 pout.write( "<option>ValueC</option>" );
585 pout.write( "</select><br/>" );
586 pout.write( "<input type=\"submit\" name=\"Action\" value=\"Submit\"><br/>" );
587 pout.write( "</form>" );
588 }
589
590 private void writeResourceForm(
591 HttpServletRequest request, HttpServletResponse response, PrintWriter pout ) throws IOException
592 {
593 pout.write( "<h2>Form to get Resource</h2>" );
594 pout.write( "<form method=\"POST\" action=\"" + response.encodeURL( getURI( request ) ) + "\">" );
595 pout.write( "resource: <input type=\"text\" name=\"resource\" /><br/>\n" );
596 pout.write( "<input type=\"submit\" name=\"Action\" value=\"getResource\">" );
597 pout.write( "</form>\n" );
598 }
599
600 /**
601 * Return the servlet info.
602 * @return the info
603 */
604 public String getServletInfo()
605 {
606 return "Dump Servlet";
607 }
608
609 /**
610 * Destroy the servlet.
611 */
612 public synchronized void destroy()
613 {
614 }
615
616 private String getURI( HttpServletRequest request )
617 {
618 String uri= (String) request.getAttribute( "javax.servlet.forward.request_uri" );
619 if( uri == null )
620 {
621 uri = request.getRequestURI();
622 }
623 return uri;
624 }
625
626 private static String toString( Object o )
627 {
628 if( o == null )
629 {
630 return null;
631 }
632 if( o.getClass().isArray() )
633 {
634 StringBuffer sb = new StringBuffer();
635 Object[] array = (Object[]) o;
636 for( int i=0; i<array.length; i++ )
637 {
638 if( i>0 )
639 {
640 sb.append( "\n" );
641 }
642 sb.append( array.getClass().getComponentType().getName() );
643 sb.append( "[" );
644 sb.append( i );
645 sb.append( "]=" );
646 sb.append( toString( array[i] ) );
647 }
648 return sb.toString();
649 }
650 else
651 {
652 return o.toString();
653 }
654 }
655 }