KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > properties > PropertyBucket


1 /*******************************************************************************
2  * Copyright (c) 2004, 2005 IBM Corporation and others.
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  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.properties;
12
13 import java.io.*;
14 import java.util.*;
15 import org.eclipse.core.internal.localstore.Bucket;
16 import org.eclipse.core.internal.resources.ResourceException;
17 import org.eclipse.core.internal.utils.Messages;
18 import org.eclipse.core.resources.IResourceStatus;
19 import org.eclipse.core.runtime.*;
20 import org.eclipse.osgi.util.NLS;
21
22 public class PropertyBucket extends Bucket {
23     public static class PropertyEntry extends Entry {
24
25         private final static Comparator COMPARATOR = new Comparator() {
26             public int compare(Object JavaDoc o1, Object JavaDoc o2) {
27                 int qualifierComparison = ((String JavaDoc[]) o1)[0].compareTo(((String JavaDoc[]) o2)[0]);
28                 return qualifierComparison != 0 ? qualifierComparison : ((String JavaDoc[]) o1)[1].compareTo(((String JavaDoc[]) o2)[1]);
29             }
30         };
31         private static final String JavaDoc[][] EMPTY_DATA = new String JavaDoc[0][];
32         /**
33          * value is a String[][] of {{propertyKey.qualifier, propertyKey.localName, propertyValue}}
34          */

35         private String JavaDoc[][] value;
36
37         /**
38          * Deletes the property with the given name, and returns the result array. Returns the original
39          * array if the property to be deleted could not be found. Returns <code>null</code> if the property was found
40          * and the original array had size 1 (instead of a zero-length array).
41          */

42         static String JavaDoc[][] delete(String JavaDoc[][] existing, QualifiedName propertyName) {
43             // a size-1 array is a special case
44
if (existing.length == 1)
45                 return (existing[0][0].equals(propertyName.getQualifier()) && existing[0][1].equals(propertyName.getLocalName())) ? null : existing;
46             // find the guy to delete
47
int deletePosition = search(existing, propertyName);
48             if (deletePosition < 0)
49                 // not found, nothing to delete
50
return existing;
51             String JavaDoc[][] newValue = new String JavaDoc[existing.length - 1][];
52             if (deletePosition > 0)
53                 // copy elements preceding the one to be removed
54
System.arraycopy(existing, 0, newValue, 0, deletePosition);
55             if (deletePosition < existing.length - 1)
56                 // copy elements succeeding the one to be removed
57
System.arraycopy(existing, deletePosition + 1, newValue, deletePosition, newValue.length - deletePosition);
58             return newValue;
59         }
60
61         static String JavaDoc[][] insert(String JavaDoc[][] existing, QualifiedName propertyName, String JavaDoc propertyValue) {
62             // look for the right spot where to insert the new guy
63
int index = search(existing, propertyName);
64             if (index >= 0) {
65                 // found existing occurrence - just replace the value
66
existing[index][2] = propertyValue;
67                 return existing;
68             }
69             // not found - insert
70
int insertPosition = -index - 1;
71             String JavaDoc[][] newValue = new String JavaDoc[existing.length + 1][];
72             if (insertPosition > 0)
73                 System.arraycopy(existing, 0, newValue, 0, insertPosition);
74             newValue[insertPosition] = new String JavaDoc[] {propertyName.getQualifier(), propertyName.getLocalName(), propertyValue};
75             if (insertPosition < existing.length)
76                 System.arraycopy(existing, insertPosition, newValue, insertPosition + 1, existing.length - insertPosition);
77             return newValue;
78         }
79
80         /**
81          * Merges two entries (are always sorted). Duplicated additions replace existing ones.
82          */

83         static Object JavaDoc merge(String JavaDoc[][] base, String JavaDoc[][] additions) {
84             int additionPointer = 0;
85             int basePointer = 0;
86             int added = 0;
87             String JavaDoc[][] result = new String JavaDoc[base.length + additions.length][];
88             while (basePointer < base.length && additionPointer < additions.length) {
89                 int comparison = COMPARATOR.compare(base[basePointer], additions[additionPointer]);
90                 if (comparison == 0) {
91                     result[added++] = additions[additionPointer++];
92                     // duplicate, override
93
basePointer++;
94                 } else if (comparison < 0)
95                     result[added++] = base[basePointer++];
96                 else
97                     result[added++] = additions[additionPointer++];
98             }
99             // copy the remaining states from either additions or base arrays
100
String JavaDoc[][] remaining = basePointer == base.length ? additions : base;
101             int remainingPointer = basePointer == base.length ? additionPointer : basePointer;
102             int remainingCount = remaining.length - remainingPointer;
103             System.arraycopy(remaining, remainingPointer, result, added, remainingCount);
104             added += remainingCount;
105             if (added == base.length + additions.length)
106                 // no collisions
107
return result;
108             // there were collisions, need to compact
109
String JavaDoc[][] finalResult = new String JavaDoc[added][];
110             System.arraycopy(result, 0, finalResult, 0, finalResult.length);
111             return finalResult;
112         }
113
114         private static int search(String JavaDoc[][] existing, QualifiedName propertyName) {
115             return Arrays.binarySearch(existing, new String JavaDoc[] {propertyName.getQualifier(), propertyName.getLocalName(), null}, COMPARATOR);
116         }
117
118         public PropertyEntry(IPath path, PropertyEntry base) {
119             super(path);
120             //copy 2-dimensional array [x][y]
121
int xLen = base.value.length;
122             this.value = new String JavaDoc[xLen][];
123             for (int i = 0; i < xLen; i++) {
124                 int yLen = base.value[i].length;
125                 this.value[i] = new String JavaDoc[yLen];
126                 System.arraycopy(base.value[i], 0, value[i], 0, yLen);
127             }
128         }
129
130         /**
131          * @param path
132          * @param value is a String[][] {{propertyKey, propertyValue}}
133          */

134         protected PropertyEntry(IPath path, String JavaDoc[][] value) {
135             super(path);
136             this.value = value;
137         }
138
139         /**
140          * Compacts the data array removing any null slots. If non-null slots
141          * are found, the entry is marked for removal.
142          */

143         private void compact() {
144             if (!isDirty())
145                 return;
146             int occurrences = 0;
147             for (int i = 0; i < value.length; i++)
148                 if (value[i] != null)
149                     value[occurrences++] = value[i];
150             if (occurrences == value.length)
151                 // no states deleted
152
return;
153             if (occurrences == 0) {
154                 // no states remaining
155
value = EMPTY_DATA;
156                 delete();
157                 return;
158             }
159             String JavaDoc[][] result = new String JavaDoc[occurrences][];
160             System.arraycopy(value, 0, result, 0, occurrences);
161             value = result;
162         }
163
164         public int getOccurrences() {
165             return value == null ? 0 : value.length;
166         }
167
168         public String JavaDoc getProperty(QualifiedName name) {
169             int index = search(value, name);
170             return index < 0 ? null : value[index][2];
171         }
172
173         public Object JavaDoc getPropertyName(int i) {
174             return new QualifiedName(this.value[i][0], this.value[i][1]);
175         }
176
177         public Object JavaDoc getPropertyValue(int i) {
178             return this.value[i][2];
179         }
180
181         public Object JavaDoc getValue() {
182             return value;
183         }
184
185         public void visited() {
186             compact();
187         }
188     }
189
190     public static final byte INDEX = 1;
191
192     public static final byte QNAME = 2;
193
194     /** Version number for the current implementation file's format.
195      * <p>
196      * Version 1:
197      * <pre>
198      * FILE ::= VERSION_ID ENTRY+
199      * ENTRY ::= PATH PROPERTY_COUNT PROPERTY+
200      * PATH ::= string (does not contain project name)
201      * PROPERTY_COUNT ::= int
202      * PROPERTY ::= QUALIFIER LOCAL_NAME VALUE
203      * QUALIFIER ::= INDEX | QNAME
204      * INDEX -> byte int
205      * QNAME -> byte string
206      * UUID ::= byte[16]
207      * LAST_MODIFIED ::= byte[8]
208      * </pre>
209      * </p>
210      */

211     private static final byte VERSION = 1;
212
213     private final List qualifierIndex = new ArrayList();
214
215     public PropertyBucket() {
216         super();
217     }
218
219     protected Entry createEntry(IPath path, Object JavaDoc value) {
220         return new PropertyEntry(path, (String JavaDoc[][]) value);
221     }
222
223     private PropertyEntry getEntry(IPath path) {
224         String JavaDoc pathAsString = path.toString();
225         String JavaDoc[][] existing = (String JavaDoc[][]) getEntryValue(pathAsString);
226         if (existing == null)
227             return null;
228         return new PropertyEntry(path, existing);
229     }
230
231     /* (non-Javadoc)
232      * @see org.eclipse.core.internal.localstore.Bucket#getIndexFileName()
233      */

234     protected String JavaDoc getIndexFileName() {
235         return "properties.index"; //$NON-NLS-1$
236
}
237
238     public String JavaDoc getProperty(IPath path, QualifiedName name) {
239         PropertyEntry entry = getEntry(path);
240         if (entry == null)
241             return null;
242         return entry.getProperty(name);
243     }
244
245     protected byte getVersion() {
246         return VERSION;
247     }
248
249     /* (non-Javadoc)
250      * @see org.eclipse.core.internal.localstore.Bucket#getVersionFileName()
251      */

252     protected String JavaDoc getVersionFileName() {
253         return "properties.version"; //$NON-NLS-1$
254
}
255
256     public void load(String JavaDoc newProjectName, File baseLocation, boolean force) throws CoreException {
257         qualifierIndex.clear();
258         super.load(newProjectName, baseLocation, force);
259     }
260
261     protected Object JavaDoc readEntryValue(DataInputStream source) throws IOException, CoreException {
262         int length = source.readUnsignedShort();
263         String JavaDoc[][] properties = new String JavaDoc[length][3];
264         for (int j = 0; j < properties.length; j++) {
265             // qualifier
266
byte constant = source.readByte();
267             switch (constant) {
268                 case QNAME :
269                     properties[j][0] = source.readUTF();
270                     qualifierIndex.add(properties[j][0]);
271                     break;
272                 case INDEX :
273                     properties[j][0] = (String JavaDoc) qualifierIndex.get(source.readInt());
274                     break;
275                 default :
276                     //if we get here the properties file is corrupt
277
IPath resourcePath = projectName == null ? Path.ROOT : Path.ROOT.append(projectName);
278                     String JavaDoc msg = NLS.bind(Messages.properties_readProperties, resourcePath.toString());
279                     throw new ResourceException(IResourceStatus.FAILED_READ_METADATA, null, msg, null);
280             }
281             // localName
282
properties[j][1] = source.readUTF();
283             // propertyValue
284
properties[j][2] = source.readUTF();
285         }
286         return properties;
287     }
288
289     public void save() throws CoreException {
290         qualifierIndex.clear();
291         super.save();
292     }
293
294     public void setProperties(PropertyEntry entry) {
295         IPath path = entry.getPath();
296         String JavaDoc[][] additions = (String JavaDoc[][]) entry.getValue();
297         String JavaDoc pathAsString = path.toString();
298         String JavaDoc[][] existing = (String JavaDoc[][]) getEntryValue(pathAsString);
299         if (existing == null) {
300             setEntryValue(pathAsString, additions);
301             return;
302         }
303         setEntryValue(pathAsString, PropertyEntry.merge(existing, additions));
304     }
305
306     public void setProperty(IPath path, QualifiedName name, String JavaDoc value) {
307         String JavaDoc pathAsString = path.toString();
308         String JavaDoc[][] existing = (String JavaDoc[][]) getEntryValue(pathAsString);
309         if (existing == null) {
310             if (value != null)
311                 setEntryValue(pathAsString, new String JavaDoc[][] {{name.getQualifier(), name.getLocalName(), value}});
312             return;
313         }
314         String JavaDoc[][] newValue;
315         if (value != null)
316             newValue = PropertyEntry.insert(existing, name, value);
317         else
318             newValue = PropertyEntry.delete(existing, name);
319         // even if newValue == existing we should mark as dirty (insert may just change the existing array)
320
setEntryValue(pathAsString, newValue);
321     }
322
323     protected void writeEntryValue(DataOutputStream destination, Object JavaDoc entryValue) throws IOException {
324         String JavaDoc[][] properties = (String JavaDoc[][]) entryValue;
325         destination.writeShort(properties.length);
326         for (int j = 0; j < properties.length; j++) {
327             // writes the property key qualifier
328
int index = qualifierIndex.indexOf(properties[j][0]);
329             if (index == -1) {
330                 destination.writeByte(QNAME);
331                 destination.writeUTF(properties[j][0]);
332                 qualifierIndex.add(properties[j][0]);
333             } else {
334                 destination.writeByte(INDEX);
335                 destination.writeInt(index);
336             }
337             // then the local name
338
destination.writeUTF(properties[j][1]);
339             // then the property value
340
destination.writeUTF(properties[j][2]);
341         }
342     }
343 }
344
Popular Tags