001: // Copyright (c) 2006 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.expr;
005:
006: import gnu.mapping.*;
007: import gnu.bytecode.*;
008: import gnu.kawa.reflect.FieldLocation;
009: import gnu.text.*;
010:
011: public class ModuleInfo {
012: /** Next element in list head by {@link ModuleManager#modules}. */
013: public ModuleInfo nextModule() {
014: return next;
015: }
016:
017: ModuleInfo next;
018:
019: /** Name of class that implements module.
020: * Must be non-null unless we're currently compiling the module,
021: * in which case sourcePath and comp must both be non-null.
022: */
023: public String className;
024:
025: public Class moduleClass;
026:
027: /** The namespace URI associated with this module, or {@code null}.
028: * This is null for Scheme modules, but non-null for XQuery modules.
029: */
030: public String getNamespaceUri() {
031: return uri;
032: }
033:
034: public void setNamespaceUri(String uri) {
035: this .uri = uri;
036: }
037:
038: String uri;
039:
040: ModuleExp exp;
041: Compilation comp;
042:
043: public Compilation getCompilation() {
044: return comp;
045: }
046:
047: public void setCompilation(Compilation comp) {
048: comp.minfo = this ;
049: this .comp = comp;
050: ModuleExp mod = comp.mainLambda;
051: this .exp = mod;
052: if (mod != null) {
053: String fileName = mod.getFileName();
054: this .sourcePath = fileName;
055: Path abs = absPath(fileName);
056: this .sourceAbsPath = abs;
057: }
058: }
059:
060: public static Path absPath(String path) {
061: return Path.valueOf(path).getCanonical();
062: }
063:
064: ModuleInfo[] dependencies;
065: int numDependencies;
066:
067: /** Location of source for module, if known.
068: * This is an absolute URI, absolute filename,
069: * or filename relative to current working directory.
070: * Null if source not known; in that case className must be non-null.
071: */
072: public String sourcePath;
073: Path sourceAbsPath;
074: String sourceAbsPathname;
075:
076: public long lastCheckedTime;
077: public long lastModifiedTime;
078:
079: public Path getSourceAbsPath() {
080: return sourceAbsPath;
081: }
082:
083: public void setSourceAbsPath(Path path) {
084: sourceAbsPath = path;
085: sourceAbsPathname = null;
086: }
087:
088: public String getSourceAbsPathname() {
089: String str = sourceAbsPathname;
090: if (str == null && sourceAbsPath != null) {
091: str = sourceAbsPath.toString();
092: sourceAbsPathname = str;
093: }
094: return str;
095: }
096:
097: public synchronized void addDependency(ModuleInfo dep) {
098: if (dependencies == null)
099: dependencies = new ModuleInfo[8];
100: else if (numDependencies == dependencies.length) {
101: ModuleInfo[] deps = new ModuleInfo[2 * numDependencies];
102: System.arraycopy(dependencies, 0, deps, 0, numDependencies);
103: dependencies = deps;
104: }
105: dependencies[numDependencies++] = dep;
106: }
107:
108: public ClassType getClassType() {
109: if (moduleClass != null)
110: return (ClassType) Type.make(moduleClass);
111: if (comp != null && comp.mainClass != null)
112: return comp.mainClass;
113: return ClassType.make(className);
114: }
115:
116: public synchronized ModuleExp getModuleExp() {
117: ModuleExp m = exp;
118: if (m == null) {
119: if (comp != null)
120: return comp.mainLambda;
121: ClassType ctype = ClassType.make(className);
122: m = new ModuleExp();
123: m.type = ctype;
124: m.setName(ctype.getName());
125: m.flags |= ModuleExp.LAZY_DECLARATIONS;
126: m.info = this ;
127: exp = m;
128: }
129: return m;
130: }
131:
132: /** If module has LAZY_DECLARATIONS, fix that. */
133: public synchronized ModuleExp setupModuleExp() {
134: ModuleExp mod = getModuleExp();
135: if ((mod.flags & ModuleExp.LAZY_DECLARATIONS) == 0)
136: return mod;
137: mod.setFlag(false, ModuleExp.LAZY_DECLARATIONS);
138: ClassType type;
139: Class rclass;
140: if (moduleClass != null) {
141: rclass = moduleClass;
142: type = (ClassType) Type.make(rclass);
143: } else {
144: type = ClassType.make(className);
145: rclass = type.getReflectClass();
146: }
147: Object instance = null;
148:
149: Language language = Language.getDefaultLanguage();
150: for (Field fld = type.getFields(); fld != null; fld = fld
151: .getNext()) {
152: int flags = fld.getFlags();
153: if ((flags & Access.PUBLIC) == 0)
154: continue;
155: try {
156: if ((flags & Access.STATIC) == 0 && instance == null)
157: instance = getInstance();
158: Object fvalue = rclass.getField(fld.getName()).get(
159: instance);
160:
161: Declaration fdecl = language.declFromField(mod, fvalue,
162: fld);
163: if ((flags & Access.FINAL) != 0
164: && (!(fvalue instanceof gnu.mapping.Location) || fvalue instanceof FieldLocation))
165: fdecl.noteValue(new QuoteExp(fvalue));
166: else
167: fdecl.noteValue(null);
168: } catch (Exception ex) {
169: throw new WrappedException(ex);
170: }
171: }
172:
173: for (Declaration fdecl = mod.firstDecl(); fdecl != null; fdecl = fdecl
174: .nextDecl()) {
175: makeDeclInModule2(mod, fdecl);
176: }
177: return mod;
178: }
179:
180: public Class getModuleClass() throws ClassNotFoundException {
181: Class mclass = moduleClass;
182: if (mclass != null)
183: return mclass;
184: mclass = Class.forName(className);
185: moduleClass = mclass;
186: return mclass;
187: }
188:
189: public static ModuleInfo findFromInstance(Object instance) {
190: return ModuleContext.getContext().findFromInstance(instance);
191: }
192:
193: public static ModuleInfo find(String className) {
194: return ModuleManager.getInstance().findWithClassName(className);
195: }
196:
197: public static ModuleInfo find(Type type) {
198: ModuleInfo info = ModuleManager.getInstance()
199: .findWithClassName(type.getName());
200: if (type instanceof ObjectType
201: && ((ObjectType) type).isExisting()) {
202: try {
203: info.moduleClass = type.getReflectClass();
204: } catch (Exception ex) {
205: }
206: }
207: return info;
208: }
209:
210: public static void register(Object instance) {
211: Class clas = instance.getClass();
212: ModuleInfo info = find(clas.getName());
213: info.moduleClass = clas;
214: ModuleContext.getContext().setInstance(info, instance);
215: }
216:
217: public Object getInstance() {
218: return ModuleContext.getContext().findInstance(this );
219: }
220:
221: public Object getRunInstance() {
222: Object inst = getInstance();
223: if (inst instanceof Runnable)
224: ((Runnable) inst).run();
225: return inst;
226: }
227:
228: static void makeDeclInModule2(ModuleExp mod, Declaration fdecl) {
229: Object fvalue = fdecl.getConstantValue();
230: if (fvalue instanceof FieldLocation) {
231: FieldLocation floc = (FieldLocation) fvalue;
232: Declaration vdecl = floc.getDeclaration();
233: ReferenceExp fref = new ReferenceExp(vdecl);
234: fdecl.setAlias(true);
235: fref.setDontDereference(true);
236: fref.setFlag(ReferenceExp.CREATE_FIELD_REFERENCE);
237: fdecl.setValue(fref);
238: if (vdecl.isProcedureDecl())
239: fdecl.setProcedureDecl(true);
240: if (vdecl.getFlag(Declaration.IS_SYNTAX))
241: fdecl.setSyntax();
242: if (!fdecl.getFlag(Declaration.STATIC_SPECIFIED)) {
243: ClassType vtype = floc.getDeclaringClass();
244: String vname = vtype.getName();
245: for (Declaration xdecl = mod.firstDecl(); xdecl != null; xdecl = xdecl
246: .nextDecl()) {
247: if (vname.equals(xdecl.getType().getName())
248: && xdecl
249: .getFlag(Declaration.MODULE_REFERENCE)) {
250: fref.setContextDecl(xdecl);
251: break;
252: }
253: }
254: }
255: }
256: }
257:
258: public int getState() {
259: return comp == null ? Compilation.CLASS_WRITTEN : comp
260: .getState();
261: }
262:
263: public void loadByStages(int wantedState) {
264: int state = getState();
265: if (state + 1 >= wantedState)
266: return;
267: loadByStages(wantedState - 2);
268: state = getState();
269: if (state >= wantedState) // Most likely? if ERROR_SEEN.
270: return;
271: comp.setState(state + 1);
272: int ndeps = numDependencies;
273: for (int idep = 0; idep < ndeps; idep++) {
274: ModuleInfo dep = dependencies[idep];
275: dep.loadByStages(wantedState);
276: }
277: state = getState();
278: if (state >= wantedState) // Most likely? if ERROR_SEEN.
279: return;
280: comp.setState(state & ~1);
281: comp.process(wantedState);
282: }
283:
284: /** Eagerly process the module and dependencies.
285: * @return true on success; false if we were unable to because of
286: * an error or a cyclic dependency.
287: */
288: public boolean loadEager(int wantedState) {
289: if (comp == null && className != null)
290: return false;
291: int state = getState();
292: if (state >= wantedState)
293: return true;
294: if ((state & 1) != 0)
295: return false;
296: comp.setState(state + 1);
297: int ndeps = numDependencies;
298: for (int idep = 0; idep < ndeps; idep++) {
299: ModuleInfo dep = dependencies[idep];
300: if (!dep.loadEager(wantedState)) {
301: if (getState() == state + 1)
302: comp.setState(state);
303: return false;
304: }
305: }
306: if (getState() == state + 1)
307: comp.setState(state);
308: comp.process(wantedState);
309: return getState() == wantedState;
310: }
311:
312: public void clearClass() {
313: moduleClass = null;
314: numDependencies = 0;
315: dependencies = null;
316: }
317:
318: /** Check if this module and its dependencies are up-to-dete.
319: * Only checks the sourcePath's modification time if it is at least
320: * ModifiedCacheTime since last time we checked.
321: * As as side-effects update lastModifiedTime and lastCheckedTime.
322: */
323: public boolean checkCurrent(ModuleManager manager, long now) {
324: if (lastCheckedTime + manager.lastModifiedCacheTime >= now)
325: return true;
326: lastCheckedTime = now;
327: long lastModifiedTime = sourceAbsPath.getLastModified();
328: if (moduleClass == null && className != null) {
329: try {
330: moduleClass = ClassType.getContextClass(className);
331: } catch (ClassNotFoundException ex) {
332: this .lastModifiedTime = lastModifiedTime;
333: return false;
334: }
335: }
336: if (this .lastModifiedTime == 0 && moduleClass != null) {
337: String classFilename = className;
338: int dot = classFilename.lastIndexOf('.');
339: if (dot >= 0)
340: classFilename = classFilename.substring(dot + 1);
341: classFilename = classFilename + ".class";
342: java.net.URL resource = moduleClass
343: .getResource(classFilename);
344: if (resource != null) {
345: try {
346: this .lastModifiedTime = resource.openConnection()
347: .getLastModified();
348: } catch (java.io.IOException ex) {
349: resource = null;
350: }
351: }
352: if (resource == null) {
353: // Couldn't open timestand of the .class file.
354: // Assume it is current.
355: this .lastModifiedTime = lastModifiedTime;
356: return true;
357: }
358: }
359: if (className == null
360: || lastModifiedTime > this .lastModifiedTime) {
361: moduleClass = null;
362: this .lastModifiedTime = lastModifiedTime;
363: return false;
364: }
365: for (int i = numDependencies; --i >= 0;) {
366: ModuleInfo dep = dependencies[i];
367: if (!dep.checkCurrent(manager, now))
368: return false;
369: }
370: return true;
371: }
372:
373: public String toString() {
374: StringBuffer sbuf = new StringBuffer();
375: sbuf.append("ModuleInfo[");
376: if (moduleClass != null) {
377: sbuf.append("class: ");
378: sbuf.append(moduleClass);
379: } else if (className != null) {
380: sbuf.append("class-name: ");
381: sbuf.append(className);
382: }
383: sbuf.append(']');
384: return sbuf.toString();
385: }
386: }
|