1 /******************************************************************************* 2 * Copyright (c) 2004, 2018 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.core.internal.registry; 15 16 import java.io.*; 17 import java.lang.ref.SoftReference; 18 import java.nio.charset.StandardCharsets; 19 import java.util.HashMap; 20 import java.util.Map; 21 import org.eclipse.core.runtime.IStatus; 22 import org.eclipse.core.runtime.Status; 23 import org.eclipse.core.runtime.spi.RegistryContributor; 24 import org.eclipse.osgi.util.NLS; 25 26 public class TableReader { 27 //Markers in the cache 28 static final int NULL = 0; 29 static final int OBJECT = 1; 30 static final int LOBJECT = 2; 31 32 //The version of the cache 33 static final int CACHE_VERSION = 8; 34 // Version 1 -> 2: the contributor Ids changed from "long" to "String" 35 // Version 2 -> 3: added namespace index and the table of contributors 36 // Version 3 -> 4: offset table saved in a binary form (performance) 37 // Version 4 -> 5: remove support added in version 4 to save offset table in a binary form (performance) 38 // Version 5 -> 6: replace HashtableOfInt with OffsetTable (memory usage optimization) 39 // Version 6 -> 7: added option for multi-language support 40 // Version 7 -> 8: added support for large UTF-8 strings 41 42 //Informations representing the MAIN file 43 static final String MAIN = ".mainData"; //$NON-NLS-1$ 44 BufferedRandomInputStream mainDataFile = null; 45 DataInputStream mainInput = null; 46 47 //Informations representing the EXTRA file 48 static final String EXTRA = ".extraData"; //$NON-NLS-1$ 49 BufferedRandomInputStream extraDataFile = null; 50 DataInputStream extraInput = null; 51 52 //The table file 53 static final String TABLE = ".table"; //$NON-NLS-1$ 54 File tableFile; 55 56 //The contributions file 57 static final String CONTRIBUTIONS = ".contributions"; //$NON-NLS-1$ 58 File contributionsFile; 59 60 //The contributor file 61 static final String CONTRIBUTORS = ".contributors"; //$NON-NLS-1$ 62 File contributorsFile; 63 64 //The namespace file 65 static final String NAMESPACES = ".namespaces"; //$NON-NLS-1$ 66 File namespacesFile; 67 68 //The orphan file 69 static final String ORPHANS = ".orphans"; //$NON-NLS-1$ 70 File orphansFile; 71 72 //Status code 73 private static final byte fileError = 0; 74 private static final boolean DEBUG = false; //TODO need to change 75 76 private boolean holdObjects = false; 77 78 private final ExtensionRegistry registry; 79 80 private SoftReference<Map<String, String>> stringPool; 81 setMainDataFile(File main)82 void setMainDataFile(File main) throws IOException { 83 mainDataFile = new BufferedRandomInputStream(main); 84 mainInput = new DataInputStream(mainDataFile); 85 } 86 setExtraDataFile(File extra)87 void setExtraDataFile(File extra) throws IOException { 88 extraDataFile = new BufferedRandomInputStream(extra); 89 extraInput = new DataInputStream(extraDataFile); 90 } 91 setTableFile(File table)92 void setTableFile(File table) { 93 tableFile = table; 94 } 95 setContributionsFile(File namespace)96 void setContributionsFile(File namespace) { 97 contributionsFile = namespace; 98 } 99 setContributorsFile(File file)100 void setContributorsFile(File file) { 101 contributorsFile = file; 102 } 103 setNamespacesFile(File file)104 void setNamespacesFile(File file) { 105 namespacesFile = file; 106 } 107 setOrphansFile(File orphan)108 void setOrphansFile(File orphan) { 109 orphansFile = orphan; 110 } 111 TableReader(ExtensionRegistry registry)112 public TableReader(ExtensionRegistry registry) { 113 this.registry = registry; 114 } 115 116 // Don't need to synchronize - called only from a synchronized method loadTables(long expectedTimestamp)117 public Object[] loadTables(long expectedTimestamp) { 118 HashtableOfStringAndInt extensionPoints; 119 120 DataInputStream tableInput = null; 121 try { 122 tableInput = new DataInputStream(new BufferedInputStream(new FileInputStream(tableFile))); 123 if (!checkCacheValidity(tableInput, expectedTimestamp)) 124 return null; 125 126 Integer nextId = Integer.valueOf(tableInput.readInt()); 127 OffsetTable offsets = OffsetTable.load(tableInput); 128 extensionPoints = new HashtableOfStringAndInt(); 129 extensionPoints.load(tableInput); 130 return new Object[] {offsets, extensionPoints, nextId}; 131 } catch (IOException e) { 132 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, RegistryMessages.meta_registryCacheReadProblems, e)); 133 return null; 134 } finally { 135 if (tableInput != null) 136 try { 137 tableInput.close(); 138 } catch (IOException e1) { 139 //Ignore 140 } 141 } 142 143 } 144 145 // Check various aspect of the cache to see if it's valid checkCacheValidity(DataInputStream in, long expectedTimestamp)146 private boolean checkCacheValidity(DataInputStream in, long expectedTimestamp) { 147 int version; 148 try { 149 version = in.readInt(); 150 if (version != CACHE_VERSION) 151 return false; 152 153 long installStamp = in.readLong(); 154 long registryStamp = in.readLong(); 155 long mainDataFileSize = in.readLong(); 156 long extraDataFileSize = in.readLong(); 157 long contributionsFileSize = in.readLong(); 158 long contributorsFileSize = in.readLong(); 159 long namespacesFileSize = in.readLong(); 160 long orphansFileSize = in.readLong(); 161 String osStamp = readUTF(in, OBJECT); 162 String windowsStamp = readUTF(in, OBJECT); 163 String localeStamp = readUTF(in, OBJECT); 164 boolean multiLanguage = in.readBoolean(); 165 166 boolean validTime = (expectedTimestamp == 0 || expectedTimestamp == registryStamp); 167 boolean validInstall = (installStamp == registry.computeState()); 168 boolean validOS = (osStamp.equals(RegistryProperties.getProperty(IRegistryConstants.PROP_OS, RegistryProperties.empty))); 169 boolean validWS = (windowsStamp.equals(RegistryProperties.getProperty(IRegistryConstants.PROP_WS, RegistryProperties.empty))); 170 boolean validNL = (localeStamp.equals(RegistryProperties.getProperty(IRegistryConstants.PROP_NL, RegistryProperties.empty))); 171 boolean validMultiLang = (registry.isMultiLanguage() == multiLanguage); 172 173 if (!validTime || !validInstall || !validOS || !validWS || !validNL || !validMultiLang) 174 return false; 175 176 boolean validMain = (mainDataFileSize == mainDataFile.length()); 177 boolean validExtra = (extraDataFileSize == extraDataFile.length()); 178 boolean validContrib = (contributionsFileSize == contributionsFile.length()); 179 boolean validContributors = (contributorsFileSize == contributorsFile.length()); 180 boolean validNamespace = (namespacesFileSize == namespacesFile.length()); 181 boolean validOrphan = (orphansFileSize == orphansFile.length()); 182 183 return (validMain && validExtra && validContrib && validContributors && validNamespace && validOrphan); 184 } catch (IOException e) { 185 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, RegistryMessages.meta_registryCacheInconsistent, e)); 186 return false; 187 } 188 } 189 loadConfigurationElement(int offset)190 public Object loadConfigurationElement(int offset) { 191 try { 192 synchronized (mainDataFile) { 193 goToInputFile(offset); 194 return basicLoadConfigurationElement(mainInput, null); 195 } 196 } catch (IOException e) { 197 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, mainDataFile); 198 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 199 if (DEBUG) 200 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, "Error reading a configuration element (" + offset + ") from the registry cache", e)); //$NON-NLS-1$//$NON-NLS-2$ 201 return null; 202 } 203 } 204 basicLoadConfigurationElement(DataInputStream is, String actualContributorId)205 private ConfigurationElement basicLoadConfigurationElement(DataInputStream is, String actualContributorId) throws IOException { 206 int self = is.readInt(); 207 String contributorId = readStringOrNull(is); 208 String name = readStringOrNull(is); 209 int parentId = is.readInt(); 210 byte parentType = is.readByte(); 211 int misc = is.readInt();//this is set in second level CEs, to indicate where in the extra data file the children CEs are 212 String[] propertiesAndValue = readPropertiesAndValue(is); 213 int[] children = readArray(is); 214 if (actualContributorId == null) 215 actualContributorId = contributorId; 216 ConfigurationElement result = getObjectFactory().createConfigurationElement(self, actualContributorId, name, propertiesAndValue, children, misc, parentId, parentType, true); 217 if (registry.isMultiLanguage()) { // cache is multi-language too or it would have failed validation 218 int numberOfLocales = is.readInt(); 219 DirectMap translated = null; 220 if (numberOfLocales != 0) { 221 translated = new DirectMap(numberOfLocales, 0.5f); 222 String[] NLs = readStringArray(is); 223 for (int i = 0; i < numberOfLocales; i++) { 224 String[] translatedProperties = readStringArray(is); 225 translated.put(NLs[i], translatedProperties); 226 } 227 } 228 ConfigurationElementMulti multiCE = (ConfigurationElementMulti) result; 229 if (translated != null) 230 multiCE.setTranslatedProperties(translated); 231 } 232 return result; 233 } 234 readStringArray(DataInputStream is)235 private String[] readStringArray(DataInputStream is) throws IOException { 236 int size = is.readInt(); 237 if (size == 0) 238 return null; 239 String[] result = new String[size]; 240 for (int i = 0; i < size; i++) { 241 result[i] = readStringOrNull(is); 242 } 243 return result; 244 } 245 loadThirdLevelConfigurationElements(int offset, RegistryObjectManager objectManager)246 public Object loadThirdLevelConfigurationElements(int offset, RegistryObjectManager objectManager) { 247 try { 248 synchronized (extraDataFile) { 249 goToExtraFile(offset); 250 return loadConfigurationElementAndChildren(null, extraInput, 3, Integer.MAX_VALUE, objectManager, null); 251 } 252 } catch (IOException e) { 253 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, extraDataFile); 254 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 255 if (DEBUG) 256 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, "Error reading a third level configuration element (" + offset + ") from the registry cache", e)); //$NON-NLS-1$//$NON-NLS-2$ 257 return null; 258 } 259 } 260 261 //Read a whole configuration element subtree loadConfigurationElementAndChildren(DataInputStream is, DataInputStream extraIs, int depth, int maxDepth, RegistryObjectManager objectManager, String namespaceOwnerId)262 private ConfigurationElement loadConfigurationElementAndChildren(DataInputStream is, DataInputStream extraIs, int depth, int maxDepth, RegistryObjectManager objectManager, String namespaceOwnerId) throws IOException { 263 DataInputStream currentStream = is; 264 if (depth > 2) 265 currentStream = extraIs; 266 267 ConfigurationElement ce = basicLoadConfigurationElement(currentStream, namespaceOwnerId); 268 if (namespaceOwnerId == null) 269 namespaceOwnerId = ce.getContributorId(); 270 int[] children = ce.getRawChildren(); 271 if (depth + 1 > maxDepth) 272 return ce; 273 274 for (int i = 0; i < children.length; i++) { 275 ConfigurationElement tmp = loadConfigurationElementAndChildren(currentStream, extraIs, depth + 1, maxDepth, objectManager, namespaceOwnerId); 276 objectManager.add(tmp, holdObjects); 277 } 278 return ce; 279 } 280 readPropertiesAndValue(DataInputStream inputStream)281 private String[] readPropertiesAndValue(DataInputStream inputStream) throws IOException { 282 int numberOfProperties = inputStream.readInt(); 283 if (numberOfProperties == 0) 284 return RegistryObjectManager.EMPTY_STRING_ARRAY; 285 String[] properties = new String[numberOfProperties]; 286 for (int i = 0; i < numberOfProperties; i++) { 287 properties[i] = readStringOrNull(inputStream); 288 } 289 return properties; 290 } 291 loadExtension(int offset)292 public Object loadExtension(int offset) { 293 try { 294 synchronized (mainDataFile) { 295 goToInputFile(offset); 296 return basicLoadExtension(mainInput); 297 } 298 } catch (IOException e) { 299 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, mainDataFile); 300 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 301 if (DEBUG) 302 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, "Error reading an extension (" + offset + ") from the registry cache", e)); //$NON-NLS-1$//$NON-NLS-2$ 303 } 304 return null; 305 } 306 basicLoadExtension(DataInputStream inputStream)307 private Extension basicLoadExtension(DataInputStream inputStream) throws IOException { 308 int self = inputStream.readInt(); 309 String simpleId = readStringOrNull(mainInput); 310 String namespace = readStringOrNull(mainInput); 311 int[] children = readArray(mainInput); 312 int extraData = mainInput.readInt(); 313 return getObjectFactory().createExtension(self, simpleId, namespace, children, extraData, true); 314 } 315 loadExtensionPointTree(int offset, RegistryObjectManager objects)316 public ExtensionPoint loadExtensionPointTree(int offset, RegistryObjectManager objects) { 317 try { 318 synchronized (mainDataFile) { 319 ExtensionPoint xpt = (ExtensionPoint) loadExtensionPoint(offset); 320 int[] children = xpt.getRawChildren(); 321 int nbrOfExtension = children.length; 322 for (int i = 0; i < nbrOfExtension; i++) { 323 Extension loaded = basicLoadExtension(mainInput); 324 objects.add(loaded, holdObjects); 325 } 326 327 for (int i = 0; i < nbrOfExtension; i++) { 328 int nbrOfCe = mainInput.readInt(); 329 for (int j = 0; j < nbrOfCe; j++) { 330 // note that max depth is set to 2 and extra input is never going to 331 // be used in this call to the loadConfigurationElementAndChildren(). 332 objects.add(loadConfigurationElementAndChildren(mainInput, null, 1, 2, objects, null), holdObjects); 333 } 334 } 335 return xpt; 336 } 337 } catch (IOException e) { 338 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, mainDataFile); 339 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 340 if (DEBUG) 341 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, "Error reading an extension point tree (" + offset + ") from the registry cache", e)); //$NON-NLS-1$//$NON-NLS-2$ 342 return null; 343 } 344 } 345 loadExtensionPoint(int offset)346 private Object loadExtensionPoint(int offset) { 347 try { 348 goToInputFile(offset); 349 return basicLoadExtensionPoint(); 350 } catch (IOException e) { 351 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, mainDataFile); 352 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 353 if (DEBUG) 354 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, "Error reading an extension point (" + offset + ") from the registry cache", e)); //$NON-NLS-1$ //$NON-NLS-2$ 355 return null; 356 } 357 } 358 basicLoadExtensionPoint()359 private ExtensionPoint basicLoadExtensionPoint() throws IOException { 360 int self = mainInput.readInt(); 361 int[] children = readArray(mainInput); 362 int extraData = mainInput.readInt(); 363 return getObjectFactory().createExtensionPoint(self, children, extraData, true); 364 } 365 readArray(DataInputStream in)366 private int[] readArray(DataInputStream in) throws IOException { 367 int arraySize = in.readInt(); 368 if (arraySize == 0) 369 return RegistryObjectManager.EMPTY_INT_ARRAY; 370 int[] result = new int[arraySize]; 371 for (int i = 0; i < arraySize; i++) { 372 result[i] = in.readInt(); 373 } 374 return result; 375 } 376 goToInputFile(int offset)377 private void goToInputFile(int offset) throws IOException { 378 mainDataFile.seek(offset); 379 } 380 goToExtraFile(int offset)381 private void goToExtraFile(int offset) throws IOException { 382 extraDataFile.seek(offset); 383 } 384 readStringOrNull(DataInputStream in)385 private String readStringOrNull(DataInputStream in) throws IOException { 386 byte type = in.readByte(); 387 if (type == NULL) 388 return null; 389 return readUTF(in, type); 390 } 391 loadExtensionExtraData(int dataPosition)392 public String[] loadExtensionExtraData(int dataPosition) { 393 try { 394 synchronized (extraDataFile) { 395 goToExtraFile(dataPosition); 396 return basicLoadExtensionExtraData(); 397 } 398 } catch (IOException e) { 399 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, extraDataFile); 400 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 401 if (DEBUG) 402 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, "Error reading extension label (" + dataPosition + ") from the registry cache", e)); //$NON-NLS-1$ //$NON-NLS-2$ 403 return null; 404 } 405 } 406 basicLoadExtensionExtraData()407 private String[] basicLoadExtensionExtraData() throws IOException { 408 return new String[] {readStringOrNull(extraInput), readStringOrNull(extraInput), readStringOrNull(extraInput)}; 409 } 410 loadExtensionPointExtraData(int offset)411 public String[] loadExtensionPointExtraData(int offset) { 412 try { 413 synchronized (extraDataFile) { 414 goToExtraFile(offset); 415 return basicLoadExtensionPointExtraData(); 416 } 417 } catch (IOException e) { 418 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, extraDataFile); 419 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 420 if (DEBUG) 421 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, "Error reading extension point data (" + offset + ") from the registry cache", e)); //$NON-NLS-1$ //$NON-NLS-2$ 422 return null; 423 } 424 } 425 basicLoadExtensionPointExtraData()426 private String[] basicLoadExtensionPointExtraData() throws IOException { 427 String[] result = new String[5]; 428 result[0] = readStringOrNull(extraInput); //the label 429 result[1] = readStringOrNull(extraInput); //the schema 430 result[2] = readStringOrNull(extraInput); //the fully qualified name 431 result[3] = readStringOrNull(extraInput); //the namespace 432 result[4] = readStringOrNull(extraInput); //the contributor Id 433 return result; 434 } 435 loadContributions()436 public KeyedHashSet loadContributions() { 437 DataInputStream namespaceInput = null; 438 try { 439 synchronized (contributionsFile) { 440 namespaceInput = new DataInputStream(new BufferedInputStream(new FileInputStream(contributionsFile))); 441 int size = namespaceInput.readInt(); 442 KeyedHashSet result = new KeyedHashSet(size); 443 for (int i = 0; i < size; i++) { 444 String contributorId = readStringOrNull(namespaceInput); 445 Contribution n = getObjectFactory().createContribution(contributorId, true); 446 n.setRawChildren(readArray(namespaceInput)); 447 result.add(n); 448 } 449 return result; 450 } 451 } catch (IOException e) { 452 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, contributionsFile); 453 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 454 return null; 455 } finally { 456 if (namespaceInput != null) 457 try { 458 namespaceInput.close(); 459 } catch (IOException e1) { 460 //Ignore 461 } 462 } 463 } 464 465 final static float contributorsLoadFactor = 1.2f; // allocate more memory to avoid resizing 466 loadContributors()467 public HashMap<String, RegistryContributor> loadContributors() { 468 HashMap<String, RegistryContributor> result = null; 469 DataInputStream contributorsInput = null; 470 try { 471 synchronized (contributorsFile) { 472 contributorsInput = new DataInputStream(new BufferedInputStream(new FileInputStream(contributorsFile))); 473 int size = contributorsInput.readInt(); 474 result = new HashMap<>((int) (size * contributorsLoadFactor)); 475 for (int i = 0; i < size; i++) { 476 String id = readStringOrNull(contributorsInput); 477 String name = readStringOrNull(contributorsInput); 478 String hostId = readStringOrNull(contributorsInput); 479 String hostName = readStringOrNull(contributorsInput); 480 result.put(id, new RegistryContributor(id, name, hostId, hostName)); 481 } 482 } 483 return result; 484 } catch (IOException e) { 485 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, contributorsFile); 486 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 487 return null; 488 } finally { 489 if (contributorsInput != null) 490 try { 491 contributorsInput.close(); 492 } catch (IOException e1) { 493 //Ignore 494 } 495 } 496 } 497 loadNamespaces()498 public KeyedHashSet loadNamespaces() { 499 DataInputStream namespaceInput = null; 500 try { 501 synchronized (namespacesFile) { 502 namespaceInput = new DataInputStream(new BufferedInputStream(new FileInputStream(namespacesFile))); 503 int size = namespaceInput.readInt(); 504 KeyedHashSet result = new KeyedHashSet(size); 505 for (int i = 0; i < size; i++) { 506 String key = readStringOrNull(namespaceInput); 507 RegistryIndexElement indexElement = new RegistryIndexElement(key); 508 indexElement.updateExtensionPoints(readArray(namespaceInput), true); 509 indexElement.updateExtensions(readArray(namespaceInput), true); 510 result.add(indexElement); 511 } 512 return result; 513 } 514 } catch (IOException e) { 515 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, namespacesFile); 516 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 517 return null; 518 } finally { 519 if (namespaceInput != null) 520 try { 521 namespaceInput.close(); 522 } catch (IOException e1) { 523 //Ignore 524 } 525 } 526 } 527 loadAllOrphans(RegistryObjectManager objectManager)528 private void loadAllOrphans(RegistryObjectManager objectManager) throws IOException { 529 //Read the extensions and configuration elements of the orphans 530 int orphans = objectManager.getOrphanExtensions().size(); 531 for (int k = 0; k < orphans; k++) { 532 int numberOfOrphanExtensions = mainInput.readInt(); 533 for (int i = 0; i < numberOfOrphanExtensions; i++) { 534 loadFullExtension(objectManager); 535 } 536 for (int i = 0; i < numberOfOrphanExtensions; i++) { 537 int nbrOfCe = mainInput.readInt(); 538 for (int j = 0; j < nbrOfCe; j++) { 539 objectManager.add(loadConfigurationElementAndChildren(mainInput, extraInput, 1, Integer.MAX_VALUE, objectManager, null), true); 540 } 541 } 542 } 543 } 544 545 // Do not need to synchronize - called only from a synchronized method readAllCache(RegistryObjectManager objectManager)546 public boolean readAllCache(RegistryObjectManager objectManager) { 547 try { 548 int size = objectManager.getExtensionPoints().size(); 549 for (int i = 0; i < size; i++) { 550 objectManager.add(readAllExtensionPointTree(objectManager), holdObjects); 551 } 552 loadAllOrphans(objectManager); 553 } catch (IOException e) { 554 String message = NLS.bind(RegistryMessages.meta_regCacheIOExceptionReading, mainDataFile); 555 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, message, e)); 556 return false; 557 } 558 return true; 559 } 560 readAllExtensionPointTree(RegistryObjectManager objectManager)561 private ExtensionPoint readAllExtensionPointTree(RegistryObjectManager objectManager) throws IOException { 562 ExtensionPoint xpt = loadFullExtensionPoint(); 563 int[] children = xpt.getRawChildren(); 564 int nbrOfExtension = children.length; 565 for (int i = 0; i < nbrOfExtension; i++) { 566 loadFullExtension(objectManager); 567 } 568 569 for (int i = 0; i < nbrOfExtension; i++) { 570 int nbrOfCe = mainInput.readInt(); 571 for (int j = 0; j < nbrOfCe; j++) { 572 objectManager.add(loadConfigurationElementAndChildren(mainInput, extraInput, 1, Integer.MAX_VALUE, objectManager, null), true); 573 } 574 } 575 return xpt; 576 } 577 loadFullExtensionPoint()578 private ExtensionPoint loadFullExtensionPoint() throws IOException { //TODO I don't like this. 579 ExtensionPoint xpt = basicLoadExtensionPoint(); 580 String[] tmp = basicLoadExtensionPointExtraData(); 581 xpt.setLabel(tmp[0]); 582 xpt.setSchema(tmp[1]); 583 xpt.setUniqueIdentifier(tmp[2]); 584 xpt.setNamespace(tmp[3]); 585 xpt.setContributorId(tmp[4]); 586 return xpt; 587 } 588 loadFullExtension(RegistryObjectManager objectManager)589 private Extension loadFullExtension(RegistryObjectManager objectManager) throws IOException { 590 String[] tmp; 591 Extension loaded = basicLoadExtension(mainInput); 592 tmp = basicLoadExtensionExtraData(); 593 loaded.setLabel(tmp[0]); 594 loaded.setExtensionPointIdentifier(tmp[1]); 595 loaded.setContributorId(tmp[2]); 596 objectManager.add(loaded, holdObjects); 597 return loaded; 598 } 599 loadOrphans()600 public HashMap<String, int[]> loadOrphans() { 601 DataInputStream orphanInput = null; 602 try { 603 synchronized (orphansFile) { 604 orphanInput = new DataInputStream(new BufferedInputStream(new FileInputStream(orphansFile))); 605 int size = orphanInput.readInt(); 606 HashMap<String, int[]> result = new HashMap<>(size); 607 for (int i = 0; i < size; i++) { 608 String key = readUTF(orphanInput, OBJECT); 609 int[] value = readArray(orphanInput); 610 result.put(key, value); 611 } 612 return result; 613 } 614 } catch (IOException e) { 615 return null; 616 } finally { 617 if (orphanInput != null) 618 try { 619 orphanInput.close(); 620 } catch (IOException e1) { 621 //ignore 622 } 623 } 624 } 625 626 // Don't need to synchronize - called only from a synchronized method setHoldObjects(boolean holdObjects)627 public void setHoldObjects(boolean holdObjects) { 628 this.holdObjects = holdObjects; 629 } 630 log(Status status)631 private void log(Status status) { 632 registry.log(status); 633 } 634 getObjectFactory()635 private RegistryObjectFactory getObjectFactory() { 636 return registry.getElementFactory(); 637 } 638 639 // Returns a file name used to test if cache is actually present at a given location getTestFileName()640 public static String getTestFileName() { 641 return TABLE; 642 } 643 close()644 public void close() { 645 try { 646 if (mainInput != null) 647 mainInput.close(); 648 if (extraInput != null) 649 extraInput.close(); 650 } catch (IOException e) { 651 log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, RegistryMessages.meta_registryCacheReadProblems, e)); 652 } 653 } 654 readUTF(DataInputStream in, int type)655 private String readUTF(DataInputStream in, int type) throws IOException { 656 String value; 657 if (type == LOBJECT) { 658 int length = in.readInt(); 659 byte[] data = new byte[length]; 660 in.readFully(data); 661 value = new String(data, StandardCharsets.UTF_8); 662 } else { 663 value = in.readUTF(); 664 } 665 666 Map<String, String> map = null; 667 if (stringPool != null) { 668 map = stringPool.get(); 669 } 670 if (map == null) { 671 map = new HashMap<>(); 672 stringPool = new SoftReference<>(map); 673 } 674 675 String pooledString = map.get(value); 676 if (pooledString == null) { 677 map.put(value, value); 678 return value; 679 } 680 681 return pooledString; 682 } 683 } 684