|
What this is
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-2004 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.javacore; import java.io.*; import java.util.*; import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.java.queries.SourceLevelQuery; import org.netbeans.api.mdr.MDRepository; import org.netbeans.jmi.javamodel.*; import org.netbeans.lib.java.parser.Factory; import org.netbeans.lib.java.parser.JScanner; import org.netbeans.lib.java.parser.ParserTokens; import org.netbeans.mdr.NBMDRepositoryImpl; import org.netbeans.modules.javacore.internalapi.JavaMetamodel; import org.netbeans.modules.javacore.jmiimpl.javamodel.JavaClassImpl; import org.netbeans.mdr.util.IOUtils; import org.netbeans.mdr.persistence.MOFID; import org.netbeans.mdr.handlers.BaseObjectHandler; import org.openide.ErrorManager; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileStateInvalidException; import org.openide.filesystems.JarFileSystem; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; /** * * @author Tomas Hurka, Martin Matula */ public class ClassIndex implements Serializable { private static final int VERSION = 2; static Map codebaseIndexes=Collections.synchronizedMap(new HashMap()); private static final String INDEX_SUFFIX=".cdx"; // NOI18N private SortedMap fqnMap; private SortedMap simpleMap; private Map identifiersMap; private String storageId; private long lastSaved; private transient NBMDRepositoryImpl rep; private transient String filename; private transient boolean isDirty; private transient HashMap changeLogSN; private transient HashMap changeLogFQN; private transient HashMap changeLogI; private static boolean shutdownListenerRegistered = false; private static final ShutdownL shutdownListener = new ShutdownL(); private static final long serialVersionUID = -2611840548775984571L; private static final boolean DEBUG = false; /** Creates a new instance of ClassIndex */ private ClassIndex(String file, String storageId) { this.storageId = storageId; rep = (NBMDRepositoryImpl) JavaMetamodel.getDefaultRepository(); filename = file; cleanIndex(); // register shutdown listener if (!shutdownListenerRegistered) { synchronized (shutdownListener) { if (!shutdownListenerRegistered) { ((NBMDRepositoryImpl) JavaMetamodel.getDefaultRepository()).addShutdownListener(shutdownListener); shutdownListenerRegistered = true; } } } } void cleanIndex() { fqnMap = new TreeMap(); simpleMap = new TreeMap(); identifiersMap = new HashMap(); isDirty = true; } static void commit() { for (Iterator it = codebaseIndexes.values().iterator(); it.hasNext();) { ((ClassIndex) it.next()).commitChanges(); } } static void rollback() { for (Iterator it = codebaseIndexes.values().iterator(); it.hasNext();) { ((ClassIndex) it.next()).rollbackChanges(); } } private void commitChanges() { changeLogSN = null; changeLogFQN = null; changeLogI = null; } private void rollbackChanges() { if (changeLogSN != null) { for (Iterator it = changeLogSN.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); it.remove(); long mofId = ((Long) entry.getKey()).longValue(); if (entry.getValue() == null) { JavaClass cls = (JavaClass) rep.getByMofId(makeMofId(mofId)); if (cls != null) { addClass(cls, cls.getName(), cls.getSimpleName()); } } else { removeFromMap(simpleMap, entry.getValue(), mofId); // list of fqn changes is superset of this list so I don't have to add the class // to index here - it will be done when iterating through changeLogFQN below } } } if (changeLogFQN != null) { for (Iterator it = changeLogFQN.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); it.remove(); long mofId = ((Long) entry.getKey()).longValue(); JavaClass cls = (JavaClass) rep.getByMofId(makeMofId(mofId)); if (entry.getValue() != null) { removeFromMap(fqnMap, entry.getValue(), mofId); } if (cls != null) { addClass(cls, cls.getName(), cls.getSimpleName()); } } } if (changeLogI != null) { for (Iterator it = changeLogI.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); it.remove(); identifiersMap.put(entry.getKey(), entry.getValue()); } } } private void removeFromMap(Map map, Object key, long value) { if (map == simpleMap) { key = ((String) key).toUpperCase(); } Object temp = map.get(key); if (temp != null) { long[] oldValue = (long[]) temp; int len = oldValue.length; long[] newValue = new long[len - 1]; int i = 0, j = 0; for (; i < len && j < len - 1; i++) { if (oldValue[i] != value) { newValue[j++] = oldValue[i]; } } if (i < len && oldValue[i] != value) { if (j < len - 1) { newValue[j] = oldValue[i]; } else { newValue = oldValue; } } if (oldValue != newValue) { if (newValue.length == 0) { map.remove(key); } else { map.put(key, newValue); } } } } public static ClassIndex getIndex(JavaModelPackage mofPackage) { return (ClassIndex)codebaseIndexes.get(mofPackage); } private static void saveAllIndexes() { MDRepository rep=JavaMetamodel.getDefaultRepository(); rep.beginTrans(false); try { synchronized(codebaseIndexes) { Iterator indexIt=codebaseIndexes.values().iterator(); while(indexIt.hasNext()) { ClassIndex index=(ClassIndex)indexIt.next(); index.saveIndex(); } } } finally { rep.endTrans(); } } static void removeIndex(JavaModelPackage mofPackage) { ClassIndex index=(ClassIndex)codebaseIndexes.remove(mofPackage); index.saveIndex(); } static void saveIndex(JavaModelPackage mofPackage) { ClassIndex index=(ClassIndex)codebaseIndexes.get(mofPackage); index.saveIndex(); } static void cleanIndex(JavaModelPackage mofPackage) { ClassIndex index=(ClassIndex)codebaseIndexes.get(mofPackage); index.cleanIndex(); } static void addIndex(JavaModelPackage mofPackage,String filename) { codebaseIndexes.put(mofPackage, new ClassIndex(filename, ((BaseObjectHandler) mofPackage)._getDelegate().getMofId().getStorageID())); } static boolean loadIndexFrom(String filename,JavaModelPackage mofPackage) { long t = 0; try { if (JMManager.PERF_DEBUG) { t = System.currentTimeMillis(); } File indexFile=new File(filename.concat(INDEX_SUFFIX)); InputStream indexStream=new BufferedInputStream(new FileInputStream(indexFile), 65536); ClassIndex index; try { index = new ClassIndex(filename, ((BaseObjectHandler) mofPackage)._getDelegate().getMofId().getStorageID()).read(indexStream); } finally { indexStream.close(); } if (index == null) { addIndex(mofPackage, filename); } else { codebaseIndexes.put(mofPackage,index); } return true; } catch (Exception ex) { ex.printStackTrace(); addIndex(mofPackage,filename); return false; } finally { if (JMManager.PERF_DEBUG) { System.err.println("loading index " + filename + " took: " + (System.currentTimeMillis() - t) + "ms"); } } } private ClassIndex read(InputStream indexStream) throws IOException { if (VERSION != IOUtils.readInt(indexStream)) return null; if (!storageId.equals(IOUtils.readString(indexStream))) return null; readMap(indexStream, fqnMap); readMap(indexStream, simpleMap); int count = IOUtils.readInt(indexStream); for (int i = 0; i < count; i++) { Long key = new Long(IOUtils.readLong(indexStream)); int count2 = IOUtils.readInt(indexStream); int[] value = new int[count2]; for (int j = 0; j < count2; j++) { value[j] = IOUtils.readInt(indexStream); } identifiersMap.put(key, value); } lastSaved = IOUtils.readLong(indexStream); return this; } private void write(OutputStream indexStream) throws IOException { if (JMManager.PERF_DEBUG) System.err.println("fqnMap: " + fqnMap.size() + " records; identifiersMap: " + identifiersMap.size() + "records"); IOUtils.writeInt(indexStream, VERSION); IOUtils.writeString(indexStream, storageId); writeMap(indexStream, fqnMap); writeMap(indexStream, simpleMap); IOUtils.writeInt(indexStream, identifiersMap.size()); for (Iterator it = identifiersMap.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); IOUtils.writeLong(indexStream, ((Long) entry.getKey()).longValue()); int[] array = (int[]) entry.getValue(); IOUtils.writeInt(indexStream, array.length); for (int i = 0; i < array.length; i++) { IOUtils.writeInt(indexStream, array[i]); } } IOUtils.writeLong(indexStream, System.currentTimeMillis()); } private void readMap(InputStream indexStream, Map map) throws IOException { int count = IOUtils.readInt(indexStream); for (int i = 0; i < count; i++) { String key = IOUtils.readString(indexStream); int count2 = IOUtils.readInt(indexStream); long[] value = new long[count2]; for (int j = 0; j < count2; j++) { value[j] = IOUtils.readLong(indexStream); } map.put(key, value); } } private void writeMap(OutputStream indexStream, Map map) throws IOException { IOUtils.writeInt(indexStream, map.size()); for (Iterator it = map.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); IOUtils.writeString(indexStream, (String) entry.getKey()); long[] array = (long[]) entry.getValue(); IOUtils.writeInt(indexStream, array.length); for (int i = 0; i < array.length; i++) { IOUtils.writeLong(indexStream, array[i]); } } } void saveIndex() { if (!isDirty) return; if (JMManager.PERF_DEBUG) { System.err.println("saving index " + filename); } rep.beginTrans(false); try { FileOutputStream fos=new FileOutputStream(filename.concat(INDEX_SUFFIX)); BufferedOutputStream indexStream=new BufferedOutputStream(fos, 65536); try { write(indexStream); } finally { indexStream.close(); } isDirty=false; } catch (Exception ex) { ex.printStackTrace(); } finally { rep.endTrans(); } } public void renameClass(JavaClass jcls, String newName) { long mofId = getMofId(jcls); String name = jcls.getName(); String simpleName = jcls.getSimpleName(); String newSimpleName = JavaClassImpl.getSimpleName(newName); if (JMManager.INCONSISTENCY_DEBUG) System.err.println("ClassIndex: Renaming class: " + name + " to: " + newName + " MOFID: " + jcls.refMofId()); //Thread.dumpStack(); isDirty=true; removeFromMap(fqnMap, name, mofId); Long objMofId = new Long(mofId); logFQNChange(objMofId, newName); if (!simpleName.equals(newSimpleName)) { removeFromMap(simpleMap, simpleName, mofId); logSNChange(objMofId, newSimpleName); } addClass(jcls, newName, newSimpleName); } private static HashMap logChange(HashMap map, Long mofId, Object value) { if (map == null) { map = new HashMap(); } map.put(mofId, value); return map; } private void logFQNChange(Long mofId, String name) { changeLogFQN = logChange(changeLogFQN, mofId, name); } private void logSNChange(Long mofId, String name) { changeLogSN = logChange(changeLogSN, mofId, name); } public void addClass(JavaClass jcls,String fqn,String simpleName) { if (JMManager.INCONSISTENCY_DEBUG) System.err.println("ClassIndex: Adding class " + fqn + " MOFID: " + jcls.refMofId()); long mofId = getMofId(jcls); isDirty=true; addToMap(fqnMap, fqn, mofId); addToMap(simpleMap, simpleName, mofId); } private void addToMap(Map map, Object key, long value) { if (map == simpleMap) { key = ((String) key).toUpperCase(); } long[] temp = (long[]) map.get(key); long[] newValue; int len; if (temp == null) { len = 0; newValue = new long[len + 1]; } else { long[] oldValue = temp; len = oldValue.length; newValue = new long[len + 1]; for (int i = 0; i < len; i++) { if (oldValue[i] == value) { newValue = oldValue; break; } newValue[i] = oldValue[i]; } } if (newValue != temp) { newValue[len] = value; map.put(key, newValue); } } public long getTimestamp() { return lastSaved; } public Set getClassesByFqn(String fqn) { Set result = new HashSet(); long[] classes = (long[]) fqnMap.get(fqn); if (classes != null) { JavaClass cls = null; int j = 0; for (int i = 0; i < classes.length; i++) { JavaClass temp = (JavaClass) rep.getByMofId(makeMofId(classes[i])); if (temp == null) { logFQNChange(new Long(classes[i]), null); } else { classes[j] = classes[i]; j++; result.add(temp); } } if (j == 0) { fqnMap.remove(fqn); } else if (j < classes.length) { long[] newValue = new long[j]; System.arraycopy(classes, 0, newValue, 0, j); fqnMap.put(fqn, newValue); } } return result; } public JavaClass getClassByFqn(String fqn) { long[] classes = (long[]) fqnMap.get(fqn); if (classes != null) { JavaClass result = null; JavaClass sureResult = null; int j = 0; for (int i = 0; i < classes.length; i++) { JavaClass temp = (JavaClass) rep.getByMofId(makeMofId(classes[i])); if (temp == null) { logFQNChange(new Long(classes[i]), null); } else { classes[j] = classes[i]; j++; result = temp; // [TODO] the following code can be incommented if necessary // (it tries to prefer classes that are in the correct folder) // now it is commented out for performance reasons // Resource res = (Resource) result.refImmediateComposite(); // if (res != null) { // if (res.getName().replace('/', '.').startsWith(res.getPackageName())) { // sureResult = result; // } // } } } if (j == 0) { fqnMap.remove(fqn); } else if (j < classes.length) { long[] newValue = new long[j]; System.arraycopy(classes, 0, newValue, 0, j); fqnMap.put(fqn, newValue); } return sureResult == null ? result : sureResult; } return null; } public List getClassesByFQNPrefix(String fqnPrefix) { SortedMap map; if (fqnPrefix == null || fqnPrefix.length() == 0) { map = fqnMap; } else { map = fqnMap.subMap(fqnPrefix, fqnPrefix + '\uffff'); } ArrayList result = new ArrayList(map.size()); int length = fqnPrefix.length(); for (Iterator it = map.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); if (((String) entry.getKey()).lastIndexOf('.') < length) { long[] value = (long[]) entry.getValue(); int j = 0; for (int i = 0; i < value.length; i++) { Object cls = (JavaClass) rep.getByMofId(makeMofId(value[i])); if (cls == null) { logFQNChange(new Long(value[i]), null); } else { value[j] = value[i]; j++; result.add(cls); } } if (j == 0) { it.remove(); } else if (j < value.length) { long[] newValue = new long[j]; System.arraycopy(value, 0, newValue, 0, j); entry.setValue(newValue); } } } return result; } /** * Looks for the classes in class index by prefix. Finding mechanism is case * sensitive. * * @param snPrefix simple name leading characters of class which will * be looked for * @return list of matching JavaClasses instances ordered by their names */ public LazyImmutableList getClassesBySNPrefix(String snPrefix) { return getClassesBySNPrefix(snPrefix, true); } /** * Looks for the classes in class index by prefix. Finding can be either * case-sensitive or case-insensitive. * * @param snPrefix simple name leading characters of class which * will be looked for * @return list of matching JavaClasses instances ordered by names */ public LazyImmutableList getClassesBySNPrefix(String snPrefix, boolean caseSensitive) { SortedMap map; if (snPrefix == null || snPrefix.length() == 0) { map = simpleMap; } else { String snPrefixUp = snPrefix.toUpperCase(); map = simpleMap.subMap(snPrefixUp, snPrefixUp + '\uffff'); } return new LazyImmutableList(new ClassesBySNPrefixIterator(map,snPrefix,caseSensitive)); } public boolean doesnotExist(String fqn) { return fqnMap.get(fqn)==null; } public boolean hasClass(String fqn) { return getClassByFqn(fqn) != null; } /** * Looks for the classes in class index. Finding mechanism is case * sensitive. * * @param simpleName simple (short) name of class which will be looked for * @return collection of matching JavaClasses instances */ public Collection getClassesBySimpleName(String simpleName) { return getClassesBySimpleName(simpleName, true); } /** * Looks for the classes in class index. Finding can be either * case-sensitive or case-insensitive. * * @param simpleName simple (short) name of class which will be looked for * @param caseSensitive use false when you want to ignore case * @return collection of matching JavaClasses instances */ public Collection getClassesBySimpleName(String simpleName, boolean caseSensitive) { String simpleUpper = simpleName.toUpperCase(); long[] value = (long[]) simpleMap.get(simpleUpper); List res=new ArrayList(); if (value!=null) { int j = 0; for (int i = 0; i < value.length; i++) { JavaClass cls = (JavaClass) rep.getByMofId(makeMofId(value[i])); if (cls == null) { logSNChange(new Long(value[i]), null); } else { value[j] = value[i]; j++; if (!caseSensitive || simpleName.equals(cls.getSimpleName())) { res.add(cls); } } } if (j == 0) { simpleMap.remove(simpleUpper); } else if (j < value.length) { long[] newValue = new long[j]; System.arraycopy(value, 0, newValue, 0, j); simpleMap.put(simpleUpper, newValue); } } return res; } public static boolean hasClass(String fqn,ClassPath classPath) { FileObject[] roots = classPath.getRoots(); // iteruj pres rooty a hledej classu podle FQN for (int i = 0; i < roots.length; i++) { JavaModelPackage mofPackage = JavaMetamodel.getManager().getJavaExtent(roots[i]); // test for mofPackage != null is needed when any other thread // mounts the new filesystem and we do not know about it yet. // It is in list of all filesystem roots, but we do not have created // package for it yet. In such a case, the index does not contain // class and we will return false. if (mofPackage!=null && ClassIndex.getIndex(mofPackage).hasClass(fqn)) return true; } return false; } public static JavaClass getClassByFqn(String fqn, ClassPath classPath) { FileObject[] roots = classPath.getRoots(); for (int i = 0; i < roots.length; i++) { JavaModelPackage mofPackage = org.netbeans.modules.javacore.internalapi.JavaMetamodel.getManager().getJavaExtent(roots[i]); if (mofPackage != null) { ClassIndex index = ClassIndex.getIndex(mofPackage); if (index != null) { JavaClass cls = index.getClassByFqn(fqn); if (cls != null) { return cls; } } } } return null; } public void setIdentifiers(Resource rsc,int identifiers[]) { isDirty=true; Arrays.sort(identifiers); identifiersMap.put(new Long(getMofId(rsc)), identifiers); } private long getMofId(Object obj) { return ((BaseObjectHandler) obj)._getMofId().getSerialNumber(); } private MOFID makeMofId(long mofId) { return new MOFID(mofId, storageId); } public void removeResource(Resource rsc) { isDirty = true; Long mofId = new Long(getMofId(rsc)); Object o = identifiersMap.remove(mofId); changeLogI = logChange(changeLogI, mofId, o); } void updateIdentifiersInResource(Resource rsc,String sourceText) { FileObject file=JavaMetamodel.getManager().getFileObject(rsc); String sourceLevel=SourceLevelQuery.getSourceLevel(file); JScanner scanner=Factory.getDefault().getScanner(new StringReader(sourceText),sourceLevel); int token; int identifiers[]=(int[])identifiersMap.get(new Long(getMofId(rsc))); List newIds=new ArrayList(10); int newIdSize; try { while((token=scanner.yylex())!=0) { if (token==ParserTokens.IDENTIFIER) { String text=scanner.yytext(); int hash=text.hashCode(); if (Arrays.binarySearch(identifiers,hash)<0) { newIds.add(text); } } } } catch (IOException ex) { ErrorManager.getDefault().notify(ex); } newIdSize=newIds.size(); if (newIdSize>0) { int ids[]=new int[identifiers.length+newIdSize]; String newIdArr[]=(String[])newIds.toArray(new String[newIdSize]); int i; for (i=0;i |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
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.