| 1 11 package org.eclipse.pde.internal.core; 12 13 import java.io.*; 14 import java.net.*; 15 import java.util.*; 16 17 import org.eclipse.core.internal.boot.*; 18 import org.eclipse.update.configurator.*; 19 20 public class PlatformConfiguration implements IPlatformConfiguration { 21 22 private static PlatformConfiguration currentPlatformConfiguration = null; 23 24 private URL configLocation; 25 private HashMap sites; 26 private HashMap externalLinkSites; private HashMap cfgdFeatures; 28 private HashMap bootPlugins; 29 private String defaultFeature; 30 private long changeStamp; 31 private boolean changeStampIsValid = false; 32 private long lastFeaturesChangeStamp; 33 private long featuresChangeStamp; 34 private boolean featuresChangeStampIsValid = false; 35 private long pluginsChangeStamp; 36 private boolean pluginsChangeStampIsValid = false; 37 private boolean transientConfig = false; 38 private File cfgLockFile; 39 private RandomAccessFile cfgLockFileRAF; 40 private BootDescriptor runtimeDescriptor; 41 42 private static String cmdFeature = null; 43 private static String cmdApplication = null; 44 private static boolean cmdInitialize = false; 45 private static boolean cmdFirstUse = false; 46 private static boolean cmdUpdate = false; 47 private static boolean cmdNoUpdate = false; 48 49 static boolean DEBUG = false; 50 51 private static final String RUNTIME_PLUGIN_ID = "org.eclipse.core.runtime"; 53 private static final String PLUGINS = "plugins"; private static final String FEATURES = "features"; private static final String CONFIG_FILE_TEMP_SUFFIX = ".tmp"; private static final String CONFIG_FILE_BAK_SUFFIX = ".bak"; private static final String PLUGIN_XML = "plugin.xml"; private static final String FRAGMENT_XML = "fragment.xml"; private static final String FEATURE_XML = "feature.xml"; 61 private static final String [] BOOTSTRAP_PLUGINS = { "org.eclipse.core.boot" }; private static final String CFG_BOOT_PLUGIN = "bootstrap"; private static final String CFG_SITE = "site"; private static final String CFG_URL = "url"; private static final String CFG_POLICY = "policy"; private static final String [] CFG_POLICY_TYPE = { "USER-INCLUDE", "USER-EXCLUDE" }; private static final String CFG_POLICY_TYPE_UNKNOWN = "UNKNOWN"; private static final String CFG_LIST = "list"; private static final String CFG_STAMP = "stamp"; private static final String CFG_FEATURE_STAMP = "stamp.features"; private static final String CFG_PLUGIN_STAMP = "stamp.plugins"; private static final String CFG_UPDATEABLE = "updateable"; private static final String CFG_LINK_FILE = "linkfile"; private static final String CFG_FEATURE_ENTRY = "feature"; private static final String CFG_FEATURE_ENTRY_DEFAULT = "feature.default.id"; private static final String CFG_FEATURE_ENTRY_ID = "id"; private static final String CFG_FEATURE_ENTRY_PRIMARY = "primary"; private static final String CFG_FEATURE_ENTRY_VERSION = "version"; private static final String CFG_FEATURE_ENTRY_PLUGIN_VERSION = "plugin-version"; private static final String CFG_FEATURE_ENTRY_PLUGIN_IDENTIFIER = "plugin-identifier"; private static final String CFG_FEATURE_ENTRY_APPLICATION = "application"; private static final String CFG_FEATURE_ENTRY_ROOT = "root"; 84 private static final String DEFAULT_FEATURE_ID = "org.eclipse.platform"; private static final String DEFAULT_FEATURE_APPLICATION = "org.eclipse.ui.workbench"; 87 private static final String CFG_VERSION = "version"; private static final String CFG_TRANSIENT = "transient"; private static final String VERSION = "2.1"; private static final String EOF = "eof"; private static final int CFG_LIST_LENGTH = 10; 92 93 private static final int DEFAULT_POLICY_TYPE = ISitePolicy.USER_EXCLUDE; 94 private static final String [] DEFAULT_POLICY_LIST = new String [0]; 95 96 97 protected static final String RECONCILER_APP = "org.eclipse.update.core.reconciler"; 99 private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 100 101 private static URL installURL; 102 103 public class SiteEntry implements IPlatformConfiguration.ISiteEntry { 104 105 private URL url; private URL resolvedURL; private ISitePolicy policy; 108 private boolean updateable = true; 109 private ArrayList features; 110 private ArrayList plugins; 111 private PlatformConfiguration parent; 112 private long changeStamp; 113 private boolean changeStampIsValid = false; 114 private long lastFeaturesChangeStamp; 115 private long featuresChangeStamp; 116 private boolean featuresChangeStampIsValid = false; 117 private long lastPluginsChangeStamp; 118 private long pluginsChangeStamp; 119 private boolean pluginsChangeStampIsValid = false; 120 private String linkFileName = null; 121 122 private SiteEntry() { 123 } 124 private SiteEntry(URL url, ISitePolicy policy, PlatformConfiguration parent) { 125 if (url == null) 126 throw new IllegalArgumentException (); 127 128 if (policy == null) 129 throw new IllegalArgumentException (); 130 131 if (parent == null) 132 throw new IllegalArgumentException (); 133 134 this.url = url; 135 this.policy = policy; 136 this.parent = parent; 137 this.features = null; 138 this.plugins = null; 139 this.resolvedURL = this.url; 140 if (url.getProtocol().equals(PlatformURLHandler.PROTOCOL)) { 141 try { 142 resolvedURL = resolvePlatformURL(url); } catch (IOException e) { 144 } 146 } 147 } 148 149 152 public URL getURL() { 153 return url; 154 } 155 156 159 public ISitePolicy getSitePolicy() { 160 return policy; 161 } 162 163 166 public synchronized void setSitePolicy(ISitePolicy policy) { 167 if (policy == null) 168 throw new IllegalArgumentException (); 169 this.policy = policy; 170 } 171 172 175 public String [] getFeatures() { 176 return getDetectedFeatures(); 177 } 178 179 182 public String [] getPlugins() { 183 184 ISitePolicy policy = getSitePolicy(); 185 186 if (policy.getType() == ISitePolicy.USER_INCLUDE) 187 return policy.getList(); 188 189 if (policy.getType() == ISitePolicy.USER_EXCLUDE) { 190 ArrayList detectedPlugins = new ArrayList(Arrays.asList(getDetectedPlugins())); 191 String [] excludedPlugins = policy.getList(); 192 for (int i = 0; i < excludedPlugins.length; i++) { 193 if (detectedPlugins.contains(excludedPlugins[i])) 194 detectedPlugins.remove(excludedPlugins[i]); 195 } 196 return (String []) detectedPlugins.toArray(new String [0]); 197 } 198 199 return new String [0]; 201 } 202 203 206 public long getChangeStamp() { 207 if (!changeStampIsValid) 208 computeChangeStamp(); 209 return changeStamp; 210 } 211 212 215 public long getFeaturesChangeStamp() { 216 if (!featuresChangeStampIsValid) 217 computeFeaturesChangeStamp(); 218 return featuresChangeStamp; 219 } 220 221 224 public long getPluginsChangeStamp() { 225 if (!pluginsChangeStampIsValid) 226 computePluginsChangeStamp(); 227 return pluginsChangeStamp; 228 } 229 230 233 public boolean isUpdateable() { 234 return updateable; 235 } 236 237 240 public boolean isNativelyLinked() { 241 return isExternallyLinkedSite(); 242 } 243 244 private String [] detectFeatures() { 245 246 changeStampIsValid = false; 248 featuresChangeStampIsValid = false; 249 parent.changeStampIsValid = false; 250 parent.featuresChangeStampIsValid = false; 251 252 features = new ArrayList(); 253 254 if (!supportsDetection(resolvedURL)) 255 return new String [0]; 256 257 File siteRoot = new File(resolvedURL.getFile().replace('/', File.separatorChar)); 259 File root = new File(siteRoot, FEATURES); 260 261 String [] list = root.list(); 262 String path; 263 File plugin; 264 for (int i = 0; list != null && i < list.length; i++) { 265 path = list[i] + File.separator + FEATURE_XML; 266 plugin = new File(root, path); 267 if (!plugin.exists()) { 268 continue; 269 } 270 features.add(FEATURES + "/" + path.replace(File.separatorChar, '/')); } 272 if (DEBUG) { 273 debug(resolvedURL.toString() + " located " + features.size() + " feature(s)"); } 275 276 return (String []) features.toArray(new String [0]); 277 } 278 279 private String [] detectPlugins() { 280 281 changeStampIsValid = false; 283 pluginsChangeStampIsValid = false; 284 parent.changeStampIsValid = false; 285 parent.pluginsChangeStampIsValid = false; 286 287 plugins = new ArrayList(); 288 289 if (!supportsDetection(resolvedURL)) 290 return new String [0]; 291 292 File root = new File(resolvedURL.getFile().replace('/', File.separatorChar) + PLUGINS); 294 String [] list = root.list(); 295 String path; 296 File plugin; 297 for (int i = 0; list != null && i < list.length; i++) { 298 path = list[i] + File.separator + PLUGIN_XML; 299 plugin = new File(root, path); 300 if (!plugin.exists()) { 301 path = list[i] + File.separator + FRAGMENT_XML; 302 plugin = new File(root, path); 303 if (!plugin.exists()) 304 continue; 305 } 306 plugins.add(PLUGINS + "/" + path.replace(File.separatorChar, '/')); } 308 if (DEBUG) { 309 debug(resolvedURL.toString() + " located " + plugins.size() + " plugin(s)"); } 311 312 return (String []) plugins.toArray(new String [0]); 313 } 314 315 private synchronized String [] getDetectedFeatures() { 316 if (features == null) 317 return detectFeatures(); 318 return (String []) features.toArray(new String [0]); 319 } 320 321 private synchronized String [] getDetectedPlugins() { 322 if (plugins == null) 323 return detectPlugins(); 324 return (String []) plugins.toArray(new String [0]); 325 } 326 327 private URL getResolvedURL() { 328 return resolvedURL; 329 } 330 331 private void computeChangeStamp() { 332 computeFeaturesChangeStamp(); 333 computePluginsChangeStamp(); 334 changeStamp = resolvedURL.hashCode() ^ featuresChangeStamp ^ pluginsChangeStamp; 335 changeStampIsValid = true; 336 } 337 338 private synchronized void computeFeaturesChangeStamp() { 339 if (featuresChangeStampIsValid) 340 return; 341 342 long start = 0; 343 if (DEBUG) 344 start = (new Date()).getTime(); 345 String [] features = getFeatures(); 346 featuresChangeStamp = computeStamp(features); 347 featuresChangeStampIsValid = true; 348 if (DEBUG) { 349 long end = (new Date()).getTime(); 350 debug(resolvedURL.toString() + " feature stamp: " + featuresChangeStamp + ((featuresChangeStamp == lastFeaturesChangeStamp) ? " [no changes]" : " [was " + lastFeaturesChangeStamp + "]") + " in " + (end - start) + "ms"); } 352 } 353 354 private synchronized void computePluginsChangeStamp() { 355 if (pluginsChangeStampIsValid) 356 return; 357 358 long start = 0; 359 if (DEBUG) 360 start = (new Date()).getTime(); 361 String [] plugins = getPlugins(); 362 pluginsChangeStamp = computeStamp(plugins); 363 pluginsChangeStampIsValid = true; 364 if (DEBUG) { 365 long end = (new Date()).getTime(); 366 debug(resolvedURL.toString() + " plugin stamp: " + pluginsChangeStamp + ((pluginsChangeStamp == lastPluginsChangeStamp) ? " [no changes]" : " [was " + lastPluginsChangeStamp + "]") + " in " + (end - start) + "ms"); } 368 } 369 370 private long computeStamp(String [] targets) { 371 372 long result = 0; 373 if (!supportsDetection(resolvedURL)) { 374 for (int i = 0; i < targets.length; i++) 382 result ^= targets[i].hashCode(); 383 if (DEBUG) 384 debug("*WARNING* computing stamp using URL hashcodes only"); } else { 386 String rootPath = resolvedURL.getFile().replace('/', File.separatorChar); 388 if (!rootPath.endsWith(File.separator)) 389 rootPath += File.separator; 390 File rootFile = new File(rootPath); 391 if (rootFile.exists()) { 392 File f = null; 393 for (int i = 0; i < targets.length; i++) { 394 f = new File(rootFile, targets[i]); 395 if (f.exists()) 396 result ^= f.getAbsolutePath().hashCode() ^ f.lastModified() ^ f.length(); 397 } 398 } 399 } 400 401 return result; 402 } 403 404 private boolean isExternallyLinkedSite() { 405 return (linkFileName != null && !linkFileName.trim().equals("")); } 407 408 private synchronized void refresh() { 409 lastFeaturesChangeStamp = featuresChangeStamp; 411 lastPluginsChangeStamp = pluginsChangeStamp; 412 changeStampIsValid = false; 413 featuresChangeStampIsValid = false; 414 pluginsChangeStampIsValid = false; 415 features = null; 416 plugins = null; 417 } 418 419 } 420 421 public class SitePolicy implements IPlatformConfiguration.ISitePolicy { 422 423 private int type; 424 private String [] list; 425 426 private SitePolicy() { 427 } 428 private SitePolicy(int type, String [] list) { 429 if (type != ISitePolicy.USER_INCLUDE && type != ISitePolicy.USER_EXCLUDE) 430 throw new IllegalArgumentException (); 431 this.type = type; 432 433 if (list == null) 434 this.list = new String [0]; 435 else 436 this.list = list; 437 } 438 439 442 public int getType() { 443 return type; 444 } 445 446 449 public String [] getList() { 450 return list; 451 } 452 453 456 public synchronized void setList(String [] list) { 457 if (list == null) 458 this.list = new String [0]; 459 else 460 this.list = list; 461 } 462 463 } 464 465 public class FeatureEntry implements IPlatformConfiguration.IFeatureEntry { 466 private String id; 467 private String version; 468 private String pluginVersion; 469 private String application; 470 private URL[] root; 471 private boolean primary; 472 private String pluginIdentifier; 473 474 private FeatureEntry(String id, String version, String pluginIdentifier, String pluginVersion, boolean primary, String application, URL[] root) { 475 if (id == null) 476 throw new IllegalArgumentException (); 477 this.id = id; 478 this.version = version; 479 this.pluginVersion = pluginVersion; 480 this.pluginIdentifier = pluginIdentifier; 481 this.primary = primary; 482 this.application = application; 483 this.root = (root == null ? new URL[0] : root); 484 } 485 486 private FeatureEntry(String id, String version, String pluginVersion, boolean primary, String application, URL[] root) { 487 this(id, version, id, pluginVersion, primary, application, root); 488 } 489 490 493 public String getFeatureIdentifier() { 494 return id; 495 } 496 497 500 public String getFeatureVersion() { 501 return version; 502 } 503 504 507 public String getFeaturePluginVersion() { 508 return pluginVersion; 509 } 510 511 514 public String getFeatureApplication() { 515 return application; 516 } 517 518 521 public URL[] getFeatureRootURLs() { 522 return root; 523 } 524 525 528 public boolean canBePrimary() { 529 return primary; 530 } 531 534 public String getFeaturePluginIdentifier() { 535 return pluginIdentifier; 536 } 537 538 } 539 540 541 545 public interface Selector { 546 547 554 public boolean select(String entry); 555 556 561 public boolean select(String element, HashMap attributes); 562 } 563 564 569 public static class Parser { 570 571 private ArrayList elements = new ArrayList(); 572 573 576 public Parser(File file) { 577 try { 578 load(new FileInputStream(file)); 579 } catch (Exception e) { 580 } 582 } 583 584 587 public Parser(URL url) { 588 try { 589 load(url.openStream()); 590 } catch (Exception e) { 591 } 593 } 594 595 601 public HashMap getElement(Selector selector) { 602 if (selector == null) 603 return null; 604 605 String element; 606 for (int i = 0; i < elements.size(); i++) { 607 element = (String ) elements.get(i); 609 if (selector.select(element)) { 610 HashMap attributes = new HashMap(); 612 String elementName; 613 int j; 614 for (j = 0; j < element.length(); j++) { 616 if (Character.isWhitespace(element.charAt(j))) 617 break; 618 } 619 if (j >= element.length()) { 620 elementName = element; 621 } else { 622 elementName = element.substring(0, j); 623 element = element.substring(j); 624 StringTokenizer t = new StringTokenizer(element, "=\""); boolean isKey = true; 627 String key = ""; while (t.hasMoreTokens()) { 629 String token = t.nextToken().trim(); 630 if (!token.equals("")) { if (isKey) { 633 key = token; 634 isKey = false; 635 } else { 636 attributes.put(key, token); 637 isKey = true; 638 } 639 } 640 } 641 } 642 if (selector.select(elementName, attributes)) { 644 attributes.put("<element>", elementName); return attributes; 646 } 647 } 648 } 649 return null; 650 } 651 652 private void load(InputStream is) { 653 if (is == null) 654 return; 655 656 StringBuffer xml = new StringBuffer (4096); 658 char[] iobuf = new char[4096]; 659 InputStreamReader r = null; 660 try { 661 r = new InputStreamReader(is); 662 int len = r.read(iobuf, 0, iobuf.length); 663 while (len != -1) { 664 xml.append(iobuf, 0, len); 665 len = r.read(iobuf, 0, iobuf.length); 666 } 667 } catch (Exception e) { 668 return; 669 } finally { 670 if (r != null) 671 try { 672 r.close(); 673 } catch (IOException e) { 674 } 676 } 677 678 String xmlString = xml.toString(); 680 StringTokenizer t = new StringTokenizer(xmlString, "<>"); while (t.hasMoreTokens()) { 682 String token = t.nextToken().trim(); 683 if (!token.equals("")) elements.add(token); 685 } 686 } 687 } 688 689 public static class BootDescriptor { 690 private String id; 691 private String version; 692 private |