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.Quercus;
033: import com.caucho.quercus.QuercusException;
034: import com.caucho.quercus.program.AbstractFunction;
035: import com.caucho.quercus.program.ClassDef;
036: import com.caucho.quercus.program.UnsetFunction;
037: import com.caucho.util.Crc64;
038: import com.caucho.util.L10N;
039: import com.caucho.util.LruCache;
040:
041: import java.lang.ref.SoftReference;
042: import java.lang.ref.WeakReference;
043: import java.util.ArrayList;
044: import java.util.Collections;
045: import java.util.HashMap;
046: import java.util.logging.Logger;
047:
048: /**
049: * Represents the state of the definitions: functions, classes and
050: * constants.
051: */
052: public final class DefinitionState {
053: private static final L10N L = new L10N(DefinitionState.class);
054: private static final Logger log = Logger
055: .getLogger(DefinitionState.class.getName());
056:
057: private static final LruCache<ClassKey, SoftReference<QuercusClass>> _classCache = new LruCache<ClassKey, SoftReference<QuercusClass>>(
058: 4096);
059:
060: private final Quercus _quercus;
061:
062: private boolean _isStrict;
063:
064: private HashMap<String, AbstractFunction> _funMap;
065:
066: private HashMap<String, AbstractFunction> _lowerFunMap;
067:
068: private HashMap<String, ClassDef> _classDefMap;
069:
070: private HashMap<String, ClassDef> _lowerClassDefMap;
071:
072: private boolean _isLazy;
073:
074: // crc of the entries
075: private long _crc;
076:
077: public DefinitionState(Quercus quercus) {
078: _quercus = quercus;
079:
080: _isStrict = quercus.isStrict();
081:
082: _funMap = new HashMap<String, AbstractFunction>(256, 0.25F);
083: _classDefMap = new HashMap<String, ClassDef>(256, 0.25F);
084:
085: if (!_isStrict) {
086: _lowerFunMap = new HashMap<String, AbstractFunction>(256,
087: 0.25F);
088:
089: _lowerClassDefMap = new HashMap<String, ClassDef>(256,
090: 0.25F);
091: }
092: }
093:
094: private DefinitionState(DefinitionState oldState) {
095: this (oldState._quercus);
096:
097: _funMap.putAll(oldState._funMap);
098:
099: if (_lowerFunMap != null)
100: _lowerFunMap.putAll(oldState._lowerFunMap);
101:
102: _classDefMap.putAll(oldState._classDefMap);
103:
104: if (_lowerClassDefMap != null)
105: _lowerClassDefMap.putAll(oldState._lowerClassDefMap);
106:
107: _crc = oldState._crc;
108: }
109:
110: private DefinitionState(DefinitionState oldState, boolean isLazy) {
111: _isLazy = true;
112:
113: _quercus = oldState._quercus;
114: _isStrict = oldState._isStrict;
115:
116: _funMap = oldState._funMap;
117: _lowerFunMap = oldState._lowerFunMap;
118:
119: _classDefMap = oldState._classDefMap;
120: _lowerClassDefMap = oldState._lowerClassDefMap;
121:
122: _crc = oldState._crc;
123: }
124:
125: /**
126: * Returns true for strict mode.
127: */
128: public final boolean isStrict() {
129: return _isStrict;
130: }
131:
132: /**
133: * Returns the owning PHP engine.
134: */
135: public Quercus getQuercus() {
136: return _quercus;
137: }
138:
139: /**
140: * returns the crc.
141: */
142: public long getCrc() {
143: return _crc;
144: }
145:
146: /**
147: * Returns an array of the defined functions.
148: */
149: public ArrayValue getDefinedFunctions() {
150: ArrayValue result = new ArrayValueImpl();
151:
152: ArrayValue internal = _quercus.getDefinedFunctions();
153: ArrayValue user = new ArrayValueImpl();
154:
155: // XXX: i18n
156: result.put(new StringBuilderValue("internal"), internal);
157: result.put(new StringBuilderValue("user"), user);
158:
159: for (String name : _funMap.keySet()) {
160: StringValue key = new StringBuilderValue(name);
161:
162: if (!internal.contains(key).isset())
163: user.put(name);
164: }
165:
166: return result;
167: }
168:
169: /**
170: * Finds the java reflection method for the function with the given name.
171: *
172: * @param name the method name
173: * @return the found method or null if no method found.
174: */
175: public AbstractFunction findFunction(String name) {
176: AbstractFunction fun = _funMap.get(name);
177:
178: if (fun == null) {
179: } else if (fun instanceof UnsetFunction) {
180: UnsetFunction unsetFun = (UnsetFunction) fun;
181:
182: if (_crc == unsetFun.getCrc())
183: return null;
184: } else {
185: return fun;
186: }
187:
188: if (_lowerFunMap != null) {
189: fun = _lowerFunMap.get(name.toLowerCase());
190:
191: if (fun != null) {
192: // copyOnWrite();
193: _funMap.put(name, fun);
194:
195: return fun;
196: }
197: }
198:
199: fun = findModuleFunction(name);
200:
201: if (fun != null) {
202: // copyOnWrite();
203: _funMap.put(name, fun);
204:
205: return fun;
206: } else {
207: // copyOnWrite();
208: _funMap.put(name, new UnsetFunction(_crc));
209:
210: return null;
211: }
212: }
213:
214: /**
215: * Finds the java reflection method for the function with the given name.
216: *
217: * @param name the method name
218: * @return the found method or null if no method found.
219: */
220: private AbstractFunction findModuleFunction(String name) {
221: AbstractFunction fun = null;
222:
223: fun = _quercus.findFunction(name);
224: if (fun != null)
225: return fun;
226:
227: return fun;
228: }
229:
230: /**
231: * Adds a function, e.g. from an include.
232: */
233: public Value addFunction(String name, AbstractFunction fun) {
234: AbstractFunction oldFun = findFunction(name);
235:
236: if (oldFun != null) {
237: throw new QuercusException(L.l(
238: "can't redefine function {0}", name));
239: }
240:
241: copyOnWrite();
242: _funMap.put(name, fun);
243: _crc = Crc64.generate(_crc, name);
244:
245: if (_lowerFunMap != null)
246: _lowerFunMap.put(name.toLowerCase(), fun);
247:
248: return BooleanValue.TRUE;
249: }
250:
251: /**
252: * Adds a function from a compiled include
253: *
254: * @param name the function name, must be an intern() string
255: * @param lowerName the function name, must be an intern() string
256: */
257: public Value addFunction(String name, String lowerName,
258: AbstractFunction fun) {
259: // XXX: skip the old function check since the include for compiled
260: // pages is already verified. Might have a switch here?
261: /*
262: AbstractFunction oldFun = _lowerFunMap.get(lowerName);
263:
264: if (oldFun == null)
265: oldFun = _quercus.findLowerFunctionImpl(lowerName);
266:
267: if (oldFun != null) {
268: throw new QuercusException(L.l("can't redefine function {0}", name));
269: }
270: */
271:
272: copyOnWrite();
273: _funMap.put(name, fun);
274: _crc = Crc64.generate(_crc, name);
275:
276: if (_lowerFunMap != null)
277: _lowerFunMap.put(lowerName, fun);
278:
279: return BooleanValue.TRUE;
280: }
281:
282: /**
283: * Adds a class, e.g. from an include.
284: */
285: public void addClassDef(String name, ClassDef cl) {
286: copyOnWrite();
287: _classDefMap.put(name, cl);
288: _crc = Crc64.generate(_crc, name);
289:
290: if (_lowerClassDefMap != null)
291: _lowerClassDefMap.put(name.toLowerCase(), cl);
292: }
293:
294: /**
295: * Adds a class, e.g. from an include.
296: */
297: public ClassDef findClassDef(String name) {
298: ClassDef def = _classDefMap.get(name);
299:
300: if (def != null)
301: return def;
302:
303: if (_lowerClassDefMap != null)
304: def = _lowerClassDefMap.get(name.toLowerCase());
305:
306: return def;
307: }
308:
309: /**
310: * Returns the declared classes.
311: *
312: * @return an array of the declared classes()
313: */
314: public Value getDeclaredClasses(Env env) {
315: ArrayList<String> names = new ArrayList<String>();
316:
317: /*
318: for (String name : _classMap.keySet()) {
319: if (! names.contains(name))
320: names.add(name);
321: }
322: */
323:
324: for (String name : _classDefMap.keySet()) {
325: if (!names.contains(name))
326: names.add(name);
327: }
328:
329: for (String name : _quercus.getClassMap().keySet()) {
330: if (!names.contains(name))
331: names.add(name);
332: }
333:
334: Collections.sort(names);
335:
336: ArrayValue array = new ArrayValueImpl();
337:
338: for (String name : names) {
339: array.put(env.createString(name));
340: }
341:
342: return array;
343: }
344:
345: public DefinitionState copy() {
346: return new DefinitionState(this );
347: }
348:
349: public DefinitionState copyLazy() {
350: return new DefinitionState(this , true);
351: }
352:
353: private void copyOnWrite() {
354: if (!_isLazy)
355: return;
356:
357: _isLazy = false;
358:
359: _funMap = new HashMap<String, AbstractFunction>(_funMap);
360:
361: if (_lowerFunMap != null) {
362: _lowerFunMap = new HashMap<String, AbstractFunction>(
363: _lowerFunMap);
364: }
365:
366: _classDefMap = new HashMap<String, ClassDef>(_classDefMap);
367:
368: if (_lowerClassDefMap != null) {
369: _lowerClassDefMap = new HashMap<String, ClassDef>(
370: _lowerClassDefMap);
371: }
372: }
373:
374: static class ClassKey {
375: private final WeakReference<ClassDef> _defRef;
376: private final WeakReference<QuercusClass> _parentRef;
377:
378: ClassKey(ClassDef def, QuercusClass parent) {
379: _defRef = new WeakReference<ClassDef>(def);
380:
381: if (parent != null)
382: _parentRef = new WeakReference<QuercusClass>(parent);
383: else
384: _parentRef = null;
385: }
386:
387: public int hashCode() {
388: int hash = 37;
389:
390: ClassDef def = _defRef.get();
391:
392: QuercusClass parent = null;
393: if (_parentRef != null)
394: parent = _parentRef.get();
395:
396: if (def != null)
397: hash = 65521 * hash + def.hashCode();
398:
399: if (parent != null)
400: hash = 65521 * hash + parent.hashCode();
401:
402: return hash;
403: }
404:
405: public boolean equals(Object o) {
406: ClassKey key = (ClassKey) o;
407:
408: ClassDef aDef = _defRef.get();
409: ClassDef bDef = key._defRef.get();
410:
411: if (aDef != bDef)
412: return false;
413:
414: if (_parentRef == key._parentRef)
415: return true;
416:
417: else if (_parentRef != null && key._parentRef != null)
418: return _parentRef.get() == key._parentRef.get();
419:
420: else
421: return false;
422: }
423: }
424: }
|