View Javadoc

1   /*
2    ~ Copyright 2006-2007 Nicolas De Loof.
3    ~
4    ~ Licensed under the Apache License, Version 2.0 (the "License");
5    ~ you may not use this file except in compliance with the License.
6    ~ You may obtain a copy of the License at
7    ~
8    ~      http://www.apache.org/licenses/LICENSE-2.0
9    ~
10   ~ Unless required by applicable law or agreed to in writing, software
11   ~ distributed under the License is distributed on an "AS IS" BASIS,
12   ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   ~ See the License for the specific language governing permissions and
14   ~ limitations under the License.
15   */
16  package org.jmonit.reporting;
17  
18  import java.io.ByteArrayOutputStream;
19  import java.io.PrintWriter;
20  import java.lang.reflect.Array;
21  import java.util.BitSet;
22  import java.util.Iterator;
23  import java.util.Locale;
24  import java.util.Map;
25  
26  import org.jmonit.Monitor;
27  
28  /**
29   * @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
30   */
31  public class JSonRenderer
32      implements Renderer, Visitor
33  {
34      private PrintWriter writer;
35  
36      public JSonRenderer( PrintWriter writer )
37      {
38          super();
39          this.writer = writer;
40      }
41  
42      public void setLocale( Locale locale )
43      {
44          // ;
45      }
46  
47      /**
48       * {@inheritDoc}
49       * 
50       * @see org.jmonit.reporting.Renderer#createNew(java.io.PrintWriter)
51       */
52      public Renderer createNew( PrintWriter writer )
53      {
54          return new JSonRenderer( writer );
55      }
56  
57      /**
58       * {@inheritDoc}
59       * 
60       * @see org.jmonit.reporting.Renderer#render(java.util.Iterator)
61       */
62      public void render( Iterator<Visitable> iterator )
63      {
64          writer.print( "[" );
65          while ( iterator.hasNext() )
66          {
67              iterator.next().accept( this );
68              if ( iterator.hasNext() )
69              {
70                  writer.write( "," );
71              }
72          }
73          writer.print( "]" );
74      }
75  
76      /**
77       * {@inheritDoc}
78       * 
79       * @see org.jmonit.reporting.Visitor#visit(org.jmonit.Monitor)
80       */
81      public void visit( Monitor monitor )
82      {
83  
84      }
85  
86      /**
87       * {@inheritDoc}
88       * 
89       * @see org.jmonit.reporting.Visitor#visit(java.util.Map)
90       */
91      public void visit( Map<String, Object> attributes )
92      {
93          writer.print( "{ " );
94          for ( Iterator<Map.Entry<String, Object>> iterator = attributes.entrySet().iterator(); iterator
95              .hasNext(); )
96          {
97              Map.Entry<String, Object> entry = iterator.next();
98              String key = entry.getKey();
99              Object value = entry.getValue();
100             if ( value instanceof Visitable )
101             {
102                 writer.print( "\"" + key + "\" : " );
103                 ( (Visitable) value ).accept( this );
104             }
105             else if ( value.getClass().isArray() )
106             {
107                 writer.print( "\"" + key + "\" : [" );
108                 int length = Array.getLength( value );
109                 for ( int i = 0; i < length; )
110                 {
111                     Object element = Array.get( value, i++ );
112                     writer.print( "\"" + sanitize( String.valueOf( element ) ) + "\"" );
113                     if ( i < length )
114                     {
115                         writer.print( "," );
116                     }
117                 }
118                 writer.print( "]" );
119             }
120             else
121             {
122                 writer.print( "\"" + key + "\" : \"" + sanitize( String.valueOf( value ) ) + "\"" );
123             }
124             if ( iterator.hasNext() )
125             {
126                 writer.print( "," );
127             }
128         }
129         writer.print( "}" );
130     }
131 
132     // --- code adapted from commons-codec -----------------------------------
133     // @author Apache Software Foundation
134 
135     private static final BitSet SAFE = new BitSet( 256 );
136 
137     // Static initializer for www_form_url
138     static
139     {
140         // alpha characters
141         for ( int i = 'a'; i <= 'z'; i++ )
142         {
143             SAFE.set( i );
144         }
145         for ( int i = 'A'; i <= 'Z'; i++ )
146         {
147             SAFE.set( i );
148         }
149         // numeric characters
150         for ( int i = '0'; i <= '9'; i++ )
151         {
152             SAFE.set( i );
153         }
154         // special chars
155         SAFE.set( '-' );
156         SAFE.set( '_' );
157         SAFE.set( '.' );
158         SAFE.set( '*' );
159         SAFE.set( '~' );
160     }
161 
162     /**
163      * Sanitize a String to get rendered as JSON value
164      * 
165      * @param string input string
166      * @return sanitized string, that can be safely included as a JSON value
167      */
168     private String sanitize( String string )
169     {
170         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
171         byte[] bytes = string.getBytes();
172         for ( int i = 0; i < bytes.length; i++ )
173         {
174             int b = bytes[i];
175             if ( b < 0 )
176             {
177                 b = 256 + b;
178             }
179             if ( SAFE.get( b ) )
180             {
181                 buffer.write( b );
182             }
183             else
184             {
185                 buffer.write( '%' );
186                 char hex1 = Character.toUpperCase( Character.forDigit( ( b >> 4 ) & 0xF, 16 ) );
187                 char hex2 = Character.toUpperCase( Character.forDigit( b & 0xF, 16 ) );
188                 buffer.write( hex1 );
189                 buffer.write( hex2 );
190             }
191         }
192         return new String( buffer.toByteArray() );
193     }
194 }