001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.quercus.env;
031:
032: import com.caucho.quercus.Location;
033: import com.caucho.quercus.lib.ArrayModule;
034: import com.caucho.vfs.WriteStream;
035:
036: import java.io.IOException;
037: import java.util.IdentityHashMap;
038: import java.util.Iterator;
039: import java.util.Map;
040: import java.util.Set;
041: import java.util.TreeSet;
042:
043: /**
044: * Represents a Quercus object value.
045: */
046: abstract public class ObjectValue extends Value {
047: transient protected QuercusClass _quercusClass;
048:
049: protected ObjectValue(QuercusClass quercusClass) {
050: _quercusClass = quercusClass;
051: }
052:
053: protected void setQuercusClass(QuercusClass cl) {
054: _quercusClass = cl;
055: }
056:
057: public QuercusClass getQuercusClass() {
058: return _quercusClass;
059: }
060:
061: /**
062: * Returns the value's class name.
063: */
064: public String getClassName() {
065: return _quercusClass.getName();
066: }
067:
068: /**
069: * Returns a Set of entries.
070: */
071: // XXX: remove entrySet() and use getIterator() instead
072: abstract public Set<? extends Map.Entry<Value, Value>> entrySet();
073:
074: /**
075: * Returns the class name.
076: */
077: public String getName() {
078: return _quercusClass.getName();
079: }
080:
081: /**
082: * Returns the parent class
083: */
084: public String getParentClassName() {
085: return _quercusClass.getParentName();
086: }
087:
088: /**
089: * Returns true for an object.
090: */
091: @Override
092: public boolean isObject() {
093: return true;
094: }
095:
096: /**
097: * Returns the type.
098: */
099: @Override
100: public String getType() {
101: return "object";
102: }
103:
104: /**
105: * Converts to a boolean.
106: */
107: @Override
108: public boolean toBoolean() {
109: return true;
110: }
111:
112: /**
113: * Returns true for an implementation of a class
114: */
115: @Override
116: public boolean isA(String name) {
117: return _quercusClass.isA(name);
118: }
119:
120: /**
121: * Converts to a long.
122: */
123: @Override
124: public long toLong() {
125: return 1;
126: }
127:
128: /**
129: * Converts to a double.
130: */
131: @Override
132: public double toDouble() {
133: return toLong();
134: }
135:
136: //
137: // array delegate methods
138: //
139:
140: /**
141: * Returns the array value with the given key.
142: */
143: @Override
144: public Value get(Value key) {
145: ArrayDelegate delegate = _quercusClass.getArrayDelegate();
146:
147: // php/066q vs. php/0906
148: //return getField(null, key.toString());
149:
150: if (delegate != null)
151: return delegate.get(this , key);
152: else
153: return super .get(key);
154: //return Env.getInstance().error(L.l("Can't use object '{0}' as array",
155: // getName()));
156: }
157:
158: /**
159: * Sets the array value with the given key.
160: */
161: @Override
162: public Value put(Value key, Value value) {
163: ArrayDelegate delegate = _quercusClass.getArrayDelegate();
164:
165: // php/0d94
166:
167: if (delegate != null)
168: return delegate.put(this , key, value);
169: else
170: return super .put(key, value);
171: }
172:
173: /**
174: * Appends a new array value
175: */
176: @Override
177: public Value put(Value value) {
178: ArrayDelegate delegate = _quercusClass.getArrayDelegate();
179:
180: // php/0d94
181:
182: if (delegate != null)
183: return delegate.put(this , value);
184: else
185: return super .put(value);
186: }
187:
188: /**
189: * Return true if set
190: */
191: @Override
192: public boolean isset(Value key) {
193: ArrayDelegate delegate = _quercusClass.getArrayDelegate();
194:
195: if (delegate != null)
196: return delegate.isset(this , key);
197: else
198: return super .isset(key);
199: }
200:
201: /**
202: * Unsets the array value
203: */
204: @Override
205: public Value remove(Value key) {
206: ArrayDelegate delegate = _quercusClass.getArrayDelegate();
207:
208: if (delegate != null)
209: return delegate.unset(this , key);
210: else
211: return super .remove(key);
212: }
213:
214: //
215: // Foreach/Traversable functions
216: //
217:
218: /**
219: * Returns an iterator for the key => value pairs.
220: */
221: @Override
222: public Iterator<Map.Entry<Value, Value>> getIterator(Env env) {
223: TraversableDelegate delegate = _quercusClass
224: .getTraversableDelegate();
225:
226: if (delegate != null)
227: return delegate.getIterator(env, this );
228: else
229: return super .getIterator(env);
230: }
231:
232: /**
233: * Returns an iterator for the keys.
234: */
235: @Override
236: public Iterator<Value> getKeyIterator(Env env) {
237: TraversableDelegate delegate = _quercusClass
238: .getTraversableDelegate();
239:
240: if (delegate != null)
241: return delegate.getKeyIterator(env, this );
242: else
243: return super .getKeyIterator(env);
244: }
245:
246: /**
247: * Returns an iterator for the values.
248: */
249: @Override
250: public Iterator<Value> getValueIterator(Env env) {
251: TraversableDelegate delegate = _quercusClass
252: .getTraversableDelegate();
253:
254: if (delegate != null)
255: return delegate.getValueIterator(env, this );
256: else
257: return super .getValueIterator(env);
258: }
259:
260: //
261: // count delegate methods
262: //
263:
264: /**
265: * Returns the count value with the given key.
266: */
267: @Override
268: public int getCount(Env env) {
269: CountDelegate delegate = _quercusClass.getCountDelegate();
270:
271: // php/066q vs. php/0906
272: //return getField(null, key.toString());
273:
274: if (delegate != null)
275: return delegate.count(this );
276: else
277: return super .getSize();
278: }
279:
280: //
281: // Convenience field methods
282: //
283:
284: /**
285: * Adds a new value.
286: * @Deprecated
287: */
288: public Value putField(String key, String value) {
289: Env env = Env.getInstance();
290:
291: return putThisField(env, env.createString(key), env
292: .createString(value));
293: }
294:
295: /**
296: * Adds a new value.
297: */
298: public Value putField(Env env, String key, String value) {
299: return putThisField(env, env.createString(key), env
300: .createString(value));
301: }
302:
303: /**
304: * Adds a new value.
305: * @Deprecated
306: */
307: public Value putField(String key, long value) {
308: Env env = Env.getInstance();
309:
310: return putThisField(env, env.createString(key), LongValue
311: .create(value));
312: }
313:
314: /**
315: * Adds a new value.
316: */
317: public Value putField(Env env, String key, long value) {
318: return putThisField(env, env.createString(key), LongValue
319: .create(value));
320: }
321:
322: /**
323: * Adds a new value.
324: */
325: public Value putField(Env env, String key, Value value) {
326: return putThisField(env, env.createString(key), value);
327: }
328:
329: /**
330: * Initializes a new field, does not call __set if it is defined.
331: */
332: public void initField(StringValue key, Value value) {
333: putThisField(null, key, value);
334: }
335:
336: /**
337: * Adds a new value.
338: * @Deprecated
339: */
340: public Value putField(String key, double value) {
341: Env env = Env.getInstance();
342:
343: return putThisField(env, env.createString(key), DoubleValue
344: .create(value));
345: }
346:
347: /**
348: * Returns true for equality
349: */
350: @Override
351: public boolean eq(Value rValue) {
352: if (rValue.isObject())
353: return cmpObject((ObjectValue) rValue) == 0;
354: else
355: return super .eq(rValue);
356: }
357:
358: /**
359: * Compare two objects
360: */
361: public int cmpObject(ObjectValue rValue) {
362: if (rValue == this )
363: return 0;
364:
365: // if objects are not equal, then which object is greater is undefined
366:
367: int result = getName().compareTo(rValue.getName());
368:
369: if (result != 0)
370: return result;
371:
372: Set<? extends Map.Entry<Value, Value>> aSet = entrySet();
373: Set<? extends Map.Entry<Value, Value>> bSet = rValue.entrySet();
374:
375: if (aSet.equals(bSet))
376: return 0;
377: else if (aSet.size() > bSet.size())
378: return 1;
379: else if (aSet.size() < bSet.size())
380: return -1;
381: else {
382: TreeSet<Map.Entry<Value, Value>> aTree = new TreeSet<Map.Entry<Value, Value>>(
383: aSet);
384:
385: TreeSet<Map.Entry<Value, Value>> bTree = new TreeSet<Map.Entry<Value, Value>>(
386: bSet);
387:
388: Iterator<Map.Entry<Value, Value>> iterA = aTree.iterator();
389: Iterator<Map.Entry<Value, Value>> iterB = bTree.iterator();
390:
391: while (iterA.hasNext()) {
392: Map.Entry<Value, Value> a = iterA.next();
393: Map.Entry<Value, Value> b = iterB.next();
394:
395: result = a.getKey().cmp(b.getKey());
396:
397: if (result != 0)
398: return result;
399:
400: result = a.getValue().cmp(b.getValue());
401:
402: if (result != 0)
403: return result;
404: }
405:
406: // should never reach this
407: return 0;
408: }
409: }
410:
411: public void varDumpObject(Env env, WriteStream out, int depth,
412: IdentityHashMap<Value, String> valueSet) throws IOException {
413: out.println("object(" + getName() + ") (" + getSize() + ") {");
414:
415: ArrayValue sortedEntries = new ArrayValueImpl();
416:
417: Iterator<Map.Entry<Value, Value>> iter = getIterator(env);
418:
419: while (iter.hasNext()) {
420: Map.Entry<Value, Value> entry = iter.next();
421: sortedEntries.put(entry.getKey(), entry.getValue());
422: }
423:
424: ArrayModule.ksort(env, sortedEntries, ArrayModule.SORT_STRING);
425:
426: iter = sortedEntries.getIterator(env);
427:
428: while (iter.hasNext()) {
429: Map.Entry<Value, Value> entry = iter.next();
430:
431: Value key = entry.getKey();
432: Value value = entry.getValue();
433:
434: printDepth(out, 2 * depth);
435: out.println("[\"" + key + "\"]=>");
436:
437: depth++;
438:
439: printDepth(out, 2 * depth);
440:
441: value.varDump(env, out, depth, valueSet);
442:
443: out.println();
444:
445: depth--;
446: }
447:
448: printDepth(out, 2 * depth);
449:
450: out.print("}");
451: }
452: }
|