001: /*
002: * Sun Public License Notice
003: *
004: * The contents of this file are subject to the Sun Public License
005: * Version 1.0 (the "License"). You may not use this file except in
006: * compliance with the License. A copy of the License is available at
007: * http://www.sun.com/
008: *
009: * The Original Code is NetBeans. The Initial Developer of the Original
010: * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
011: * Microsystems, Inc. All Rights Reserved.
012: */
013:
014: package org.netbeans.editor.ext.java;
015:
016: import java.awt.Component;
017: import java.io.IOException;
018: import java.lang.reflect.Modifier;
019: import java.text.MessageFormat;
020: import java.util.ArrayList;
021: import java.util.HashMap;
022: import java.util.Iterator;
023:
024: import javax.swing.JOptionPane;
025:
026: import org.netbeans.editor.LocaleSupport;
027: import org.netbeans.editor.Utilities;
028: import org.netbeans.editor.ext.FileStorage;
029: import org.netbeans.editor.ext.StringCache;
030:
031: /**
032: * Java completion resolver that operates over two files. One is skeleton file
033: * and it's read at once during the build() methods. The other file is class
034: * body file and it's read lazily as necessary.
035: *
036: * File structures: Skeleton file: class skeletons: String: class name String:
037: * package name int: body seek offset int: body len
038: *
039: * Body file: class bodies: int: modifiers String: super class name String:
040: * super class package name int: field count field count * field body field
041: * body: !!! dodelat
042: *
043: *
044: *
045: * @author Miloslav Metelka
046: * @version 1.00
047: */
048:
049: public class JCFileProvider extends JavaCompletion.AbstractProvider {
050:
051: /** Version of parser DB file */
052: static final int VERSION = 2;
053:
054: static final int OPCODE_ADD = 1; // adding new class
055:
056: public static final String SKEL_FILE_EXT = "jcs"; // NOI18N
057: public static final String BODY_FILE_EXT = "jcb"; // NOI18N
058:
059: /** Global cache saving the string creations */
060: private static final StringCache strCache = new StringCache(200,
061: 5003);
062:
063: static {
064: // pre-cache standard strings
065: strCache.putSurviveString(""); // NOI18N
066: Iterator i = JavaCompletion.getPrimitiveClassIterator();
067: while (i.hasNext()) {
068: strCache.putSurviveString(((JCClass) i.next()).getName());
069: }
070: }
071:
072: FileStorage skels;
073:
074: FileStorage bodies;
075:
076: HashMap classes;
077:
078: int fileVersion;
079:
080: public JCFileProvider(String fileNamePrefix) {
081: this (fileNamePrefix + "." + SKEL_FILE_EXT, fileNamePrefix + "."
082: + BODY_FILE_EXT);
083: }
084:
085: public JCFileProvider(String fileNameSkels, String fileNameBodies) {
086: skels = new FileStorage(fileNameSkels, strCache);
087: bodies = new FileStorage(fileNameBodies, strCache);
088: }
089:
090: public synchronized void reset() {
091: boolean passedOK = false;
092: try {
093: skels.resetFile();
094: bodies.resetFile();
095:
096: // write version to skels
097: skels.open(true);
098: skels.setVersion(1);
099: skels.putInteger(VERSION);
100: fileVersion = VERSION;
101: setVersion(fileVersion);
102: skels.write();
103: skels.close();
104:
105: // write version to bodies
106: if (VERSION > 1) {
107: bodies.open(true);
108: bodies.setVersion(1);
109: bodies.putInteger(VERSION);
110: setVersion(fileVersion);
111: bodies.write();
112: bodies.close();
113: }
114:
115: passedOK = true;
116: } catch (IOException e) {
117: e.printStackTrace();
118: } finally {
119: if (passedOK == false) {
120: // some error occured, we have to reset unwritten bytes.
121: skels.resetBytes();
122: bodies.resetBytes();
123: }
124: }
125: }
126:
127: private void setVersion(int ver) {
128: skels.setVersion(ver);
129: bodies.setVersion(ver);
130: }
131:
132: protected boolean appendClass(JCClass c) {
133: try {
134: skels.putInteger(OPCODE_ADD);
135: writeClass(c);
136: skels.write();
137: bodies.write();
138: } catch (IOException e) {
139: e.printStackTrace();
140: return false;
141: }
142: return true;
143: }
144:
145: public synchronized boolean append(JCClassProvider cp) {
146: boolean passedOK = false;
147: try {
148: if (skels.getFileLength() <= 0) { // reset if necessary
149: reset();
150: }
151:
152: skels.open(true);
153: bodies.open(true);
154:
155: if (!super .append(cp)) {
156: return false;
157: }
158:
159: passedOK = true;
160:
161: } catch (IOException e) {
162: e.printStackTrace();
163: return false;
164: } catch (ThreadDeath td) {
165: throw td;
166: } catch (Throwable t) {
167: System.err
168: .println("Error occurred during updating parser DB: "
169: + this ); // NOI18N
170: t.printStackTrace();
171: if (t instanceof OutOfMemoryError)
172: throw (OutOfMemoryError) t;
173: return false;
174: } finally {
175: boolean ok = true;
176: try {
177: skels.close();
178: } catch (IOException e) {
179: e.printStackTrace();
180: ok = false;
181: }
182:
183: try {
184: bodies.close();
185: } catch (IOException e) {
186: e.printStackTrace();
187: ok = false;
188: }
189:
190: if ((passedOK == false) || (ok == false)) {
191: // some error occured, we have to reset unwritten bytes.
192: skels.resetBytes();
193: bodies.resetBytes();
194: }
195: passedOK = ok;
196: }
197: return passedOK;
198: }
199:
200: public synchronized Iterator getClasses() {
201: int skelsFileLen;
202: try {
203: skels.open(false);
204: skels.seek(0);
205: skelsFileLen = skels.getFileLength();
206: if (skelsFileLen < 4) { // file exists but was not reset
207: // reset();
208: return new ArrayList().iterator(); // return empty iterator
209: }
210: skels.read(skelsFileLen);
211: } catch (IOException e) {
212: if (!skels.fileNotFound) { // show this info only once for
213: // appropriate file.
214: JOptionPane.showMessageDialog((Component) Utilities
215: .getLastActiveComponent(), MessageFormat
216: .format(LocaleSupport
217: .getString("pd-file-not-found"), // NOI18N
218: new Object[] { bodies.toString() }),
219: LocaleSupport
220: .getString("pd-file-not-found-title"), // NOI18N
221: JOptionPane.WARNING_MESSAGE);
222: skels.fileNotFound = true;
223: }
224: return new ArrayList().iterator();
225: } finally {
226: try {
227: skels.close();
228: } catch (IOException e) {
229: e.printStackTrace();
230: }
231: }
232: setVersion(1); // Version of file is always saved in version 1 encoding
233: fileVersion = skels.getInteger();
234: setVersion(fileVersion);
235:
236: ArrayList clsList = new ArrayList();
237: while (skels.getOffset() < skelsFileLen) { // till the last class
238: int opcode = skels.getInteger();
239: if (opcode == OPCODE_ADD) {
240: Cls cls = new Cls();
241: clsList.add(cls);
242: if (cls.fullName
243: .equals(JavaCompletion.OBJECT_CLASS.fullName)) {
244: // make clone of Object and add a new public final int
245: // length field into it
246: clsList.add(cls.makeClone());
247: }
248: } else {
249: break; // Unsupported operation code
250: }
251: }
252:
253: skels.resetBytes(); // GC possibly large skels bytes array
254: return clsList.iterator();
255: }
256:
257: void writeClass(JCClass c) throws IOException {
258: // write body
259: bodies.putInteger(c.getTagOffset());
260: writeClassName(c.getSuperclass(), bodies);
261:
262: // Write implemented interfaces
263: JCClass[] interfaces = c.getInterfaces();
264: bodies.putInteger(interfaces.length);
265: for (int i = 0; i < interfaces.length; i++) {
266: writeClassName(interfaces[i], bodies);
267: }
268:
269: // Write declared fields
270: JCField[] fields = c.getFields();
271: bodies.putInteger(fields.length);
272: for (int i = 0; i < fields.length; i++) {
273: writeField(fields[i]);
274: }
275:
276: // Write constructors
277: JCConstructor[] constructors = c.getConstructors();
278: bodies.putInteger(constructors.length);
279: for (int i = 0; i < constructors.length; i++) {
280: writeConstructor(constructors[i]);
281: }
282:
283: // Write methods
284: JCMethod[] methods = c.getMethods();
285: bodies.putInteger(methods.length);
286: for (int i = 0; i < methods.length; i++) {
287: writeMethod(methods[i]);
288: }
289:
290: // write skeleton
291: writeClassName(c, skels);
292: int modifiers = c.getModifiers();
293: if (c.isInterface()) {
294: modifiers |= JavaCompletion.INTERFACE_BIT;
295: }
296: skels.putInteger(modifiers);
297:
298: skels.putInteger(bodies.getFilePointer());
299: skels.putInteger(bodies.getOffset());
300: /*
301: * Cls updatedCls = new Cls(c, bodies.getFilePointer(),
302: * bodies.getOffset()); if (updatedCls!=null){ // update class in memory
303: * JavaCompletion.getFinder().append(new
304: * JavaCompletion.SingleProvider(updatedCls)); }
305: */
306: }
307:
308: void writeType(JCType t) {
309: writeClassName(t.getClazz(), bodies);
310: bodies.putInteger(t.getArrayDepth());
311: }
312:
313: void writeParameter(JCParameter p) {
314: bodies.putString(p.getName());
315: writeType(p.getType());
316: }
317:
318: void writeField(JCField f) {
319: bodies.putString(f.getName());
320: writeType(f.getType());
321: bodies.putInteger(f.getTagOffset());
322: bodies.putInteger(f.getModifiers());
323: }
324:
325: void writeConstructor(JCConstructor c) {
326: bodies.putInteger(c.getTagOffset());
327: bodies.putInteger(c.getModifiers());
328:
329: JCParameter[] parameters = c.getParameters();
330: bodies.putInteger(parameters.length);
331: for (int i = 0; i < parameters.length; i++) {
332: writeParameter(parameters[i]);
333: }
334:
335: JCClass[] exceptions = c.getExceptions();
336: bodies.putInteger(exceptions.length);
337: for (int i = 0; i < exceptions.length; i++) {
338: writeClassName(exceptions[i], bodies);
339: }
340: }
341:
342: void writeMethod(JCMethod m) {
343: writeConstructor(m);
344: bodies.putString(m.getName());
345: writeType(m.getReturnType());
346: }
347:
348: /** Write name and package of the given class */
349: void writeClassName(JCClass c, FileStorage fs) {
350: fs.putString(c.getFullName());
351: fs.putInteger(c.getPackageName().length());
352: }
353:
354: private JCClass getSimpleClass(String fullName, int packageNameLen) {
355: JCClass c = null;
356: if (packageNameLen == 0) {
357: c = JavaCompletion.getPrimitiveClass(fullName);
358: }
359: if (c == null) {
360: String fullNameIntern = fullName.intern();
361: if (fullName != fullNameIntern) { // update cache with interned
362: // string
363: strCache.putSurviveString(fullNameIntern);
364: }
365: c = JavaCompletion.getSimpleClass(fullNameIntern,
366: packageNameLen);
367: }
368: return c;
369: }
370:
371: JCClass readSimpleClass(FileStorage fs) {
372: String fullName = fs.getString();
373: int packageNameLen = fs.getInteger();
374: return getSimpleClass(fullName, packageNameLen);
375: }
376:
377: final class Cls extends JavaCompletion.AbstractClass {
378:
379: /** Seek position in the file of the class body */
380: int bodySeekPointer;
381:
382: /** Length of the class body in the file */
383: int bodyLen;
384:
385: /** A flag determining whether this class is an interface */
386: boolean isInterface = false;
387:
388: public Cls() {
389: JCClass c = readSimpleClass(skels);
390: fullName = c.getFullName();
391: name = c.getName();
392: packageName = c.getPackageName();
393: modifiers = skels.getInteger();
394: bodySeekPointer = skels.getInteger();
395: bodyLen = skels.getInteger();
396: }
397:
398: public Cls(JCClass c, int seekPointer, int len) {
399: fullName = c.getFullName();
400: name = c.getName();
401: packageName = c.getPackageName();
402: modifiers = c.getModifiers();
403: isInterface = c.isInterface();
404: bodySeekPointer = seekPointer;
405: bodyLen = len;
406: }
407:
408: /** Fill clone with new parameters. Add a public final int length to it */
409: private Cls(Cls original) {
410: this .fullName = JavaCompletion.OBJECT_CLASS_ARRAY.fullName;
411: this .name = JavaCompletion.OBJECT_CLASS_ARRAY.name;
412: this .packageName = JavaCompletion.OBJECT_CLASS_ARRAY.packageName;
413: this .body = new Body();
414: original.init();
415: this .body.super Class = original.body.super Class;
416: this .body.interfaces = original.body.interfaces;
417: this .body.constructors = original.body.constructors;
418: this .body.methods = original.body.methods;
419: this .body.fields = new JCField[1];
420: this .body.fields[0] = new JavaCompletion.BaseField(
421: this ,
422: "length", // NOI18N
423: JavaCompletion.INT_TYPE,
424: (Modifier.PUBLIC | Modifier.FINAL));
425: }
426:
427: public boolean isInterface() {
428: if (isInterface) {
429: return true;
430: } else {
431: return super .isInterface();
432: }
433: }
434:
435: /** makeClone of java.lang.Object */
436: public Cls makeClone() {
437: return new Cls(this );
438: }
439:
440: /** Init internal representation */
441: protected void init() {
442: synchronized (JCFileProvider.this ) {
443: body = new Body();
444: // set the right seek position and read
445: try {
446: bodies.open(false);
447: bodies.seek(bodySeekPointer);
448: bodies.read(bodyLen);
449: bodies.close();
450: } catch (IOException e) {
451: if (!bodies.fileNotFound) { // show this info only once for
452: // appropriate file.
453: JOptionPane
454: .showMessageDialog(
455: (Component) Utilities
456: .getLastActiveComponent(),
457: MessageFormat
458: .format(
459: LocaleSupport
460: .getString("pd-file-not-found"), // NOI18N
461: new Object[] { bodies
462: .toString() }),
463: LocaleSupport
464: .getString("pd-file-not-found-title"), // NOI18N
465: JOptionPane.WARNING_MESSAGE);
466: bodies.fileNotFound = true;
467: skels.fileNotFound = true;
468: }
469: body.tagOffset = -1;
470: body.super Class = JavaCompletion.INVALID_CLASS;
471: body.interfaces = JavaCompletion.EMPTY_CLASSES;
472: body.fields = JavaCompletion.EMPTY_FIELDS;
473: body.constructors = JavaCompletion.EMPTY_CONSTRUCTORS;
474: body.methods = JavaCompletion.EMPTY_METHODS;
475: return;
476: }
477:
478: body.tagOffset = bodies.getInteger();
479: body.super Class = readSimpleClass(bodies);
480:
481: int cnt = bodies.getInteger();
482: body.interfaces = (cnt > 0) ? new JCClass[cnt]
483: : JavaCompletion.EMPTY_CLASSES;
484: for (int i = 0; i < cnt; i++) {
485: body.interfaces[i] = readSimpleClass(bodies);
486: }
487:
488: cnt = bodies.getInteger();
489: body.fields = (cnt > 0) ? new JCField[cnt]
490: : JavaCompletion.EMPTY_FIELDS;
491: for (int i = 0; i < cnt; i++) {
492: body.fields[i] = new Fld(this );
493: }
494:
495: cnt = bodies.getInteger();
496: body.constructors = (cnt > 0) ? new JCConstructor[cnt]
497: : JavaCompletion.EMPTY_CONSTRUCTORS;
498: for (int i = 0; i < cnt; i++) {
499: body.constructors[i] = new Ctr(this );
500: }
501:
502: cnt = bodies.getInteger();
503: body.methods = (cnt > 0) ? new JCMethod[cnt]
504: : JavaCompletion.EMPTY_METHODS;
505: for (int i = 0; i < cnt; i++) {
506: body.methods[i] = new Mtd(this );
507: }
508:
509: try {
510: bodies.close();
511: } catch (IOException e) {
512: e.printStackTrace();
513: }
514: }
515: }
516:
517: }
518:
519: final class Typ extends JavaCompletion.BaseType {
520:
521: Typ() {
522: clazz = readSimpleClass(bodies);
523: arrayDepth = bodies.getInteger();
524: }
525:
526: }
527:
528: /** Description of the declared field */
529: final class Fld extends JavaCompletion.BaseField {
530:
531: Fld(JCClass clazz) {
532: this .clazz = clazz;
533: name = bodies.getString();
534: type = new Typ();
535: tagOffset = bodies.getInteger();
536: modifiers = bodies.getInteger();
537: }
538:
539: }
540:
541: private void readBC(JavaCompletion.BaseConstructor bc) {
542: bc.tagOffset = bodies.getInteger();
543: bc.modifiers = bodies.getInteger();
544:
545: int cnt = bodies.getInteger();
546: bc.parameters = (cnt > 0) ? new JCParameter[cnt]
547: : JavaCompletion.EMPTY_PARAMETERS;
548: for (int i = 0; i < cnt; i++) {
549: bc.parameters[i] = new Prm();
550: }
551:
552: cnt = bodies.getInteger();
553: bc.exceptions = (cnt > 0) ? new JCClass[cnt]
554: : JavaCompletion.EMPTY_CLASSES;
555: for (int i = 0; i < cnt; i++) {
556: bc.exceptions[i] = readSimpleClass(bodies);
557: }
558: }
559:
560: /** Read constructor */
561: final class Ctr extends JavaCompletion.BaseConstructor {
562:
563: Ctr(JCClass clazz) {
564: this .clazz = clazz;
565: readBC(this );
566: }
567:
568: }
569:
570: /** Read method */
571: final class Mtd extends JavaCompletion.BaseMethod {
572:
573: Mtd(JCClass clazz) {
574: this .clazz = clazz;
575: readBC(this );
576:
577: name = bodies.getString();
578: returnType = new Typ();
579:
580: }
581:
582: }
583:
584: /** Description of the method parameter */
585: public class Prm extends JavaCompletion.BaseParameter {
586:
587: Prm() {
588: name = bodies.getString();
589: type = new Typ();
590: }
591:
592: }
593:
594: public String toString() {
595: return "Skeleton: " + skels + " , Body: " + bodies;
596: // return "strCache=" + strCache; // NOI18N
597: }
598:
599: }
|