View Javadoc

1   /*
2    * Copyright 2002-2009 the original author or authors.
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  
17  package net.sf.json;
18  
19  import java.lang.ref.SoftReference;
20  import java.util.HashSet;
21  import java.util.Iterator;
22  import java.util.Set;
23  
24  import net.sf.json.util.JSONTokener;
25  import net.sf.json.util.JSONUtils;
26  import net.sf.json.util.JsonEventListener;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  /**
32   * Base class for JSONObject and JSONArray.
33   *
34   * @author Andres Almiray <aalmiray@users.sourceforge.net>
35   */
36  abstract class AbstractJSON {
37     private static class CycleSet extends ThreadLocal {
38        protected Object initialValue() {
39           return new SoftReference(new HashSet());
40        }
41  
42        public Set getSet() {
43           Set set = (Set) ((SoftReference)get()).get();
44           if( set == null ) {
45               set = new HashSet();
46               set(new SoftReference(set));
47           }
48           return set;
49        }
50     }
51     
52     private static CycleSet cycleSet = new CycleSet();
53  
54     private static final Log log = LogFactory.getLog( AbstractJSON.class );
55  
56     /**
57      * Adds a reference for cycle detection check.
58      *
59      * @param instance the reference to add
60      * @return true if the instance has not been added previously, false
61      *        otherwise.
62      */
63     protected static boolean addInstance( Object instance ) {
64        return getCycleSet().add( instance );
65     }
66  
67     /**
68      * Fires an end of array event.
69      */
70     protected static void fireArrayEndEvent( JsonConfig jsonConfig ) {
71        if( jsonConfig.isEventTriggeringEnabled() ){
72           for( Iterator listeners = jsonConfig.getJsonEventListeners()
73                 .iterator(); listeners.hasNext(); ){
74              JsonEventListener listener = (JsonEventListener) listeners.next();
75              try{
76                 listener.onArrayEnd();
77              }catch( RuntimeException e ){
78                 log.warn( e );
79              }
80           }
81        }
82     }
83  
84     /**
85      * Fires a start of array event.
86      */
87     protected static void fireArrayStartEvent( JsonConfig jsonConfig ) {
88        if( jsonConfig.isEventTriggeringEnabled() ){
89           for( Iterator listeners = jsonConfig.getJsonEventListeners()
90                 .iterator(); listeners.hasNext(); ){
91              JsonEventListener listener = (JsonEventListener) listeners.next();
92              try{
93                 listener.onArrayStart();
94              }catch( RuntimeException e ){
95                 log.warn( e );
96              }
97           }
98        }
99     }
100 
101    /**
102     * Fires an element added event.
103     *
104     * @param index the index where the element was added
105     * @param element the added element
106     */
107    protected static void fireElementAddedEvent( int index, Object element, JsonConfig jsonConfig ) {
108       if( jsonConfig.isEventTriggeringEnabled() ){
109          for( Iterator listeners = jsonConfig.getJsonEventListeners()
110                .iterator(); listeners.hasNext(); ){
111             JsonEventListener listener = (JsonEventListener) listeners.next();
112             try{
113                listener.onElementAdded( index, element );
114             }catch( RuntimeException e ){
115                log.warn( e );
116             }
117          }
118       }
119    }
120 
121    /**
122     * Fires an error event.
123     *
124     * @param jsone the thrown exception
125     */
126    protected static void fireErrorEvent( JSONException jsone, JsonConfig jsonConfig ) {
127       if( jsonConfig.isEventTriggeringEnabled() ){
128          for( Iterator listeners = jsonConfig.getJsonEventListeners()
129                .iterator(); listeners.hasNext(); ){
130             JsonEventListener listener = (JsonEventListener) listeners.next();
131             try{
132                listener.onError( jsone );
133             }catch( RuntimeException e ){
134                log.warn( e );
135             }
136          }
137       }
138    }
139 
140    /**
141     * Fires an end of object event.
142     */
143    protected static void fireObjectEndEvent( JsonConfig jsonConfig ) {
144       if( jsonConfig.isEventTriggeringEnabled() ){
145          for( Iterator listeners = jsonConfig.getJsonEventListeners()
146                .iterator(); listeners.hasNext(); ){
147             JsonEventListener listener = (JsonEventListener) listeners.next();
148             try{
149                listener.onObjectEnd();
150             }catch( RuntimeException e ){
151                log.warn( e );
152             }
153          }
154       }
155    }
156 
157    /**
158     * Fires a start of object event.
159     */
160    protected static void fireObjectStartEvent( JsonConfig jsonConfig ) {
161       if( jsonConfig.isEventTriggeringEnabled() ){
162          for( Iterator listeners = jsonConfig.getJsonEventListeners()
163                .iterator(); listeners.hasNext(); ){
164             JsonEventListener listener = (JsonEventListener) listeners.next();
165             try{
166                listener.onObjectStart();
167             }catch( RuntimeException e ){
168                log.warn( e );
169             }
170          }
171       }
172    }
173 
174    /**
175     * Fires a property set event.
176     *
177     * @param key the name of the property
178     * @param value the value of the property
179     * @param accumulated if the value has been accumulated over 'key'
180     */
181    protected static void firePropertySetEvent( String key, Object value, boolean accumulated,
182          JsonConfig jsonConfig ) {
183       if( jsonConfig.isEventTriggeringEnabled() ){
184          for( Iterator listeners = jsonConfig.getJsonEventListeners()
185                .iterator(); listeners.hasNext(); ){
186             JsonEventListener listener = (JsonEventListener) listeners.next();
187             try{
188                listener.onPropertySet( key, value, accumulated );
189             }catch( RuntimeException e ){
190                log.warn( e );
191             }
192          }
193       }
194    }
195 
196    /**
197     * Fires a warning event.
198     *
199     * @param warning the warning message
200     */
201    protected static void fireWarnEvent( String warning, JsonConfig jsonConfig ) {
202       if( jsonConfig.isEventTriggeringEnabled() ){
203          for( Iterator listeners = jsonConfig.getJsonEventListeners()
204                .iterator(); listeners.hasNext(); ){
205             JsonEventListener listener = (JsonEventListener) listeners.next();
206             try{
207                listener.onWarning( warning );
208             }catch( RuntimeException e ){
209                log.warn( e );
210             }
211          }
212       }
213    }
214 
215    /**
216     * Removes a reference for cycle detection check.
217     */
218    protected static void removeInstance( Object instance ) {
219       getCycleSet().remove( instance );
220    }
221 
222    protected Object _processValue( Object value, JsonConfig jsonConfig ) {
223       if( JSONNull.getInstance().equals( value ) ) {
224          return JSONNull.getInstance();
225       } else if( Class.class.isAssignableFrom( value.getClass() ) || value instanceof Class ) {
226          return ((Class) value).getName();
227       } else if( JSONUtils.isFunction( value ) ) {
228          if( value instanceof String ) {
229             value = JSONFunction.parse( (String) value );
230          }
231          return value;
232       } else if( value instanceof JSONString ) {
233          return JSONSerializer.toJSON( (JSONString) value, jsonConfig );
234       } else if( value instanceof JSON ) {
235          return JSONSerializer.toJSON( value, jsonConfig );
236       } else if( JSONUtils.isArray( value ) ) {
237          return JSONArray.fromObject( value, jsonConfig );
238       } else if( JSONUtils.isString( value ) ) {
239          String str = String.valueOf( value );
240          if( JSONUtils.hasQuotes( str ) ){
241             str = JSONUtils.stripQuotes( str );
242             if( JSONUtils.isFunction( str )){
243                return JSONUtils.DOUBLE_QUOTE + str + JSONUtils.DOUBLE_QUOTE;
244             }
245             return str;
246          } else if( JSONUtils.isJsonKeyword( str, jsonConfig ) ) {
247             if( jsonConfig.isJavascriptCompliant() && "undefined".equals( str )){
248                return JSONNull.getInstance();
249             }
250             return str;
251          } else if( JSONUtils.mayBeJSON( str ) ) {
252             try {
253                return JSONSerializer.toJSON( str, jsonConfig );
254             } catch( JSONException jsone ) {
255                return str;
256             }
257          }
258          return str;
259       } else if( JSONUtils.isNumber( value ) ) {
260          JSONUtils.testValidity( value );
261          return JSONUtils.transformNumber( (Number) value );
262       } else if( JSONUtils.isBoolean( value ) ) {
263          return value;
264       } else {
265          JSONObject jsonObject = JSONObject.fromObject( value, jsonConfig );
266          if( jsonObject.isNullObject() ) {
267             return JSONNull.getInstance();
268          } else {
269             return jsonObject;
270          }
271       }
272    }
273    
274    private static Set getCycleSet() {
275       return cycleSet.getSet();
276    }
277 }