1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.builder;
13 import java.io.DataInputStream;
14 import java.io.DataOutputStream;
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.Date;
19 import net.sourceforge.phpdt.core.compiler.CharOperation;
20 import net.sourceforge.phpdt.internal.compiler.util.Util;
21 import net.sourceforge.phpdt.internal.core.util.SimpleLookupTable;
23 import org.eclipse.core.resources.IContainer;
24 import org.eclipse.core.resources.IProject;
25 import org.eclipse.core.resources.IResource;
26 import org.eclipse.core.resources.IResourceDelta;
27 import org.eclipse.core.resources.IWorkspaceRoot;
28 import org.eclipse.core.runtime.IPath;
29 import org.eclipse.core.runtime.Path;
32 // NOTE: this state cannot contain types that are not defined in this project
34 String javaProjectName;
35 ClasspathMultiDirectory[] sourceLocations;
36 //ClasspathLocation[] binaryLocations;
37 // keyed by the project relative path of the type (ie. "src1/p1/p2/A.java"), value is a ReferenceCollection or an
38 // AdditionalTypeCollection
39 SimpleLookupTable references;
40 // keyed by qualified type name "p1/p2/A", value is the project relative path which defines this type "src1/p1/p2/A.java"
41 SimpleLookupTable typeLocators;
44 long lastStructuralBuildTime;
45 SimpleLookupTable structuralBuildTimes;
47 private String[] knownPackageNames; // of the form "p1/p2"
49 static final byte VERSION = 0x0007;
51 static final byte SOURCE_FOLDER = 1;
52 // static final byte BINARY_FOLDER = 2;
53 // static final byte EXTERNAL_JAR = 3;
54 // static final byte INTERNAL_JAR = 4;
59 protected State(PHPBuilder javaBuilder) {
60 this.knownPackageNames = null;
61 this.javaProjectName = javaBuilder.currentProject.getName();
62 this.sourceLocations = javaBuilder.nameEnvironment.sourceLocations;
63 // this.binaryLocations = javaBuilder.nameEnvironment.binaryLocations;
64 this.references = new SimpleLookupTable(7);
65 this.typeLocators = new SimpleLookupTable(7);
67 this.buildNumber = 0; // indicates a full build
68 this.lastStructuralBuildTime = System.currentTimeMillis();
69 this.structuralBuildTimes = new SimpleLookupTable(3);
72 void copyFrom(State lastState) {
74 this.knownPackageNames = null;
75 this.buildNumber = lastState.buildNumber + 1;
76 this.lastStructuralBuildTime = lastState.lastStructuralBuildTime;
77 this.references = (SimpleLookupTable) lastState.references.clone();
78 this.typeLocators = (SimpleLookupTable) lastState.typeLocators.clone();
79 } catch (CloneNotSupportedException e) {
80 this.references = new SimpleLookupTable(lastState.references.elementSize);
81 Object[] keyTable = lastState.references.keyTable;
82 Object[] valueTable = lastState.references.valueTable;
83 for (int i = 0, l = keyTable.length; i < l; i++)
84 if (keyTable[i] != null)
85 this.references.put(keyTable[i], valueTable[i]);
87 this.typeLocators = new SimpleLookupTable(lastState.typeLocators.elementSize);
88 keyTable = lastState.typeLocators.keyTable;
89 valueTable = lastState.typeLocators.valueTable;
90 for (int i = 0, l = keyTable.length; i < l; i++)
91 if (keyTable[i] != null)
92 this.typeLocators.put(keyTable[i], valueTable[i]);
96 char[][] getDefinedTypeNamesFor(String typeLocator) {
97 Object c = references.get(typeLocator);
98 if (c instanceof AdditionalTypeCollection)
99 return ((AdditionalTypeCollection) c).definedTypeNames;
100 return null; // means only one type is defined with the same name as the file... saves space
103 boolean isDuplicateLocator(String qualifiedTypeName, String typeLocator) {
104 String existing = (String) typeLocators.get(qualifiedTypeName);
105 return existing != null && !existing.equals(typeLocator);
108 boolean isKnownPackage(String qualifiedPackageName) {
109 if (knownPackageNames == null) {
110 ArrayList names = new ArrayList(typeLocators.elementSize);
111 Object[] keyTable = typeLocators.keyTable;
112 for (int i = 0, l = keyTable.length; i < l; i++) {
113 if (keyTable[i] != null) {
114 String packageName = (String) keyTable[i]; // is a type name of the form p1/p2/A
115 int last = packageName.lastIndexOf('/');
116 packageName = last == -1 ? null : packageName.substring(0, last);
117 while (packageName != null && !names.contains(packageName)) {
118 names.add(packageName);
119 last = packageName.lastIndexOf('/');
120 packageName = last == -1 ? null : packageName.substring(0, last);
124 knownPackageNames = new String[names.size()];
125 names.toArray(knownPackageNames);
127 for (int i = 0, l = knownPackageNames.length; i < l; i++)
128 if (knownPackageNames[i].equals(qualifiedPackageName))
133 void record(String typeLocator, char[][][] qualifiedRefs, char[][] simpleRefs, char[] mainTypeName, ArrayList typeNames) {
134 if (typeNames.size() == 1 && CharOperation.equals(mainTypeName, (char[]) typeNames.get(0))) {
135 references.put(typeLocator, new ReferenceCollection(qualifiedRefs, simpleRefs));
137 char[][] definedTypeNames = new char[typeNames.size()][]; // can be empty when no types are defined
138 typeNames.toArray(definedTypeNames);
139 references.put(typeLocator, new AdditionalTypeCollection(definedTypeNames, qualifiedRefs, simpleRefs));
143 void recordLocatorForType(String qualifiedTypeName, String typeLocator) {
144 this.knownPackageNames = null;
145 typeLocators.put(qualifiedTypeName, typeLocator);
148 void recordStructuralDependency(IProject prereqProject, State prereqState) {
149 if (prereqState != null)
150 structuralBuildTimes.put(prereqProject.getName(), new Long(prereqState.lastStructuralBuildTime));
153 void removeLocator(String typeLocatorToRemove) {
154 this.knownPackageNames = null;
155 references.removeKey(typeLocatorToRemove);
156 typeLocators.removeValue(typeLocatorToRemove);
159 void removePackage(IResourceDelta sourceDelta) {
160 IResource resource = sourceDelta.getResource();
161 switch (resource.getType()) {
162 case IResource.FOLDER :
163 IResourceDelta[] children = sourceDelta.getAffectedChildren();
164 for (int i = 0, l = children.length; i < l; i++)
165 removePackage(children[i]);
167 case IResource.FILE :
168 IPath typeLocatorPath = resource.getProjectRelativePath();
169 if (Util.isJavaFileName(typeLocatorPath.lastSegment()))
170 removeLocator(typeLocatorPath.toString());
174 void removeQualifiedTypeName(String qualifiedTypeNameToRemove) {
175 this.knownPackageNames = null;
176 typeLocators.removeKey(qualifiedTypeNameToRemove);
179 static State read(IProject project, DataInputStream in) throws IOException {
180 if (PHPBuilder.DEBUG)
181 System.out.println("About to read state..."); //$NON-NLS-1$
182 if (VERSION != in.readByte()) {
183 if (PHPBuilder.DEBUG)
184 System.out.println("Found non-compatible state version... answered null"); //$NON-NLS-1$
188 State newState = new State();
189 newState.javaProjectName = in.readUTF();
190 if (!project.getName().equals(newState.javaProjectName)) {
191 if (PHPBuilder.DEBUG)
192 System.out.println("Project's name does not match... answered null"); //$NON-NLS-1$
195 newState.buildNumber = in.readInt();
196 newState.lastStructuralBuildTime = in.readLong();
198 int length = in.readInt();
199 newState.sourceLocations = new ClasspathMultiDirectory[0];
200 // newState.sourceLocations = new ClasspathMultiDirectory[length];
201 // for (int i = 0; i < length; i++) {
202 // IContainer sourceFolder = project, outputFolder = project;
203 // String folderName;
204 // if ((folderName = in.readUTF()).length() > 0) sourceFolder = project.getFolder(folderName);
205 // if ((folderName = in.readUTF()).length() > 0) outputFolder = project.getFolder(folderName);
206 // ClasspathMultiDirectory md =
207 // (ClasspathMultiDirectory) ClasspathLocation.forSourceFolder(sourceFolder, outputFolder, readNames(in));
208 // if (in.readBoolean())
209 // md.hasIndependentOutputFolder = true;
210 // newState.sourceLocations[i] = md;
213 length = in.readInt();
214 // newState.binaryLocations = new ClasspathLocation[length];
215 // IWorkspaceRoot root = project.getWorkspace().getRoot();
216 // for (int i = 0; i < length; i++) {
217 // switch (in.readByte()) {
218 // case SOURCE_FOLDER :
219 // newState.binaryLocations[i] = newState.sourceLocations[in.readInt()];
221 // case BINARY_FOLDER :
222 // IPath path = new Path(in.readUTF());
223 // IContainer outputFolder = path.segmentCount() == 1
224 // ? (IContainer) root.getProject(path.toString())
225 // : (IContainer) root.getFolder(path);
226 // newState.binaryLocations[i] = ClasspathLocation.forBinaryFolder(outputFolder, in.readBoolean());
228 // case EXTERNAL_JAR :
229 // newState.binaryLocations[i] = ClasspathLocation.forLibrary(in.readUTF());
231 // case INTERNAL_JAR :
232 // newState.binaryLocations[i] = ClasspathLocation.forLibrary(root.getFile(new Path(in.readUTF())));
236 newState.structuralBuildTimes = new SimpleLookupTable(length = in.readInt());
237 for (int i = 0; i < length; i++)
238 newState.structuralBuildTimes.put(in.readUTF(), new Long(in.readLong()));
240 String[] internedTypeLocators = new String[length = in.readInt()];
241 for (int i = 0; i < length; i++)
242 internedTypeLocators[i] = in.readUTF();
244 newState.typeLocators = new SimpleLookupTable(length = in.readInt());
245 for (int i = 0; i < length; i++)
246 newState.typeLocators.put(in.readUTF(), internedTypeLocators[in.readInt()]);
248 char[][] internedSimpleNames = ReferenceCollection.internSimpleNames(readNames(in), false);
249 char[][][] internedQualifiedNames = new char[length = in.readInt()][][];
250 for (int i = 0; i < length; i++) {
251 int qLength = in.readInt();
252 char[][] qName = new char[qLength][];
253 for (int j = 0; j < qLength; j++)
254 qName[j] = internedSimpleNames[in.readInt()];
255 internedQualifiedNames[i] = qName;
257 internedQualifiedNames = ReferenceCollection.internQualifiedNames(internedQualifiedNames);
259 newState.references = new SimpleLookupTable(length = in.readInt());
260 for (int i = 0; i < length; i++) {
261 String typeLocator = internedTypeLocators[in.readInt()];
262 ReferenceCollection collection = null;
263 switch (in.readByte()) {
265 char[][] additionalTypeNames = readNames(in);
266 char[][][] qualifiedNames = new char[in.readInt()][][];
267 for (int j = 0, m = qualifiedNames.length; j < m; j++)
268 qualifiedNames[j] = internedQualifiedNames[in.readInt()];
269 char[][] simpleNames = new char[in.readInt()][];
270 for (int j = 0, m = simpleNames.length; j < m; j++)
271 simpleNames[j] = internedSimpleNames[in.readInt()];
272 collection = new AdditionalTypeCollection(additionalTypeNames, qualifiedNames, simpleNames);
275 char[][][] qNames = new char[in.readInt()][][];
276 for (int j = 0, m = qNames.length; j < m; j++)
277 qNames[j] = internedQualifiedNames[in.readInt()];
278 char[][] sNames = new char[in.readInt()][];
279 for (int j = 0, m = sNames.length; j < m; j++)
280 sNames[j] = internedSimpleNames[in.readInt()];
281 collection = new ReferenceCollection(qNames, sNames);
283 newState.references.put(typeLocator, collection);
285 if (PHPBuilder.DEBUG)
286 System.out.println("Successfully read state for " + newState.javaProjectName); //$NON-NLS-1$
290 private static char[][] readNames(DataInputStream in) throws IOException {
291 int length = in.readInt();
292 char[][] names = new char[length][];
293 for (int i = 0; i < length; i++) {
294 int nLength = in.readInt();
295 char[] name = new char[nLength];
296 for (int j = 0; j < nLength; j++)
297 name[j] = in.readChar();
303 void tagAsNoopBuild() {
304 this.buildNumber = -1; // tag the project since it has no source folders and can be skipped
307 boolean wasNoopBuild() {
308 return buildNumber == -1;
311 void tagAsStructurallyChanged() {
312 this.lastStructuralBuildTime = System.currentTimeMillis();
315 boolean wasStructurallyChanged(IProject prereqProject, State prereqState) {
316 if (prereqState != null) {
317 Object o = structuralBuildTimes.get(prereqProject.getName());
318 long previous = o == null ? 0 : ((Long) o).longValue();
319 if (previous == prereqState.lastStructuralBuildTime)
325 void write(DataOutputStream out) throws IOException {
331 * byte VERSION String project name int build number int last structural build number
333 out.writeByte(VERSION);
334 out.writeUTF(javaProjectName);
335 out.writeInt(buildNumber);
336 out.writeLong(lastStructuralBuildTime);
339 * ClasspathMultiDirectory[] int id String path(s)
341 out.writeInt(length = sourceLocations.length);
342 for (int i = 0; i < length; i++) {
343 ClasspathMultiDirectory md = sourceLocations[i];
344 out.writeUTF(md.sourceFolder.getProjectRelativePath().toString());
345 out.writeUTF(md.binaryFolder.getProjectRelativePath().toString());
346 writeNames(md.exclusionPatterns, out);
347 out.writeBoolean(md.hasIndependentOutputFolder);
351 * ClasspathLocation[] int id String path(s)
353 // out.writeInt(length = binaryLocations.length);
354 // next : for (int i = 0; i < length; i++) {
355 // ClasspathLocation c = binaryLocations[i];
356 // if (c instanceof ClasspathMultiDirectory) {
357 // out.writeByte(SOURCE_FOLDER);
358 // for (int j = 0, m = sourceLocations.length; j < m; j++) {
359 // if (sourceLocations[j] == c) {
364 // } else if (c instanceof ClasspathDirectory) {
365 // out.writeByte(BINARY_FOLDER);
366 // ClasspathDirectory cd = (ClasspathDirectory) c;
367 // out.writeUTF(cd.binaryFolder.getFullPath().toString());
368 // out.writeBoolean(cd.isOutputFolder);
370 // ClasspathJar jar = (ClasspathJar) c;
371 // if (jar.resource == null) {
372 // out.writeByte(EXTERNAL_JAR);
373 // out.writeUTF(jar.zipFilename);
375 // out.writeByte(INTERNAL_JAR);
376 // out.writeUTF(jar.resource.getFullPath().toString());
382 * Structural build numbers table String prereq project name int last structural build number
384 out.writeInt(length = structuralBuildTimes.elementSize);
386 keyTable = structuralBuildTimes.keyTable;
387 valueTable = structuralBuildTimes.valueTable;
388 for (int i = 0, l = keyTable.length; i < l; i++) {
389 if (keyTable[i] != null) {
391 out.writeUTF((String) keyTable[i]);
392 out.writeLong(((Long) valueTable[i]).longValue());
395 if (PHPBuilder.DEBUG && length != 0)
396 System.out.println("structuralBuildNumbers table is inconsistent"); //$NON-NLS-1$
400 * String[] Interned type locators
402 out.writeInt(length = references.elementSize);
403 ArrayList internedTypeLocators = new ArrayList(length);
405 keyTable = references.keyTable;
406 for (int i = 0, l = keyTable.length; i < l; i++) {
407 if (keyTable[i] != null) {
409 String key = (String) keyTable[i];
411 internedTypeLocators.add(key);
414 if (PHPBuilder.DEBUG && length != 0)
415 System.out.println("references table is inconsistent"); //$NON-NLS-1$
419 * Type locators table String type name int interned locator id
421 out.writeInt(length = typeLocators.elementSize);
423 keyTable = typeLocators.keyTable;
424 valueTable = typeLocators.valueTable;
425 for (int i = 0, l = keyTable.length; i < l; i++) {
426 if (keyTable[i] != null) {
428 out.writeUTF((String) keyTable[i]);
429 out.writeInt(internedTypeLocators.indexOf((String) valueTable[i]));
432 if (PHPBuilder.DEBUG && length != 0)
433 System.out.println("typeLocators table is inconsistent"); //$NON-NLS-1$
437 * char[][][] Interned qualified names char[][] Interned simple names
439 ArrayList internedQualifiedNames = new ArrayList(31);
440 ArrayList internedSimpleNames = new ArrayList(31);
441 valueTable = references.valueTable;
442 for (int i = 0, l = valueTable.length; i < l; i++) {
443 if (valueTable[i] != null) {
444 ReferenceCollection collection = (ReferenceCollection) valueTable[i];
445 char[][][] qNames = collection.qualifiedNameReferences;
446 for (int j = 0, m = qNames.length; j < m; j++) {
447 char[][] qName = qNames[j];
448 if (!internedQualifiedNames.contains(qName)) { // remember the names have been interned
449 internedQualifiedNames.add(qName);
450 for (int k = 0, n = qName.length; k < n; k++) {
451 char[] sName = qName[k];
452 if (!internedSimpleNames.contains(sName)) // remember the names have been interned
453 internedSimpleNames.add(sName);
457 char[][] sNames = collection.simpleNameReferences;
458 for (int j = 0, m = sNames.length; j < m; j++) {
459 char[] sName = sNames[j];
460 if (!internedSimpleNames.contains(sName)) // remember the names have been interned
461 internedSimpleNames.add(sName);
465 char[][] internedArray = new char[internedSimpleNames.size()][];
466 internedSimpleNames.toArray(internedArray);
467 writeNames(internedArray, out);
468 // now write the interned qualified names as arrays of interned simple names
469 out.writeInt(length = internedQualifiedNames.size());
470 for (int i = 0; i < length; i++) {
471 char[][] qName = (char[][]) internedQualifiedNames.get(i);
472 int qLength = qName.length;
473 out.writeInt(qLength);
474 for (int j = 0; j < qLength; j++)
475 out.writeInt(internedSimpleNames.indexOf(qName[j]));
479 * References table int interned locator id ReferenceCollection
481 out.writeInt(length = references.elementSize);
483 keyTable = references.keyTable;
484 for (int i = 0, l = keyTable.length; i < l; i++) {
485 if (keyTable[i] != null) {
487 out.writeInt(internedTypeLocators.indexOf((String) keyTable[i]));
488 ReferenceCollection collection = (ReferenceCollection) valueTable[i];
489 if (collection instanceof AdditionalTypeCollection) {
491 AdditionalTypeCollection atc = (AdditionalTypeCollection) collection;
492 writeNames(atc.definedTypeNames, out);
496 char[][][] qNames = collection.qualifiedNameReferences;
497 int qLength = qNames.length;
498 out.writeInt(qLength);
499 for (int j = 0; j < qLength; j++)
500 out.writeInt(internedQualifiedNames.indexOf(qNames[j]));
501 char[][] sNames = collection.simpleNameReferences;
502 int sLength = sNames.length;
503 out.writeInt(sLength);
504 for (int j = 0; j < sLength; j++)
505 out.writeInt(internedSimpleNames.indexOf(sNames[j]));
508 if (PHPBuilder.DEBUG && length != 0)
509 System.out.println("references table is inconsistent"); //$NON-NLS-1$
513 private void writeNames(char[][] names, DataOutputStream out) throws IOException {
514 int length = names == null ? 0 : names.length;
515 out.writeInt(length);
516 for (int i = 0; i < length; i++) {
517 char[] name = names[i];
518 int nLength = name.length;
519 out.writeInt(nLength);
520 for (int j = 0; j < nLength; j++)
521 out.writeChar(name[j]);
526 * Returns a string representation of the receiver.
528 public String toString() {
529 return "State for " + javaProjectName //$NON-NLS-1$
530 +" (#" + buildNumber //$NON-NLS-1$
531 +" @ " + new Date(lastStructuralBuildTime) //$NON-NLS-1$
536 * Debug helper void dump() { System.out.println("State for " + javaProjectName + " (" + buildNumber + " @ " + new
537 * Date(lastStructuralBuildTime) + ")"); System.out.println("\tClass path source locations:"); for (int i = 0, l =
538 * sourceLocations.length; i < l; i++) System.out.println("\t\t" + sourceLocations[i]); System.out.println("\tClass path binary
539 * locations:"); for (int i = 0, l = binaryLocations.length; i < l; i++) System.out.println("\t\t" + binaryLocations[i]);
541 * System.out.print("\tStructural build numbers table:"); if (structuralBuildTimes.elementSize == 0) { System.out.print(" <empty>
542 * "); } else { Object[] keyTable = structuralBuildTimes.keyTable; Object[] valueTable = structuralBuildTimes.valueTable; for
543 * (int i = 0, l = keyTable.length; i < l; i++) if (keyTable[i] != null) System.out.print("\n\t\t" + keyTable[i].toString() + " -> " +
544 * valueTable[i].toString()); }
546 * System.out.print("\tType locators table:"); if (typeLocators.elementSize == 0) { System.out.print(" <empty> "); } else {
547 * Object[] keyTable = typeLocators.keyTable; Object[] valueTable = typeLocators.valueTable; for (int i = 0, l = keyTable.length;
548 * i < l; i++) if (keyTable[i] != null) System.out.print("\n\t\t" + keyTable[i].toString() + " -> " + valueTable[i].toString()); }
550 * System.out.print("\n\tReferences table:"); if (references.elementSize == 0) { System.out.print(" <empty> "); } else { Object[]
551 * keyTable = references.keyTable; Object[] valueTable = references.valueTable; for (int i = 0, l = keyTable.length; i
552 * < l; i++) { if (keyTable[i] != null) { System.out.print("\n\t\t" + keyTable[i].toString()); ReferenceCollection c =
553 * (ReferenceCollection) valueTable[i]; char[][][] qRefs = c.qualifiedNameReferences; System.out.print("\n\t\t\tqualified:"); if
554 * (qRefs.length == 0) System.out.print(" <empty> "); else for (int j = 0, m = qRefs.length; j < m; j++) System.out.print(" '" +
555 * CharOperation.toString(qRefs[j]) + "'"); char[][] sRefs = c.simpleNameReferences; System.out.print("\n\t\t\tsimple:"); if
556 * (sRefs.length == 0) System.out.print(" <empty> "); else for (int j = 0, m = sRefs.length; j < m; j++) System.out.print(" " +
557 * new String(sRefs[j])); if (c instanceof AdditionalTypeCollection) { char[][] names = ((AdditionalTypeCollection)
558 * c).definedTypeNames; System.out.print("\n\t\t\tadditional type names:"); for (int j = 0, m = names.length; j < m; j++)
559 * System.out.print(" " + new String(names[j])); } } } } System.out.print("\n\n"); }