2 * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
4 * Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
9 import java.lang.ref.WeakReference;
10 import java.util.HashMap;
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;
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;
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.
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;
41 final WeakReference<RubyEncoding> utf8;
42 final WeakReference<RubyEncoding> ascii8bit;
44 private final Map<String, WeakReference<RubyEncoding>> encodings;
46 private RuntimeInfo(Ruby runtime) {
47 RubyClass encodingClass = runtime.getEncoding();
48 if (encodingClass == null) { // 1.8 mode
49 utf8 = ascii8bit = null;
52 ThreadContext context = runtime.getCurrentContext();
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>>();
62 static RuntimeInfo initRuntime(Ruby runtime) {
63 synchronized (RuntimeInfo.class) {
64 if (runtime1.get() == runtime) {
66 } else if (runtime1.get() == null) {
67 runtime1 = new WeakReference<Ruby>(runtime);
68 info1 = new RuntimeInfo(runtime);
71 if (runtimes == null) {
72 runtimes = new WeakHashMap<Ruby, RuntimeInfo>(1);
74 RuntimeInfo cache = runtimes.get(runtime);
76 cache = new RuntimeInfo(runtime);
77 runtimes.put(runtime, cache);
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";
94 public boolean encodingsSupported() {
95 return utf8 != null && utf8.get() != null;
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);
107 return encoding.get();
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());
117 safeStatePrototype = new WeakReference<GeneratorState>((GeneratorState)value);
119 return safeStatePrototype.get();