1 19 package org.netbeans.modules.subversion.client.parser; 20 21 import java.io.BufferedReader ; 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.FileReader ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.InputStreamReader ; 28 import java.util.HashMap ; 29 import java.util.Map ; 30 import java.util.Set ; 31 import org.openide.ErrorManager; 32 import org.openide.xml.XMLUtil; 33 import org.xml.sax.Attributes ; 34 import org.xml.sax.InputSource ; 35 import org.xml.sax.SAXException ; 36 import org.xml.sax.SAXParseException ; 37 import org.xml.sax.XMLReader ; 38 import org.xml.sax.helpers.DefaultHandler ; 39 40 44 public class EntriesCache { 45 46 47 private static final String SVN_THIS_DIR = "svn:this_dir"; private static final String EMPTY_STRING = ""; 49 private static final String DELIMITER = "\f"; 50 51 private class EntryAttributes extends HashMap <String , Map <String , String >> { }; 52 53 57 static String [] entryFileAttributes = new String [] { 58 "name", 59 "kind", 60 "revision", 61 "url", 62 "repos", 63 "schedule", 64 "text-time", 65 "checksum", 66 "committed-date", 67 "committed-rev", 68 "last-author", 69 "has-props", 70 "has-prop-mods", 71 "cachable-props", 72 "present-props", 73 "prop-reject-file", 74 "conflict-old", 75 "conflict-new", 76 "conflict-wrk", 77 "copied", 78 "copyfrom-url", 79 "copyfrom-rev", 80 "deleted", 81 "absent", 82 "incomplete", 83 "uuid", 84 "lock-token", 85 "lock-owner", 86 "lock-comment", 87 "lock-creation-date", 88 }; 89 90 private static final Set <String > BOOLEAN_ATTRIBUTES = new java.util.HashSet <String >(); 91 static { 92 BOOLEAN_ATTRIBUTES.add("has-props"); 93 BOOLEAN_ATTRIBUTES.add("has-prop-mods"); 94 BOOLEAN_ATTRIBUTES.add("copied"); 95 BOOLEAN_ATTRIBUTES.add("deleted"); 96 } 97 98 private class EntriesFile { 99 long ts; 100 long size; 101 EntryAttributes attributes; 102 EntriesFile(EntryAttributes attributes, long ts, long size) { 103 this.ts = ts; 104 this.size = size; 105 this.attributes = attributes; 106 } 107 } 108 109 private class Entries extends HashMap <String , EntriesFile> {}; 110 111 private Entries entries; 112 private static EntriesCache instance; 113 114 private EntriesCache() { } 115 116 static EntriesCache getInstance() { 117 if(instance == null) { 118 instance = new EntriesCache(); 119 } 120 return instance; 121 } 122 123 Map <String , String > getFileAttributes(File file) throws IOException , SAXException { 124 File entriesFile = SvnWcUtils.getEntriesFile(file); 125 if(entriesFile==null) { 126 return null; 127 } 128 return getFileAttributes(entriesFile, file); 129 } 130 131 private synchronized Map <String , String > getFileAttributes(final File entriesFile, final File file) throws IOException , SAXException { 132 EntriesFile ef = getEntries().get(entriesFile.getAbsolutePath()); 133 long lastModified = entriesFile.lastModified(); 134 long fileLength = entriesFile.length(); 135 if(ef == null || ef.ts != lastModified || ef.size != fileLength) { 136 EntryAttributes ea = getAttributesFromEntriesFile(entriesFile); 137 ef = new EntriesFile(getMergedAttributes(ea), lastModified, fileLength); 138 getEntries().put(entriesFile.getAbsolutePath(), ef); 139 } 140 if(ef.attributes.get(file.getName()) == null) { 141 Map <String , String > attributes = mergeThisDirAttributes(file.isDirectory(), file.getName(), ef.attributes); 144 } 145 146 return ef.attributes.get(file.isDirectory() ? SVN_THIS_DIR : file.getName()); 147 } 148 149 private EntryAttributes getMergedAttributes(EntryAttributes ea) throws SAXException { 150 for(String fileName : ea.keySet()) { 151 boolean isDirectory = ea.get(fileName).get("kind").equals("dir"); 152 Map <String , String > attributes = mergeThisDirAttributes(isDirectory, fileName, ea); 153 if(isDirectory) { 154 attributes.put(WorkingCopyDetails.IS_HANDLED, "" + (ea.get(SVN_THIS_DIR).get("deleted") == null)); } else { 156 if(ea.get(fileName) != null) { 157 for(Map.Entry <String , String > entry : ea.get(fileName).entrySet()) { 158 attributes.put(entry.getKey(), entry.getValue()); 159 } 160 } 161 attributes.put(WorkingCopyDetails.IS_HANDLED, "" + (ea.containsKey(fileName) && ea.get("deleted") == null)); } 164 } 165 return ea; 166 } 167 168 private Map <String , String > mergeThisDirAttributes(final boolean isDirectory, final String fileName, final EntryAttributes ea) { 169 Map <String , String > attributes = ea.get(fileName); 170 if(attributes == null) { 171 attributes = new HashMap <String , String >(); 172 ea.put(fileName, attributes); 173 } 174 for(Map.Entry <String , String > entry : ea.get(SVN_THIS_DIR).entrySet()) { 175 String key = entry.getKey(); 176 String value = entry.getValue(); 177 if(isDirectory) { 178 attributes.put(key, value); 179 } else { 180 if(key.equals("url")) { 181 if( attributes.get(key) == null ) { 182 attributes.put(key, value + "/" + fileName); 183 } 184 } else if( key.equals("uuid") || 185 key.equals("repos") || 186 key.equals("revision") || 187 key.equals(WorkingCopyDetails.VERSION_ATTR_KEY)) { 188 if( attributes.get(key) == null ) { 189 attributes.put(key, value); 190 } 191 } 192 } 193 } 194 return attributes; 195 } 196 197 private EntryAttributes getAttributesFromEntriesFile(File entriesFile) throws IOException , SAXException { 198 boolean isXml = false; 202 BufferedReader fileReader = new BufferedReader (new InputStreamReader (new FileInputStream (entriesFile), "UTF8")); 203 try { 204 String firstLine = fileReader.readLine(); 205 try { 206 Integer.valueOf(firstLine); 207 isXml = false; 208 } catch (NumberFormatException ex) { 209 isXml = true; 210 } 211 212 if (isXml) { 213 return loadAttributesFromXml(entriesFile); 214 } else { 215 return loadAttributesFromPlainText(fileReader, entriesFile.getAbsolutePath()); 216 } 217 } finally { 218 fileReader.close(); 219 } 220 } 221 222 private EntryAttributes loadAttributesFromXml(File entriesFile) throws IOException , SAXException { 223 XMLReader saxReader = XMLUtil.createXMLReader(); 225 XmlEntriesHandler xmlEntriesHandler = new XmlEntriesHandler(); 226 saxReader.setContentHandler(xmlEntriesHandler); 227 saxReader.setErrorHandler(xmlEntriesHandler); 228 InputStream inputStream = new java.io.FileInputStream (entriesFile); 229 230 try { 231 saxReader.parse(new InputSource (inputStream)); 232 } catch (SAXException ex) { 233 throw ex; 234 } finally { 235 inputStream.close(); 236 } 237 return xmlEntriesHandler.getEntryAttributes(); 238 } 239 240 private EntryAttributes loadAttributesFromPlainText(BufferedReader entriesReader, String entryFilePath) throws IOException { 242 EntryAttributes returnValue = new EntryAttributes(); 243 244 int attrIndex = 0; 245 246 String entryName = null; 247 Map <String , String > attributes = new HashMap <String , String >(); 248 249 String nextLine = entriesReader.readLine(); 250 while (nextLine != null) { 251 if (attrIndex == 0) { 252 entryName = nextLine; 253 if (entryName.equals(EMPTY_STRING)) { 254 entryName = SVN_THIS_DIR; 255 } 256 } 257 258 if (!(EMPTY_STRING.equals(nextLine))) { 259 if (isBooleanValue(entryFileAttributes[attrIndex])) { 260 nextLine = "true"; 261 } 262 attributes.put(entryFileAttributes[attrIndex], nextLine); 263 } 264 attrIndex++; 265 nextLine = entriesReader.readLine(); 266 267 if(nextLine != null && attrIndex > entryFileAttributes.length - 1) { 268 ErrorManager.getDefault().log(ErrorManager.WARNING, "Skipping attribute from position " + attrIndex + " in entry file " + entryFilePath); for( ; nextLine != null && !DELIMITER.equals(nextLine); nextLine = entriesReader.readLine()); 270 } 271 272 if (DELIMITER.equals(nextLine)) { 273 attributes.put(WorkingCopyDetails.VERSION_ATTR_KEY, WorkingCopyDetails.VERSION_14); 274 returnValue.put(entryName, attributes); 275 attributes = new HashMap <String , String >(); 276 attrIndex = 0; 277 nextLine = entriesReader.readLine(); 278 continue; 279 } 280 281 } 282 283 return returnValue; 284 } 285 286 private static boolean isBooleanValue(String attribute) { 287 return BOOLEAN_ATTRIBUTES.contains(attribute); 288 } 289 290 private class XmlEntriesHandler extends DefaultHandler { 291 292 private static final String ENTRY_ELEMENT_NAME = "entry"; private static final String NAME_ATTRIBUTE = "name"; private EntryAttributes entryAttributes; 295 296 public void startElement(String uri, String localName, String qName, Attributes elementAttributes) throws SAXException { 297 if (ENTRY_ELEMENT_NAME.equals(qName)) { 298 Map <String , String > attributes = new HashMap <String , String >(); 299 for (int i = 0; i < elementAttributes.getLength(); i++) { 300 String name = elementAttributes.getQName(i); 301 String value = elementAttributes.getValue(i); 302 attributes.put(name, value); 303 } 304 305 String nameValue = attributes.get(NAME_ATTRIBUTE); 306 if (EMPTY_STRING.equals(nameValue)) { 307 nameValue = SVN_THIS_DIR; 308 } 309 if(entryAttributes == null) { 310 entryAttributes = new EntryAttributes(); 311 } 312 attributes.put(WorkingCopyDetails.VERSION_ATTR_KEY, WorkingCopyDetails.VERSION_13); 313 entryAttributes.put(nameValue, attributes); 314 } 315 } 316 317 public void error(SAXParseException e) throws SAXException { 318 throw e; 319 } 320 321 public void fatalError(SAXParseException e) throws SAXException { 322 throw e; 323 } 324 325 public EntryAttributes getEntryAttributes() { 326 return entryAttributes; 327 } 328 } 329 330 private Entries getEntries() { 331 if(entries == null) { 332 entries = new Entries(); 333 } 334 return entries; 335 } 336 337 } 338 | Popular Tags |