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 AdditionalTypeCollection
38 SimpleLookupTable references;
39 // keyed by qualified type name "p1/p2/A", value is the project relative path which defines this type "src1/p1/p2/A.java"
40 SimpleLookupTable typeLocators;
43 long lastStructuralBuildTime;
44 SimpleLookupTable structuralBuildTimes;
46 private String[] knownPackageNames; // of the form "p1/p2"
48 static final byte VERSION = 0x0007;
50 static final byte SOURCE_FOLDER = 1;
51 static final byte BINARY_FOLDER = 2;
52 static final byte EXTERNAL_JAR = 3;
53 static final byte INTERNAL_JAR = 4;
58 protected State(PHPBuilder javaBuilder) {
59 this.knownPackageNames = null;
60 this.javaProjectName = javaBuilder.currentProject.getName();
61 this.sourceLocations = javaBuilder.nameEnvironment.sourceLocations;
62 // this.binaryLocations = javaBuilder.nameEnvironment.binaryLocations;
63 this.references = new SimpleLookupTable(7);
64 this.typeLocators = new SimpleLookupTable(7);
66 this.buildNumber = 0; // indicates a full build
67 this.lastStructuralBuildTime = System.currentTimeMillis();
68 this.structuralBuildTimes = new SimpleLookupTable(3);
71 void copyFrom(State lastState) {
73 this.knownPackageNames = null;
74 this.buildNumber = lastState.buildNumber + 1;
75 this.lastStructuralBuildTime = lastState.lastStructuralBuildTime;
76 this.references = (SimpleLookupTable) lastState.references.clone();
77 this.typeLocators = (SimpleLookupTable) lastState.typeLocators.clone();
78 } catch (CloneNotSupportedException e) {
79 this.references = new SimpleLookupTable(lastState.references.elementSize);
80 Object[] keyTable = lastState.references.keyTable;
81 Object[] valueTable = lastState.references.valueTable;
82 for (int i = 0, l = keyTable.length; i < l; i++)
83 if (keyTable[i] != null)
84 this.references.put(keyTable[i], valueTable[i]);
86 this.typeLocators = new SimpleLookupTable(lastState.typeLocators.elementSize);
87 keyTable = lastState.typeLocators.keyTable;
88 valueTable = lastState.typeLocators.valueTable;
89 for (int i = 0, l = keyTable.length; i < l; i++)
90 if (keyTable[i] != null)
91 this.typeLocators.put(keyTable[i], valueTable[i]);
95 char[][] getDefinedTypeNamesFor(String typeLocator) {
96 Object c = references.get(typeLocator);
97 if (c instanceof AdditionalTypeCollection)
98 return ((AdditionalTypeCollection) c).definedTypeNames;
99 return null; // means only one type is defined with the same name as the file... saves space
102 boolean isDuplicateLocator(String qualifiedTypeName, String typeLocator) {
103 String existing = (String) typeLocators.get(qualifiedTypeName);
104 return existing != null && !existing.equals(typeLocator);
107 boolean isKnownPackage(String qualifiedPackageName) {
108 if (knownPackageNames == null) {
109 ArrayList names = new ArrayList(typeLocators.elementSize);
110 Object[] keyTable = typeLocators.keyTable;
111 for (int i = 0, l = keyTable.length; i < l; i++) {
112 if (keyTable[i] != null) {
113 String packageName = (String) keyTable[i]; // is a type name of the form p1/p2/A
114 int last = packageName.lastIndexOf('/');
115 packageName = last == -1 ? null : packageName.substring(0, last);
116 while (packageName != null && !names.contains(packageName)) {
117 names.add(packageName);
118 last = packageName.lastIndexOf('/');
119 packageName = last == -1 ? null : packageName.substring(0, last);
123 knownPackageNames = new String[names.size()];
124 names.toArray(knownPackageNames);
126 for (int i = 0, l = knownPackageNames.length; i < l; i++)
127 if (knownPackageNames[i].equals(qualifiedPackageName))
132 void record(String typeLocator, char[][][] qualifiedRefs, char[][] simpleRefs, char[] mainTypeName, ArrayList typeNames) {
133 if (typeNames.size() == 1 && CharOperation.equals(mainTypeName, (char[]) typeNames.get(0))) {
134 references.put(typeLocator, new ReferenceCollection(qualifiedRefs, simpleRefs));
136 char[][] definedTypeNames = new char[typeNames.size()][]; // can be empty when no types are defined
137 typeNames.toArray(definedTypeNames);
138 references.put(typeLocator, new AdditionalTypeCollection(definedTypeNames, qualifiedRefs, simpleRefs));
142 void recordLocatorForType(String qualifiedTypeName, String typeLocator) {
143 this.knownPackageNames = null;
144 typeLocators.put(qualifiedTypeName, typeLocator);
147 void recordStructuralDependency(IProject prereqProject, State prereqState) {
148 if (prereqState != null)
149 structuralBuildTimes.put(prereqProject.getName(), new Long(prereqState.lastStructuralBuildTime));
152 void removeLocator(String typeLocatorToRemove) {
153 this.knownPackageNames = null;
154 references.removeKey(typeLocatorToRemove);
155 typeLocators.removeValue(typeLocatorToRemove);
158 void removePackage(IResourceDelta sourceDelta) {
159 IResource resource = sourceDelta.getResource();
160 switch(resource.getType()) {
161 case IResource.FOLDER :
162 IResourceDelta[] children = sourceDelta.getAffectedChildren();
163 for (int i = 0, l = children.length; i < l; i++)
164 removePackage(children[i]);
166 case IResource.FILE :
167 IPath typeLocatorPath = resource.getProjectRelativePath();
168 if (Util.isJavaFileName(typeLocatorPath.lastSegment()))
169 removeLocator(typeLocatorPath.toString());
173 void removeQualifiedTypeName(String qualifiedTypeNameToRemove) {
174 this.knownPackageNames = null;
175 typeLocators.removeKey(qualifiedTypeNameToRemove);
178 static State read(IProject project, DataInputStream in) throws IOException {
179 if (PHPBuilder.DEBUG)
180 System.out.println("About to read state..."); //$NON-NLS-1$
181 if (VERSION != in.readByte()) {
182 if (PHPBuilder.DEBUG)
183 System.out.println("Found non-compatible state version... answered null"); //$NON-NLS-1$
187 State newState = new State();
188 newState.javaProjectName = in.readUTF();
189 if (!project.getName().equals(newState.javaProjectName)) {
190 if (PHPBuilder.DEBUG)
191 System.out.println("Project's name does not match... answered null"); //$NON-NLS-1$
194 newState.buildNumber = in.readInt();
195 newState.lastStructuralBuildTime = in.readLong();
197 int length = in.readInt();
198 newState.sourceLocations = new ClasspathMultiDirectory[0];
199 // newState.sourceLocations = new ClasspathMultiDirectory[length];
200 // for (int i = 0; i < length; i++) {
201 // IContainer sourceFolder = project, outputFolder = project;
202 // String folderName;
203 // if ((folderName = in.readUTF()).length() > 0) sourceFolder = project.getFolder(folderName);
204 // if ((folderName = in.readUTF()).length() > 0) outputFolder = project.getFolder(folderName);
205 // ClasspathMultiDirectory md =
206 // (ClasspathMultiDirectory) ClasspathLocation.forSourceFolder(sourceFolder, outputFolder, readNames(in));
207 // if (in.readBoolean())
208 // md.hasIndependentOutputFolder = true;
209 // newState.sourceLocations[i] = md;
212 length = in.readInt();
213 // newState.binaryLocations = new ClasspathLocation[length];
214 // IWorkspaceRoot root = project.getWorkspace().getRoot();
215 // for (int i = 0; i < length; i++) {
216 // switch (in.readByte()) {
217 // case SOURCE_FOLDER :
218 // newState.binaryLocations[i] = newState.sourceLocations[in.readInt()];
220 // case BINARY_FOLDER :
221 // IPath path = new Path(in.readUTF());
222 // IContainer outputFolder = path.segmentCount() == 1
223 // ? (IContainer) root.getProject(path.toString())
224 // : (IContainer) root.getFolder(path);
225 // newState.binaryLocations[i] = ClasspathLocation.forBinaryFolder(outputFolder, in.readBoolean());
227 // case EXTERNAL_JAR :
228 // newState.binaryLocations[i] = ClasspathLocation.forLibrary(in.readUTF());
230 // case INTERNAL_JAR :
231 // newState.binaryLocations[i] = ClasspathLocation.forLibrary(root.getFile(new Path(in.readUTF())));
235 newState.structuralBuildTimes = new SimpleLookupTable(length = in.readInt());
236 for (int i = 0; i < length; i++)
237 newState.structuralBuildTimes.put(in.readUTF(), new Long(in.readLong()));
239 String[] internedTypeLocators = new String[length = in.readInt()];
240 for (int i = 0; i < length; i++)
241 internedTypeLocators[i] = in.readUTF();
243 newState.typeLocators = new SimpleLookupTable(length = in.readInt());
244 for (int i = 0; i < length; i++)
245 newState.typeLocators.put(in.readUTF(), internedTypeLocators[in.readInt()]);
247 char[][] internedSimpleNames = ReferenceCollection.internSimpleNames(readNames(in), false);
248 char[][][] internedQualifiedNames = new char[length = in.readInt()][][];
249 for (int i = 0; i < length; i++) {
250 int qLength = in.readInt();
251 char[][] qName = new char[qLength][];
252 for (int j = 0; j < qLength; j++)
253 qName[j] = internedSimpleNames[in.readInt()];
254 internedQualifiedNames[i] = qName;
256 internedQualifiedNames = ReferenceCollection.internQualifiedNames(internedQualifiedNames);
258 newState.references = new SimpleLookupTable(length = in.readInt());
259 for (int i = 0; i < length; i++) {
260 String typeLocator = internedTypeLocators[in.readInt()];
261 ReferenceCollection collection = null;
262 switch (in.readByte()) {
264 char[][] additionalTypeNames = readNames(in);
265 char[][][] qualifiedNames = new char[in.readInt()][][];
266 for (int j = 0, m = qualifiedNames.length; j < m; j++)
267 qualifiedNames[j] = internedQualifiedNames[in.readInt()];
268 char[][] simpleNames = new char[in.readInt()][];
269 for (int j = 0, m = simpleNames.length; j < m; j++)
270 simpleNames[j] = internedSimpleNames[in.readInt()];
271 collection = new AdditionalTypeCollection(additionalTypeNames, qualifiedNames, simpleNames);
274 char[][][] qNames = new char[in.readInt()][][];
275 for (int j = 0, m = qNames.length; j < m; j++)
276 qNames[j] = internedQualifiedNames[in.readInt()];
277 char[][] sNames = new char[in.readInt()][];
278 for (int j = 0, m = sNames.length; j < m; j++)
279 sNames[j] = internedSimpleNames[in.readInt()];
280 collection = new ReferenceCollection(qNames, sNames);
282 newState.references.put(typeLocator, collection);
284 if (PHPBuilder.DEBUG)
285 System.out.println("Successfully read state for " + newState.javaProjectName); //$NON-NLS-1$
289 private static char[][] readNames(DataInputStream in) throws IOException {
290 int length = in.readInt();
291 char[][] names = new char[length][];
292 for (int i = 0; i < length; i++) {
293 int nLength = in.readInt();
294 char[] name = new char[nLength];
295 for (int j = 0; j < nLength; j++)
296 name[j] = in.readChar();
302 void tagAsNoopBuild() {
303 this.buildNumber = -1; // tag the project since it has no source folders and can be skipped
306 boolean wasNoopBuild() {
307 return buildNumber == -1;
310 void tagAsStructurallyChanged() {
311 this.lastStructuralBuildTime = System.currentTimeMillis();
314 boolean wasStructurallyChanged(IProject prereqProject, State prereqState) {
315 if (prereqState != null) {
316 Object o = structuralBuildTimes.get(prereqProject.getName());
317 long previous = o == null ? 0 : ((Long) o).longValue();
318 if (previous == prereqState.lastStructuralBuildTime) return false;
323 void write(DataOutputStream out) throws IOException {
330 * String project name
332 * int last structural build number
334 out.writeByte(VERSION);
335 out.writeUTF(javaProjectName);
336 out.writeInt(buildNumber);
337 out.writeLong(lastStructuralBuildTime);
340 * ClasspathMultiDirectory[]
344 out.writeInt(length = sourceLocations.length);
345 for (int i = 0; i < length; i++) {
346 ClasspathMultiDirectory md = sourceLocations[i];
347 out.writeUTF(md.sourceFolder.getProjectRelativePath().toString());
348 out.writeUTF(md.binaryFolder.getProjectRelativePath().toString());
349 writeNames(md.exclusionPatterns, out);
350 out.writeBoolean(md.hasIndependentOutputFolder);
354 * ClasspathLocation[]
358 // out.writeInt(length = binaryLocations.length);
359 // next : for (int i = 0; i < length; i++) {
360 // ClasspathLocation c = binaryLocations[i];
361 // if (c instanceof ClasspathMultiDirectory) {
362 // out.writeByte(SOURCE_FOLDER);
363 // for (int j = 0, m = sourceLocations.length; j < m; j++) {
364 // if (sourceLocations[j] == c) {
369 // } else if (c instanceof ClasspathDirectory) {
370 // out.writeByte(BINARY_FOLDER);
371 // ClasspathDirectory cd = (ClasspathDirectory) c;
372 // out.writeUTF(cd.binaryFolder.getFullPath().toString());
373 // out.writeBoolean(cd.isOutputFolder);
375 // ClasspathJar jar = (ClasspathJar) c;
376 // if (jar.resource == null) {
377 // out.writeByte(EXTERNAL_JAR);
378 // out.writeUTF(jar.zipFilename);
380 // out.writeByte(INTERNAL_JAR);
381 // out.writeUTF(jar.resource.getFullPath().toString());
387 * Structural build numbers table
388 * String prereq project name
389 * int last structural build number
391 out.writeInt(length = structuralBuildTimes.elementSize);
393 keyTable = structuralBuildTimes.keyTable;
394 valueTable = structuralBuildTimes.valueTable;
395 for (int i = 0, l = keyTable.length; i < l; i++) {
396 if (keyTable[i] != null) {
398 out.writeUTF((String) keyTable[i]);
399 out.writeLong(((Long) valueTable[i]).longValue());
402 if (PHPBuilder.DEBUG && length != 0)
403 System.out.println("structuralBuildNumbers table is inconsistent"); //$NON-NLS-1$
407 * String[] Interned type locators
409 out.writeInt(length = references.elementSize);
410 ArrayList internedTypeLocators = new ArrayList(length);
412 keyTable = references.keyTable;
413 for (int i = 0, l = keyTable.length; i < l; i++) {
414 if (keyTable[i] != null) {
416 String key = (String) keyTable[i];
418 internedTypeLocators.add(key);
421 if (PHPBuilder.DEBUG && length != 0)
422 System.out.println("references table is inconsistent"); //$NON-NLS-1$
426 * Type locators table
428 * int interned locator id
430 out.writeInt(length = typeLocators.elementSize);
432 keyTable = typeLocators.keyTable;
433 valueTable = typeLocators.valueTable;
434 for (int i = 0, l = keyTable.length; i < l; i++) {
435 if (keyTable[i] != null) {
437 out.writeUTF((String) keyTable[i]);
438 out.writeInt(internedTypeLocators.indexOf((String) valueTable[i]));
441 if (PHPBuilder.DEBUG && length != 0)
442 System.out.println("typeLocators table is inconsistent"); //$NON-NLS-1$
446 * char[][][] Interned qualified names
447 * char[][] Interned simple names
449 ArrayList internedQualifiedNames = new ArrayList(31);
450 ArrayList internedSimpleNames = new ArrayList(31);
451 valueTable = references.valueTable;
452 for (int i = 0, l = valueTable.length; i < l; i++) {
453 if (valueTable[i] != null) {
454 ReferenceCollection collection = (ReferenceCollection) valueTable[i];
455 char[][][] qNames = collection.qualifiedNameReferences;
456 for (int j = 0, m = qNames.length; j < m; j++) {
457 char[][] qName = qNames[j];
458 if (!internedQualifiedNames.contains(qName)) { // remember the names have been interned
459 internedQualifiedNames.add(qName);
460 for (int k = 0, n = qName.length; k < n; k++) {
461 char[] sName = qName[k];
462 if (!internedSimpleNames.contains(sName)) // remember the names have been interned
463 internedSimpleNames.add(sName);
467 char[][] sNames = collection.simpleNameReferences;
468 for (int j = 0, m = sNames.length; j < m; j++) {
469 char[] sName = sNames[j];
470 if (!internedSimpleNames.contains(sName)) // remember the names have been interned
471 internedSimpleNames.add(sName);
475 char[][] internedArray = new char[internedSimpleNames.size()][];
476 internedSimpleNames.toArray(internedArray);
477 writeNames(internedArray, out);
478 // now write the interned qualified names as arrays of interned simple names
479 out.writeInt(length = internedQualifiedNames.size());
480 for (int i = 0; i < length; i++) {
481 char[][] qName = (char[][]) internedQualifiedNames.get(i);
482 int qLength = qName.length;
483 out.writeInt(qLength);
484 for (int j = 0; j < qLength; j++)
485 out.writeInt(internedSimpleNames.indexOf(qName[j]));
490 * int interned locator id
491 * ReferenceCollection
493 out.writeInt(length = references.elementSize);
495 keyTable = references.keyTable;
496 for (int i = 0, l = keyTable.length; i < l; i++) {
497 if (keyTable[i] != null) {
499 out.writeInt(internedTypeLocators.indexOf((String) keyTable[i]));
500 ReferenceCollection collection = (ReferenceCollection) valueTable[i];
501 if (collection instanceof AdditionalTypeCollection) {
503 AdditionalTypeCollection atc = (AdditionalTypeCollection) collection;
504 writeNames(atc.definedTypeNames, out);
508 char[][][] qNames = collection.qualifiedNameReferences;
509 int qLength = qNames.length;
510 out.writeInt(qLength);
511 for (int j = 0; j < qLength; j++)
512 out.writeInt(internedQualifiedNames.indexOf(qNames[j]));
513 char[][] sNames = collection.simpleNameReferences;
514 int sLength = sNames.length;
515 out.writeInt(sLength);
516 for (int j = 0; j < sLength; j++)
517 out.writeInt(internedSimpleNames.indexOf(sNames[j]));
520 if (PHPBuilder.DEBUG && length != 0)
521 System.out.println("references table is inconsistent"); //$NON-NLS-1$
525 private void writeNames(char[][] names, DataOutputStream out) throws IOException {
526 int length = names == null ? 0 : names.length;
527 out.writeInt(length);
528 for (int i = 0; i < length; i++) {
529 char[] name = names[i];
530 int nLength = name.length;
531 out.writeInt(nLength);
532 for (int j = 0; j < nLength; j++)
533 out.writeChar(name[j]);
538 * Returns a string representation of the receiver.
540 public String toString() {
541 return "State for " + javaProjectName //$NON-NLS-1$
542 + " (#" + buildNumber //$NON-NLS-1$
543 + " @ " + new Date(lastStructuralBuildTime) //$NON-NLS-1$
549 System.out.println("State for " + javaProjectName + " (" + buildNumber + " @ " + new Date(lastStructuralBuildTime) + ")");
550 System.out.println("\tClass path source locations:");
551 for (int i = 0, l = sourceLocations.length; i < l; i++)
552 System.out.println("\t\t" + sourceLocations[i]);
553 System.out.println("\tClass path binary locations:");
554 for (int i = 0, l = binaryLocations.length; i < l; i++)
555 System.out.println("\t\t" + binaryLocations[i]);
557 System.out.print("\tStructural build numbers table:");
558 if (structuralBuildTimes.elementSize == 0) {
559 System.out.print(" <empty>");
561 Object[] keyTable = structuralBuildTimes.keyTable;
562 Object[] valueTable = structuralBuildTimes.valueTable;
563 for (int i = 0, l = keyTable.length; i < l; i++)
564 if (keyTable[i] != null)
565 System.out.print("\n\t\t" + keyTable[i].toString() + " -> " + valueTable[i].toString());
568 System.out.print("\tType locators table:");
569 if (typeLocators.elementSize == 0) {
570 System.out.print(" <empty>");
572 Object[] keyTable = typeLocators.keyTable;
573 Object[] valueTable = typeLocators.valueTable;
574 for (int i = 0, l = keyTable.length; i < l; i++)
575 if (keyTable[i] != null)
576 System.out.print("\n\t\t" + keyTable[i].toString() + " -> " + valueTable[i].toString());
579 System.out.print("\n\tReferences table:");
580 if (references.elementSize == 0) {
581 System.out.print(" <empty>");
583 Object[] keyTable = references.keyTable;
584 Object[] valueTable = references.valueTable;
585 for (int i = 0, l = keyTable.length; i < l; i++) {
586 if (keyTable[i] != null) {
587 System.out.print("\n\t\t" + keyTable[i].toString());
588 ReferenceCollection c = (ReferenceCollection) valueTable[i];
589 char[][][] qRefs = c.qualifiedNameReferences;
590 System.out.print("\n\t\t\tqualified:");
591 if (qRefs.length == 0)
592 System.out.print(" <empty>");
593 else for (int j = 0, m = qRefs.length; j < m; j++)
594 System.out.print(" '" + CharOperation.toString(qRefs[j]) + "'");
595 char[][] sRefs = c.simpleNameReferences;
596 System.out.print("\n\t\t\tsimple:");
597 if (sRefs.length == 0)
598 System.out.print(" <empty>");
599 else for (int j = 0, m = sRefs.length; j < m; j++)
600 System.out.print(" " + new String(sRefs[j]));
601 if (c instanceof AdditionalTypeCollection) {
602 char[][] names = ((AdditionalTypeCollection) c).definedTypeNames;
603 System.out.print("\n\t\t\tadditional type names:");
604 for (int j = 0, m = names.length; j < m; j++)
605 System.out.print(" " + new String(names[j]));
610 System.out.print("\n\n");