001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
015: * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
016: * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
017: * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
018: * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
019: * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
020: * Copyright (C) 2004 David Corbin <dcorbin@users.sourceforge.net>
021: *
022: * Alternatively, the contents of this file may be used under the terms of
023: * either of the GNU General Public License Version 2 or later (the "GPL"),
024: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
025: * in which case the provisions of the GPL or the LGPL are applicable instead
026: * of those above. If you wish to allow use of your version of this file only
027: * under the terms of either the GPL or the LGPL, and not to allow others to
028: * use your version of this file under the terms of the CPL, indicate your
029: * decision by deleting the provisions above and replace them with the notice
030: * and other provisions required by the GPL or the LGPL. If you do not delete
031: * the provisions above, a recipient may use your version of this file under
032: * the terms of any one of the CPL, the GPL or the LGPL.
033: ***** END LICENSE BLOCK *****/package org.jruby.javasupport;
034:
035: import org.jruby.Ruby;
036: import org.jruby.RubyClass;
037: import org.jruby.RubyFixnum;
038: import org.jruby.RubyModule;
039: import org.jruby.RubyObject;
040: import org.jruby.RubyString;
041: import org.jruby.runtime.Block;
042: import org.jruby.runtime.CallbackFactory;
043: import org.jruby.runtime.ObjectAllocator;
044: import org.jruby.runtime.ObjectMarshal;
045: import org.jruby.runtime.builtin.IRubyObject;
046:
047: /**
048: *
049: * @author jpetersen
050: */
051: public class JavaObject extends RubyObject {
052: private static Object NULL_LOCK = new Object();
053: private final Object value;
054:
055: protected JavaObject(Ruby runtime, RubyClass rubyClass, Object value) {
056: super (runtime, rubyClass);
057: this .value = value;
058: }
059:
060: protected JavaObject(Ruby runtime, Object value) {
061: this (runtime, runtime.getJavaSupport().getJavaObjectClass(),
062: value);
063: }
064:
065: public static JavaObject wrap(Ruby runtime, Object value) {
066: Object lock = value == null ? NULL_LOCK : value;
067:
068: synchronized (lock) {
069: JavaObject wrapper = runtime.getJavaSupport()
070: .getJavaObjectFromCache(value);
071: if (wrapper == null) {
072: if (value == null) {
073: wrapper = new JavaObject(runtime, value);
074: } else if (value.getClass().isArray()) {
075: wrapper = new JavaArray(runtime, value);
076: } else if (value.getClass().equals(Class.class)) {
077: wrapper = JavaClass.get(runtime, (Class) value);
078: } else {
079: wrapper = new JavaObject(runtime, value);
080: }
081: runtime.getJavaSupport()
082: .putJavaObjectIntoCache(wrapper);
083: }
084: return wrapper;
085: }
086: }
087:
088: public Class getJavaClass() {
089: return value != null ? value.getClass() : Void.TYPE;
090: }
091:
092: public Object getValue() {
093: return value;
094: }
095:
096: public static RubyClass createJavaObjectClass(Ruby runtime,
097: RubyModule javaModule) {
098: // FIXME: Ideally JavaObject instances should be marshallable, which means that
099: // the JavaObject metaclass should have an appropriate allocator. JRUBY-414
100: RubyClass result = javaModule.defineClassUnder("JavaObject",
101: runtime.getObject(),
102: ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
103:
104: registerRubyMethods(runtime, result);
105:
106: result.getMetaClass().undefineMethod("new");
107: result.getMetaClass().undefineMethod("allocate");
108:
109: result.setMarshal(ObjectMarshal.NOT_MARSHALABLE_MARSHAL);
110:
111: return result;
112: }
113:
114: protected static void registerRubyMethods(Ruby runtime,
115: RubyClass result) {
116: CallbackFactory callbackFactory = runtime
117: .callbackFactory(JavaObject.class);
118:
119: result.defineFastMethod("to_s", callbackFactory
120: .getFastMethod("to_s"));
121: result.defineFastMethod("==", callbackFactory.getFastMethod(
122: "equal", IRubyObject.class));
123: result.defineFastMethod("eql?", callbackFactory.getFastMethod(
124: "equal", IRubyObject.class));
125: result.defineFastMethod("equal?", callbackFactory
126: .getFastMethod("same", IRubyObject.class));
127: result.defineFastMethod("hash", callbackFactory
128: .getFastMethod("hash"));
129: result.defineFastMethod("java_type", callbackFactory
130: .getFastMethod("java_type"));
131: result.defineFastMethod("java_class", callbackFactory
132: .getFastMethod("java_class"));
133: result.defineFastMethod("java_proxy?", callbackFactory
134: .getFastMethod("is_java_proxy"));
135: result.defineMethod("synchronized", callbackFactory
136: .getMethod("ruby_synchronized"));
137: result.defineFastMethod("length", callbackFactory
138: .getFastMethod("length"));
139: result.defineFastMethod("[]", callbackFactory.getFastMethod(
140: "aref", IRubyObject.class));
141: result.defineFastMethod("[]=", callbackFactory.getFastMethod(
142: "aset", IRubyObject.class, IRubyObject.class));
143: result.defineFastMethod("fill", callbackFactory.getFastMethod(
144: "afill", IRubyObject.class, IRubyObject.class,
145: IRubyObject.class));
146: }
147:
148: public RubyFixnum hash() {
149: return getRuntime().newFixnum(
150: value == null ? 0 : value.hashCode());
151: }
152:
153: public IRubyObject to_s() {
154: String s = value == null ? "" : value.toString();
155:
156: return s == null ? getRuntime().getNil() : RubyString
157: .newUnicodeString(getRuntime(), s);
158: }
159:
160: public IRubyObject equal(IRubyObject other) {
161: if (!(other instanceof JavaObject)) {
162: other = other.getInstanceVariable("@java_object");
163: if (!(other instanceof JavaObject)) {
164: return getRuntime().getFalse();
165: }
166: }
167:
168: if (getValue() == null
169: && ((JavaObject) other).getValue() == null) {
170: return getRuntime().getTrue();
171: }
172:
173: boolean isEqual = getValue().equals(
174: ((JavaObject) other).getValue());
175: return isEqual ? getRuntime().getTrue() : getRuntime()
176: .getFalse();
177: }
178:
179: public IRubyObject same(IRubyObject other) {
180: if (!(other instanceof JavaObject)) {
181: other = other.getInstanceVariable("@java_object");
182: if (!(other instanceof JavaObject)) {
183: return getRuntime().getFalse();
184: }
185: }
186:
187: if (getValue() == null
188: && ((JavaObject) other).getValue() == null) {
189: return getRuntime().getTrue();
190: }
191:
192: boolean isSame = getValue() == ((JavaObject) other).getValue();
193: return isSame ? getRuntime().getTrue() : getRuntime()
194: .getFalse();
195: }
196:
197: public RubyString java_type() {
198: return getRuntime().newString(getJavaClass().getName());
199: }
200:
201: public IRubyObject java_class() {
202: return JavaClass.get(getRuntime(), getJavaClass());
203: }
204:
205: public RubyFixnum length() {
206: throw getRuntime().newTypeError("not a java array");
207: }
208:
209: public IRubyObject aref(IRubyObject index) {
210: throw getRuntime().newTypeError("not a java array");
211: }
212:
213: public IRubyObject aset(IRubyObject index, IRubyObject someValue) {
214: throw getRuntime().newTypeError("not a java array");
215: }
216:
217: public IRubyObject afill(IRubyObject beginIndex,
218: IRubyObject endIndex, IRubyObject someValue) {
219: throw getRuntime().newTypeError("not a java array");
220: }
221:
222: public IRubyObject is_java_proxy() {
223: return getRuntime().getTrue();
224: }
225:
226: public IRubyObject ruby_synchronized(Block block) {
227: Object lock = getValue();
228: synchronized (lock != null ? lock : NULL_LOCK) {
229: return block.yield(getRuntime().getCurrentContext(), null);
230: }
231: }
232: }
|