5de57407bfd72103ce34abdbb4a78518b1f39aff
[packages/precise/mcollective.git] / lib / mcollective / vendor / json / java / src / json / ext / RuntimeInfo.java
1 /*
2  * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3  *
4  * Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
5  * for details.
6  */
7 package json.ext;
8
9 import java.lang.ref.WeakReference;
10 import java.util.HashMap;
11 import java.util.Map;
12 import java.util.WeakHashMap;
13 import org.jruby.Ruby;
14 import org.jruby.RubyClass;
15 import org.jruby.RubyEncoding;
16 import org.jruby.RubyModule;
17 import org.jruby.runtime.ThreadContext;
18 import org.jruby.runtime.builtin.IRubyObject;
19
20
21 final class RuntimeInfo {
22     // since the vast majority of cases runs just one runtime,
23     // we optimize for that
24     private static WeakReference<Ruby> runtime1 = new WeakReference<Ruby>(null);
25     private static RuntimeInfo info1;
26     // store remaining runtimes here (does not include runtime1)
27     private static Map<Ruby, RuntimeInfo> runtimes;
28
29     // these fields are filled by the service loaders
30     // Use WeakReferences so that RuntimeInfo doesn't indirectly hold a hard reference to
31     // the Ruby runtime object, which would cause memory leaks in the runtimes map above.
32     /** JSON */
33     WeakReference<RubyModule> jsonModule;
34     /** JSON::Ext::Generator::GeneratorMethods::String::Extend */
35     WeakReference<RubyModule> stringExtendModule;
36     /** JSON::Ext::Generator::State */
37     WeakReference<RubyClass> generatorStateClass;
38     /** JSON::SAFE_STATE_PROTOTYPE */
39     WeakReference<GeneratorState> safeStatePrototype;
40
41     final WeakReference<RubyEncoding> utf8;
42     final WeakReference<RubyEncoding> ascii8bit;
43     // other encodings
44     private final Map<String, WeakReference<RubyEncoding>> encodings;
45
46     private RuntimeInfo(Ruby runtime) {
47         RubyClass encodingClass = runtime.getEncoding();
48         if (encodingClass == null) { // 1.8 mode
49             utf8 = ascii8bit = null;
50             encodings = null;
51         } else {
52             ThreadContext context = runtime.getCurrentContext();
53
54             utf8 = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context,
55                     encodingClass, runtime.newString("utf-8")));
56             ascii8bit = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context,
57                     encodingClass, runtime.newString("ascii-8bit")));
58             encodings = new HashMap<String, WeakReference<RubyEncoding>>();
59         }
60     }
61
62     static RuntimeInfo initRuntime(Ruby runtime) {
63         synchronized (RuntimeInfo.class) {
64             if (runtime1.get() == runtime) {
65                 return info1;
66             } else if (runtime1.get() == null) {
67                 runtime1 = new WeakReference<Ruby>(runtime);
68                 info1 = new RuntimeInfo(runtime);
69                 return info1;
70             } else {
71                 if (runtimes == null) {
72                     runtimes = new WeakHashMap<Ruby, RuntimeInfo>(1);
73                 }
74                 RuntimeInfo cache = runtimes.get(runtime);
75                 if (cache == null) {
76                     cache = new RuntimeInfo(runtime);
77                     runtimes.put(runtime, cache);
78                 }
79                 return cache;
80             }
81         }
82     }
83
84     public static RuntimeInfo forRuntime(Ruby runtime) {
85         synchronized (RuntimeInfo.class) {
86             if (runtime1.get() == runtime) return info1;
87             RuntimeInfo cache = null;
88             if (runtimes != null) cache = runtimes.get(runtime);
89             assert cache != null : "Runtime given has not initialized JSON::Ext";
90             return cache;
91         }
92     }
93
94     public boolean encodingsSupported() {
95         return utf8 != null && utf8.get() != null;
96     }
97
98     public RubyEncoding getEncoding(ThreadContext context, String name) {
99         synchronized (encodings) {
100             WeakReference<RubyEncoding> encoding = encodings.get(name);
101             if (encoding == null) {
102                 Ruby runtime = context.getRuntime();
103                 encoding = new WeakReference<RubyEncoding>((RubyEncoding)RubyEncoding.find(context,
104                         runtime.getEncoding(), runtime.newString(name)));
105                 encodings.put(name, encoding);
106             }
107             return encoding.get();
108         }
109     }
110
111     public GeneratorState getSafeStatePrototype(ThreadContext context) {
112         if (safeStatePrototype == null) {
113             IRubyObject value = jsonModule.get().getConstant("SAFE_STATE_PROTOTYPE");
114             if (!(value instanceof GeneratorState)) {
115                 throw context.getRuntime().newTypeError(value, generatorStateClass.get());
116             }
117             safeStatePrototype = new WeakReference<GeneratorState>((GeneratorState)value);
118         }
119         return safeStatePrototype.get();
120     }
121 }