alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.editor.ext.java;

import java.awt.Component;
import java.io.Serializable;
import java.io.IOException;
import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.Modifier;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import javax.swing.JOptionPane;
import org.netbeans.editor.ext.StringCache;
import org.netbeans.editor.ext.FileStorage;
import org.netbeans.editor.LocaleSupport;
import org.netbeans.editor.Utilities;

/**
* Java completion resolver that operates over two files.
* One is skeleton file and it's read at once during 
* the build() methods. The other file is class body
* file and it's read lazily as necessary.
*
* File structures:
*   Skeleton file:
*     class skeletons:
*       String: class name
*       String: package name
*       int: body seek offset
*       int: body len
*
*   Body file:
*     class bodies:
*       int: modifiers
*       String: super class name
*       String: super class package name
*       int: field count
*       field count * field body
*         field body:
*           !!! dodelat
*               
*  
*
* @author Miloslav Metelka
* @version 1.00
*/

public class JCFileProvider extends JavaCompletion.AbstractProvider {

    /** Version of Code Completion DB file */
    static final int VERSION = 2;

    static final int OPCODE_ADD = 1; // adding new class
    static final int OPCODE_REMOVE = 2; // removing a class
    
    public static final String SKEL_FILE_EXT = "jcs"; // NOI18N
    public static final String BODY_FILE_EXT = "jcb"; // NOI18N

    /** Global cache saving the string creations */
    protected  static final StringCache strCache = new StringCache(200, 5003);
    
    // validity of the provider
    private boolean valid = true;

    static {
        // pre-cache standard strings
        strCache.putSurviveString(""); // NOI18N
        Iterator i = JavaCompletion.getPrimitiveClassIterator();
        while (i.hasNext()) {
            strCache.putSurviveString(((JCClass)i.next()).getName());
        }
    }

    protected FileStorage skels;

    protected FileStorage bodies;

    HashMap classes;

    int fileVersion;

    protected JCFileProvider(){
    }
    
    public JCFileProvider(String fileNamePrefix) {
        this(fileNamePrefix + "." + SKEL_FILE_EXT, // NOI18N
             fileNamePrefix + "." + BODY_FILE_EXT); // NOI18N
    }

    public JCFileProvider(String fileNameSkels, String fileNameBodies) {
        this(new FileStorage(fileNameSkels, strCache),
             new FileStorage(fileNameBodies, strCache));
    }
    public JCFileProvider(FileStorage skels, FileStorage bodies) {
        this.skels = skels;
        this.bodies = bodies;
    }

    

    /** Invalidates the FileProvider.*/
    public void invalidate(){
        valid = false;
    }
    
    public synchronized void reset() {
        boolean passedOK = false;
        try {
            skels.resetFile();
            bodies.resetFile();

            // write version to skels
            skels.open(true);
            skels.setVersion(1); 
            skels.putInteger(VERSION);
            fileVersion = VERSION;
            setVersion(fileVersion);
            skels.write();
            skels.close();

            // write version to bodies
            if (VERSION > 1){
                bodies.open(true);
                bodies.setVersion(1); 
                bodies.putInteger(VERSION);
                setVersion(fileVersion);
                bodies.write();
                bodies.close();
            }
            
            passedOK = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if (passedOK == false){
                // some error occured, we have to reset unwritten bytes.
                skels.resetBytes();
                bodies.resetBytes();
            }
        }
    }

    private void setVersion(int ver){
        skels.setVersion(ver);
        bodies.setVersion(ver);
    }
    
    protected boolean appendClass(JCClass c) {
        try {
            skels.putInteger(OPCODE_ADD);
            writeClass(c);
            skels.write();
            bodies.write();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    
    protected boolean removeClass(JCClass c) {
        try {
            skels.putInteger(OPCODE_REMOVE);
            skels.putString(c.toString());
            skels.write();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    
    public synchronized boolean remove(JCClassProvider cp) {
        boolean passedOK = false;
        boolean ok;
        try {
            if (skels.getFileLength() <= 0) { // reset if necessary
                reset();
            }

            skels.open(true);

            if (!super.remove(cp)) {
                return false;
            }
            
            passedOK = true;

        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } catch ( ThreadDeath td ) {
            throw td;
        } catch (Throwable t) {
            System.err.println("Error occurred during updating Code Completion DB: " + this); // NOI18N 
            t.printStackTrace();            
            if (t instanceof OutOfMemoryError) throw (OutOfMemoryError) t;            
            return false;
        } finally {
            ok = true;
            try {
                skels.close();
            } catch (IOException e) {
                e.printStackTrace();
                ok = false;
            }
            
            if ((passedOK == false) || (ok == false)) {
                // some error occured, we have to reset unwritten bytes.
                skels.resetBytes();
            }
        }
        
        return passedOK && ok;        
    }

    public synchronized boolean append(JCClassProvider cp) {
        boolean passedOK = false;
        boolean ok;
        try {
            if (skels.getFileLength() <= 0) { // reset if necessary
                reset();
            }

            skels.open(true);
            bodies.open(true);

            if (!super.append(cp)) {
                return false;
            }
            
            passedOK = true;

        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } catch ( ThreadDeath td ) {
            throw td;
        } catch (Throwable t) {
            System.err.println("Error occurred during updating Code Completion DB: " + this); // NOI18N 
            t.printStackTrace();            
            if (t instanceof OutOfMemoryError) throw (OutOfMemoryError) t;            
            return false;
        } finally {
            ok = true;
            try {
                skels.close();
            } catch (IOException e) {
                e.printStackTrace();
                ok = false;
            }

            try {
                bodies.close();
            } catch (IOException e) {
                e.printStackTrace();
                ok = false;
            }
            
            if ((passedOK == false) || (ok == false)) {
                // some error occured, we have to reset unwritten bytes.
                skels.resetBytes();
                bodies.resetBytes();
            }
        }
        return ok && passedOK;        
    }

    public synchronized Iterator getClasses() {
        int skelsFileLen;
        boolean opened = false;
        try {
            skels.open(false);
            opened = true;
            skels.seek(0);
            skelsFileLen = skels.getFileLength();
            if (skelsFileLen < 4) { // file exists but was not reset
                //                reset();
                return new ArrayList().iterator(); // return empty iterator
            }
            skels.read(skelsFileLen);
        } catch (IOException e) {
            if (!skels.fileNotFound){ // show this info only once for appropriate file.
                JOptionPane.showMessageDialog((Component)Utilities.getLastActiveComponent(),
                MessageFormat.format(
                LocaleSupport.getString( "pd-file-not-found" ), //NOI18N
                new Object[] {bodies.toString()}),
                LocaleSupport.getString( "pd-file-not-found-title" ), //NOI18N
                JOptionPane.WARNING_MESSAGE
                );
                skels.fileNotFound = true;
            }
            return new ArrayList().iterator();
        } finally {
            if (opened) {
                try {
                    skels.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        setVersion(1); // Version of file is always saved in version 1 encoding
        fileVersion = skels.getInteger();
        setVersion(fileVersion);

        ArrayList deletedClassesList = new ArrayList();
        HashSet clsSet = new HashSet(Math.max(skelsFileLen/38,16));   // avoid HashSet resing
        while (skels.getOffset() < skelsFileLen) { // till the last class
            int opcode = skels.getInteger();
            if (opcode == OPCODE_ADD) {
                Cls cls = new Cls();
                if (clsSet.add(cls) == false){
                    clsSet.remove(cls);
                    clsSet.add(cls);
                }
                deletedClassesList.remove(cls);
                
                if(cls.fullName.equals(JavaCompletion.OBJECT_CLASS.fullName)) {
                    // make clone of Object and add a new public final int length field into it
                    clsSet.add(cls.makeClone());
                }
            } else if (opcode == OPCODE_REMOVE){
                String removedClassName = skels.getString();
                JCClass removedClass = JavaCompletion.createSimpleClass(removedClassName);
                if (!deletedClassesList.contains(removedClassName))deletedClassesList.add(removedClass);
            } else {
                break; // Unsupported operation code
            } 
        }
        
        ArrayList allClassesList = new ArrayList(clsSet);
        allClassesList.removeAll(deletedClassesList);
        
        skels.resetBytes(); // GC possibly large skels bytes array
        return allClassesList.iterator();
    }
    
    void writeClass(JCClass c) throws IOException {
        // write body
        bodies.putInteger(c.getTagOffset());
        writeClassName(c.getSuperclass(), bodies);

        // Write implemented interfaces
        JCClass[] interfaces = c.getInterfaces();
        bodies.putInteger(interfaces.length);
        for (int i = 0; i < interfaces.length; i++) {
            writeClassName(interfaces[i], bodies);
        }

        // Write declared fields
        JCField[] fields = c.getFields();
        bodies.putInteger(fields.length);
        for (int i = 0; i < fields.length; i++) {
            writeField(fields[i]);
        }

        // Write constructors
        JCConstructor[] constructors = c.getConstructors();
        bodies.putInteger(constructors.length);
        for (int i = 0; i < constructors.length; i++) {
            writeConstructor(constructors[i]);
        }

        // Write methods
        JCMethod[] methods = c.getMethods();
        bodies.putInteger(methods.length);
        for (int i = 0; i < methods.length; i++) {
            writeMethod(methods[i]);
        }

        // write skeleton
        writeClassName(c, skels);
        int modifiers = c.getModifiers();
        /*if (c.isInterface()) {
            modifiers |= JavaCompletion.INTERFACE_BIT;
        }*/
        skels.putInteger(modifiers);

        skels.putInteger(bodies.getFilePointer());
        skels.putInteger(bodies.getOffset());
/*        
        Cls updatedCls = new Cls(c, bodies.getFilePointer(), bodies.getOffset());
        if (updatedCls!=null){
            // update class in memory
            JavaCompletion.getFinder().append(new JavaCompletion.SingleProvider(updatedCls));
        }
 */
    }

    void writeType(JCType t) {
        writeClassName(t.getClazz(), bodies);
        bodies.putInteger(t.getArrayDepth());
    }

    void writeParameter(JCParameter p) {
        bodies.putString(p.getName());
        writeType(p.getType());
    }

    void writeField(JCField f) {
        bodies.putString(f.getName());
        writeType(f.getType());
        bodies.putInteger(f.getTagOffset());
        bodies.putInteger(f.getModifiers());
    }

    void writeConstructor(JCConstructor c) {
        bodies.putInteger(c.getTagOffset());
        bodies.putInteger(c.getModifiers());

        JCParameter[] parameters = c.getParameters();
        bodies.putInteger(parameters.length);
        for (int i = 0; i < parameters.length; i++) {
            writeParameter(parameters[i]);
        }

        JCClass[] exceptions = c.getExceptions();
        bodies.putInteger(exceptions.length);
        for (int i = 0; i < exceptions.length; i++) {
            writeClassName(exceptions[i], bodies);
        }
    }

    void writeMethod(JCMethod m) {
        writeConstructor(m);
        bodies.putString(m.getName());
        writeType(m.getReturnType());
    }

    /** Write name and package of the given class */
    void writeClassName(JCClass c, FileStorage fs) {
        fs.putString(c.getFullName());
        fs.putInteger(c.getPackageName().length());
    }


    private JCClass getSimpleClass(String fullName, int packageNameLen, boolean addToCache) {
        JCClass c = null;
        if (packageNameLen == 0) {
            c = JavaCompletion.getPrimitiveClass(fullName);
        }
        if (c == null) {
            String fullNameIntern = fullName.intern();
            if (fullName != fullNameIntern) { // update cache with interned string
                strCache.putSurviveString(fullNameIntern);
            }
            if (fullNameIntern.length() > 0)
                c = (addToCache) ? JavaCompletion.getSimpleClass(fullNameIntern, packageNameLen):
                        new JavaCompletion.SimpleClass(fullNameIntern, packageNameLen, true);
            else
                c = JavaCompletion.INVALID_CLASS;
        }
        return c;
    }

    JCClass readSimpleClass(FileStorage fs, boolean addToCache) {
        String fullName = fs.getString();
        int packageNameLen = fs.getInteger();
        return getSimpleClass(fullName, packageNameLen, addToCache);
    }
    
    JCClass readSimpleClass(FileStorage fs) {
        return readSimpleClass(fs, true);
    }
    
    final class Cls extends JavaCompletion.AbstractClass {

        /** Seek position in the file of the class body */
        int bodySeekPointer;

        /** Length of the class body in the file */
        int bodyLen;
         
        /** A flag determining whether this class is an interface  */
        boolean isInterface = false; 
 
        public Cls() {
            JCClass c = readSimpleClass(skels, false);
            fullName = c.getFullName();
            name = c.getName();
            packageName = c.getPackageName();
            modifiers = skels.getInteger();
            bodySeekPointer = skels.getInteger();
            bodyLen = skels.getInteger();
        }
        
        public Cls(JCClass c, int seekPointer, int len){
            fullName = c.getFullName();
            name = c.getName();
            packageName = c.getPackageName();
            modifiers = c.getModifiers();
            isInterface = c.isInterface();            
            bodySeekPointer = seekPointer;
            bodyLen = len;
        }

        /** Fill clone with new parameters. Add a public final int length to it */
        private Cls(Cls original) {
            this.fullName = JavaCompletion.OBJECT_CLASS_ARRAY.fullName;
            this.name= JavaCompletion.OBJECT_CLASS_ARRAY.name;
            this.packageName = JavaCompletion.OBJECT_CLASS_ARRAY.packageName;
            this.body = new Body();
            original.init();
            this.body.superClass = original.body.superClass;
            this.body.interfaces = original.body.interfaces;
            this.body.constructors = original.body.constructors;
            this.body.methods = original.body.methods;
            this.body.fields = new JCField[1];
            this.body.fields[0] = new JavaCompletion.BaseField(this, "length", //NOI18N
            JavaCompletion.INT_TYPE, (Modifier.PUBLIC | Modifier.FINAL));
        }

        public boolean isInterface() {
            if (isInterface) {
                return true;
            } else {
                return super.isInterface();
            }
        }

        
        /** makeClone of java.lang.Object */
        public Cls makeClone() {
            return new Cls(this);
        }
        
        private void invalidateBody(){
            body.tagOffset = -1;
            body.superClass = JavaCompletion.INVALID_CLASS;
            body.interfaces = JavaCompletion.EMPTY_CLASSES;
            body.fields = JavaCompletion.EMPTY_FIELDS;
            body.constructors = JavaCompletion.EMPTY_CONSTRUCTORS;
            body.methods = JavaCompletion.EMPTY_METHODS;
        }

        /** Init internal representation */
        protected synchronized void init() {
            synchronized (JCFileProvider.this) {
                body = new Body();
                // set the right seek position and read
                try {
                    // bugfix of the #26223. 
                    if (!valid) {
                        invalidateBody();
                        return;
                    }
                    bodies.open(false);
                    bodies.seek(bodySeekPointer);
                    bodies.read(bodyLen);
                    bodies.close();
                } catch (IOException e) {
                    if (!bodies.fileNotFound){ // show this info only once for appropriate file.
                        JOptionPane.showMessageDialog((Component)Utilities.getLastActiveComponent(),
                        MessageFormat.format(
                        LocaleSupport.getString( "pd-file-not-found" ), //NOI18N
                        new Object[] {bodies.toString()}),
                        LocaleSupport.getString( "pd-file-not-found-title" ), //NOI18N
                        JOptionPane.WARNING_MESSAGE
                        );
                        bodies.fileNotFound = true;
                        skels.fileNotFound = true;
                    }
                    invalidateBody();
                    return;
                }
                
                body.tagOffset = bodies.getInteger();
                body.superClass = readSimpleClass(bodies);
                
                int cnt = bodies.getInteger();
                body.interfaces = (cnt > 0) ? new JCClass[cnt]
                : JavaCompletion.EMPTY_CLASSES;
                for (int i = 0; i < cnt; i++) {
                    body.interfaces[i] = readSimpleClass(bodies);
                }
                
                cnt = bodies.getInteger();
                body.fields = (cnt > 0) ? new JCField[cnt]
                : JavaCompletion.EMPTY_FIELDS;
                for (int i = 0; i < cnt; i++) {
                    body.fields[i] = new Fld(this);
                }
                
                cnt = bodies.getInteger();
                body.constructors = (cnt > 0) ? new JCConstructor[cnt]
                : JavaCompletion.EMPTY_CONSTRUCTORS;
                for (int i = 0; i < cnt; i++) {
                    body.constructors[i] = new Ctr(this);
                }
                
                cnt = bodies.getInteger();
                body.methods = (cnt > 0) ? new JCMethod[cnt]
                : JavaCompletion.EMPTY_METHODS;
                for (int i = 0; i < cnt; i++) {
                    body.methods[i] = new Mtd(this);
                }
                
                try {
                    bodies.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        
    }
    
    final class Typ extends JavaCompletion.BaseType {
        
        Typ() {
            clazz = readSimpleClass(bodies);
            arrayDepth = bodies.getInteger();
        }
        
    }
    
    /** Description of the declared field */
    final class Fld extends JavaCompletion.BaseField {
        
        Fld(JCClass clazz) {
            this.clazz = clazz;
            name = bodies.getString();
            type = new Typ();
            tagOffset = bodies.getInteger();
            modifiers = bodies.getInteger();
        }

    }

    private void readBC(JavaCompletion.BaseConstructor bc) {
        bc.tagOffset = bodies.getInteger();
        bc.modifiers = bodies.getInteger();

        int cnt = bodies.getInteger();
        bc.parameters = (cnt > 0) ? new JCParameter[cnt]
                        : JavaCompletion.EMPTY_PARAMETERS;
        for (int i = 0; i < cnt; i++) {
            bc.parameters[i] = new Prm();
        }

        cnt = bodies.getInteger();
        bc.exceptions = (cnt > 0) ? new JCClass[cnt]
                        : JavaCompletion.EMPTY_CLASSES;
        for (int i = 0; i < cnt; i++) {
            bc.exceptions[i] = readSimpleClass(bodies);
        }
    }

    /** Read constructor */
    final class Ctr extends JavaCompletion.BaseConstructor {

        Ctr(JCClass clazz) {
            this.clazz = clazz;
            readBC(this);
        }

    }

    /** Read method */
    final class Mtd extends JavaCompletion.BaseMethod {

        Mtd(JCClass clazz) {
            this.clazz = clazz;
            readBC(this);

            name = bodies.getString();
            returnType = new Typ();

        }

    }

    /** Description of the method parameter */
    public class Prm extends JavaCompletion.BaseParameter {

        Prm() {
            name = bodies.getString();
            type = new Typ();
        }

    }

    public String toString() {
        return "Skeleton: "+skels+" , Body: "+bodies; // NOI18N
        // return "strCache=" + strCache; // NOI18N
    }

}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.