KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > apt > core > internal > generatedfile > GeneratedFileMap


1 /*******************************************************************************
2  * Copyright (c) 2006 BEA Systems, Inc.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * wharley@bea.com - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.apt.core.internal.generatedfile;
12
13 import java.io.BufferedInputStream JavaDoc;
14 import java.io.BufferedOutputStream JavaDoc;
15 import java.io.DataInputStream JavaDoc;
16 import java.io.DataOutputStream JavaDoc;
17 import java.io.File JavaDoc;
18 import java.io.FileInputStream JavaDoc;
19 import java.io.FileOutputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.util.Collections JavaDoc;
22 import java.util.EnumSet JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Set JavaDoc;
26 import java.util.Map.Entry;
27
28 import org.eclipse.core.resources.IFile;
29 import org.eclipse.core.resources.IProject;
30 import org.eclipse.core.runtime.IPath;
31 import org.eclipse.core.runtime.Path;
32 import org.eclipse.jdt.apt.core.internal.AptPlugin;
33 import org.eclipse.jdt.apt.core.internal.util.ManyToMany;
34
35 /**
36  * A bidirectional many-to-many map from parent files to generated files.
37  * This extends the functionality of ManyToMany by adding serialization.
38  * The object also tracks attributes of the generated files.
39  */

40 public class GeneratedFileMap extends ManyToMany<IFile, IFile> {
41     
42     public enum Flags {
43         /** Non-source files, e.g., text or xml. */
44         NONSOURCE;
45     }
46
47     // Version 2 since Eclipse 3.3.1: add ability to track attributes of generated files
48
private static final int SERIALIZATION_VERSION = 2;
49     
50     private final IProject _proj;
51     
52     private final Map JavaDoc<IFile, Set JavaDoc<Flags>> _flags = new HashMap JavaDoc<IFile, Set JavaDoc<Flags>>();
53     
54     public GeneratedFileMap(IProject proj) {
55         _proj = proj;
56         readState();
57     }
58     
59     /* (non-Javadoc)
60      * @see org.eclipse.jdt.apt.core.internal.util.ManyToMany#clear()
61      */

62     @Override JavaDoc
63     public synchronized boolean clear() {
64         _flags.clear();
65         return super.clear();
66     }
67
68     /* (non-Javadoc)
69      * @see org.eclipse.jdt.apt.core.internal.util.ManyToMany#remove(java.lang.Object, java.lang.Object)
70      */

71     @Override JavaDoc
72     public synchronized boolean remove(IFile key, IFile value) {
73         boolean removed = super.remove(key, value);
74         if (removed) {
75             if (!containsValue(value)) {
76                 _flags.remove(value);
77             }
78         }
79         return removed;
80     }
81
82     /* (non-Javadoc)
83      * @see org.eclipse.jdt.apt.core.internal.util.ManyToMany#removeKey(java.lang.Object)
84      */

85     @Override JavaDoc
86     public synchronized boolean removeKey(IFile key) {
87         Set JavaDoc<IFile> values = getValues(key);
88         boolean removed = super.removeKey(key);
89         if (removed) {
90             for (IFile value : values) {
91                 if (!containsValue(value)) {
92                     _flags.remove(value);
93                 }
94             }
95         }
96         return removed;
97     }
98
99     /* (non-Javadoc)
100      * @see org.eclipse.jdt.apt.core.internal.util.ManyToMany#removeValue(java.lang.Object)
101      */

102     @Override JavaDoc
103     public synchronized boolean removeValue(IFile value) {
104         boolean removed = super.removeValue(value);
105         if (removed) {
106             _flags.remove(value);
107         }
108         return removed;
109     }
110
111     /**
112      * Clear the file dependencies and delete the serialized state.
113      * This will take effect even if the dirty bit is not set.
114      */

115     public synchronized void clearState() {
116         clear();
117         File JavaDoc state = getStateFile(_proj);
118         if (state != null) {
119             boolean successfullyDeleted = state.delete();
120             if (!successfullyDeleted && state.exists()) {
121                 AptPlugin.log(new IOException JavaDoc("Could not delete apt dependency state file"), //$NON-NLS-1$
122
state.getPath());
123             }
124         }
125         clearDirtyBit();
126     }
127     
128     /**
129      * Convenience method, equivalent to put(key, value, [no flags])
130      */

131     @Override JavaDoc
132     public boolean put(IFile parent, IFile generated) {
133         return put(parent, generated, Collections.<Flags>emptySet());
134     }
135     
136     /**
137      * Convenience method, equivalent to put(key, value, isSource ? [no flags] : [NONSOURCE])
138      */

139     public boolean put(IFile parent, IFile generated, boolean isSource) {
140         return put(parent, generated, isSource ? Collections.<Flags>emptySet() : EnumSet.of(Flags.NONSOURCE));
141     }
142     
143     /**
144      * Add a parent-to-generated association and specify attributes for the generated file.
145      * The attributes are associated with the file, not the link: that is, a given generated
146      * file can only have one set of attributes, not a different set per parent. The attributes
147      * set in the most recent call will override those set in previous calls.
148      */

149     public synchronized boolean put(IFile parent, IFile generated, Set JavaDoc<Flags> flags) {
150         if (flags.isEmpty()) {
151             _flags.remove(generated);
152         }
153         else {
154             _flags.put(generated, flags);
155         }
156         return super.put(parent, generated);
157     }
158     
159     public Set JavaDoc<Flags> getFlags(IFile generated) {
160         Set JavaDoc<Flags> flags = _flags.get(generated);
161         return flags == null ? Collections.<Flags>emptySet() : flags;
162     }
163     
164     /**
165      * Convenience method, equivalent to !getFlags(generated).contains(Flags.NONSOURCE)
166      * @return true if the generated file is a source (Java) file rather than text, xml, etc.
167      */

168     public boolean isSource(IFile generated) {
169         return !getFlags(generated).contains(Flags.NONSOURCE);
170     }
171     
172     /**
173      * Utility method for serialization
174      */

175     private String JavaDoc convertIFileToPath(IFile file) {
176         IPath path = file.getProjectRelativePath();
177         return path.toOSString();
178     }
179     
180     /**
181      * Utility method for deserialization
182      */

183     private IFile convertPathToIFile(String JavaDoc projectRelativeString) {
184         IPath path = new Path(projectRelativeString);
185         return _proj.getFile(path);
186     }
187     
188     /**
189      * Returns the File to use for saving and restoring the last built state for the given project.
190      * Returns null if the project does not exists (e.g. has been deleted)
191      */

192     private File JavaDoc getStateFile(IProject project) {
193         if (!project.exists()) return null;
194         IPath workingLocation = project.getWorkingLocation(AptPlugin.PLUGIN_ID);
195         return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$
196
}
197     
198     /**
199      * Reads the last serialized build state into memory. This includes dependency
200      * information so that we do not need to do a clean build in order to recreate
201      * our dependencies.
202      *
203      * File format:
204      *
205      * int version
206      * int sizeOfMap
207      * String parentIFilePath
208      * int numberOfChildren
209      * String childIFilePath
210      *
211      * This method is not synchronized because it is called only from this object's constructor.
212      */

213     private void readState() {
214         File JavaDoc file = getStateFile(_proj);
215         if (file == null || !file.exists()) {
216             // We'll just start with no dependencies
217
return;
218         }
219         DataInputStream JavaDoc in = null;
220         try {
221             in= new DataInputStream JavaDoc(new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(file)));
222             int version = in.readInt();
223             if (version != SERIALIZATION_VERSION) {
224                 throw new IOException JavaDoc("Dependency map file version does not match. Expected " //$NON-NLS-1$
225
+ SERIALIZATION_VERSION + ", but found " + version); //$NON-NLS-1$
226
}
227             int sizeOfMap = in.readInt();
228             
229             // For each entry, we'll have a parent and a set of children,
230
// which we can drop into the parent -> child map.
231
for (int parentIndex=0; parentIndex<sizeOfMap; parentIndex++) {
232                 String JavaDoc parentPath = in.readUTF();
233                 IFile parent = convertPathToIFile(parentPath);
234                 int numChildren = in.readInt();
235                 for (int childIndex = 0; childIndex<numChildren; childIndex++) {
236                     String JavaDoc childPath = in.readUTF();
237                     IFile child = convertPathToIFile(childPath);
238                     // add the child to the parent->child map
239
put(parent, child);
240                 }
241             }
242             
243             // Now the _flags map:
244
int sizeOfFlags = in.readInt();
245             for (int i = 0; i < sizeOfFlags; ++i) {
246                 String JavaDoc childPath = in.readUTF();
247                 IFile child = convertPathToIFile(childPath);
248                 if (!containsValue(child)) {
249                     throw new IOException JavaDoc("Error in generated file attributes: did not expect file " + childPath); //$NON-NLS-1$
250
}
251                 
252                 int attributeCount = in.readInt();
253                 EnumSet JavaDoc<Flags> flags = EnumSet.noneOf(Flags.class);
254                 for (int j = 0; j < attributeCount; ++j) {
255                     String JavaDoc attr = in.readUTF();
256                     Flags f = Flags.valueOf(attr);
257                     flags.add(f);
258                 }
259                 _flags.put(child, flags);
260             }
261             
262             // our serialized and in-memory states are now identical
263
clearDirtyBit();
264         }
265         catch (IOException JavaDoc ioe) {
266             // Avoid partial initialization
267
clear();
268             // We can safely continue without having read our dependencies.
269
AptPlugin.logWarning(ioe, "Could not read APT dependencies: generated files may not be deleted until the next clean"); //$NON-NLS-1$
270
}
271         catch (IllegalArgumentException JavaDoc iae) {
272             // Avoid partial initialization
273
clear();
274             // We can safely continue without having read our dependencies.
275
AptPlugin.logWarning(iae, "Could not read APT dependencies: generated files may not be deleted until the next clean"); //$NON-NLS-1$
276
}
277         finally {
278             if (in != null) {
279                 try {in.close();} catch (IOException JavaDoc ioe) {}
280             }
281         }
282     }
283     
284     /**
285      * Write our dependencies to disk. If not dirty, nothing is written.
286      */

287     public synchronized void writeState() {
288         if (!isDirty()) {
289             return;
290         }
291         File JavaDoc file = getStateFile(_proj);
292         if (file == null) {
293             // Cannot write state, as project has been deleted
294
return;
295         }
296         file.delete();
297         
298         DataOutputStream JavaDoc out = null;
299         try {
300             out = new DataOutputStream JavaDoc(new BufferedOutputStream JavaDoc(new FileOutputStream JavaDoc(file)));
301             
302             out.writeInt(SERIALIZATION_VERSION);
303             
304             // Number of parent files
305
Set JavaDoc<IFile> parents = getKeySet();
306             out.writeInt(parents.size());
307             
308             // for each parent...
309
for (IFile parent : parents) {
310                 
311                 // ...parent name
312
out.writeUTF(convertIFileToPath(parent));
313                 
314                 Set JavaDoc<IFile> children = getValues(parent);
315                 
316                 // ...number of children
317
out.writeInt(children.size());
318                 
319                 // for each child...
320
for (IFile child : children) {
321                     // ...child name.
322
out.writeUTF(convertIFileToPath(child));
323                 }
324             }
325             
326             // Number of generated files with attributes
327
out.writeInt(_flags.size());
328             
329             // for each generated file that has attributes...
330
for (Entry<IFile, Set JavaDoc<Flags>> entry : _flags.entrySet()) {
331                 // ...generated file name
332
out.writeUTF(convertIFileToPath(entry.getKey()));
333                 
334                 Set JavaDoc<Flags> flags = entry.getValue();
335                 // ...number of attributes
336
out.writeInt(flags.size());
337                 for (Flags f : flags) {
338                     // ...attribute name
339
out.writeUTF(f.name());
340                 }
341             }
342             
343             // our serialized and in-memory states are now identical
344
clearDirtyBit();
345             out.flush();
346         }
347         catch (IOException JavaDoc ioe) {
348             // We can safely continue without having written our dependencies.
349
AptPlugin.logWarning(ioe, "Could not serialize APT dependencies"); //$NON-NLS-1$
350
}
351         finally {
352             if (out != null) {
353                 try {
354                     out.close();
355                 }
356                 catch (IOException JavaDoc ioe) {
357                     // Do nothing
358
}
359             }
360         }
361     }
362     
363
364 }
365
Popular Tags