• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright (c) 2000, 2009 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.test.internal.performance.results.db;
12 
13 import java.io.File;
14 import java.io.PrintWriter;
15 import java.io.StringWriter;
16 import java.math.BigDecimal;
17 import java.sql.Connection;
18 import java.sql.DriverManager;
19 import java.sql.ResultSet;
20 import java.sql.SQLException;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.StringTokenizer;
27 
28 import org.eclipse.core.runtime.Assert;
29 import org.eclipse.test.internal.performance.PerformanceTestPlugin;
30 import org.eclipse.test.internal.performance.data.Dim;
31 import org.eclipse.test.internal.performance.db.DB;
32 import org.eclipse.test.internal.performance.results.utils.IPerformancesConstants;
33 import org.eclipse.test.internal.performance.results.utils.Util;
34 import org.eclipse.test.performance.Dimension;
35 
36 /**
37  * Specific and private implementation of {@link org.eclipse.test.internal.performance.db.DB} class
38  * to get massive results from performance results database.
39  * TODO (frederic) Should be at least a subclass of {@link DB}...
40  */
41 public class DB_Results {
42 
43 
44 	private static final String DEFAULT_DB_BASELINE_PREFIX = "R-";
45 	private static final Dim[] NO_DIMENSION = new Dim[0];
46 	private static final String[] EMPTY_LIST = new String[0];
47 	static final boolean DEBUG = false;
48     static final boolean LOG = false;
49 
50     // the two supported DB types
51     private static final String DERBY= "derby"; //$NON-NLS-1$
52     private static final String CLOUDSCAPE= "cloudscape"; //$NON-NLS-1$
53 
54     private static DB_Results fgDefault;
55 
56     private Connection fConnection;
57     private SQL_Results fSQL;
58 //    private boolean fIsEmbedded;
59     private String fDBType;	// either "derby" or "cloudscape"
60 
61 	    // Preferences info
62     public static boolean DB_CONNECTION = false;
63     private static String DB_NAME;
64     private static String DB_LOCATION;
65 	private static String DB_BASELINE_PREFIX = DEFAULT_DB_BASELINE_PREFIX;
66 	private static String DB_VERSION;
67 	private static String DB_VERSION_REF;
68 
69 	/**
70 	 * Get the name of the database.
71 	 *
72 	 * @return The name as a string.
73 	 */
getDbName()74     public static String getDbName() {
75     	if (DB_NAME == null) initDbContants();
76     	return DB_NAME;
77     }
78 
79 	/**
80 	 * Set the name of the database.
81 	 *
82 	 * @param dbName The name as a string.
83 	 */
setDbName(String dbName)84     public static void setDbName(String dbName) {
85     	Assert.isNotNull(dbName);
86     	DB_NAME = dbName;
87     }
88 
89 	/**
90 	 * Get the location of the database.
91 	 *
92 	 * @return The location as a string.
93 	 */
getDbLocation()94     public static String getDbLocation() {
95     	if (!DB_CONNECTION) return null;
96     	if (DB_LOCATION == null) initDbContants();
97     	return DB_LOCATION;
98     }
99 
100 	/**
101 	 * Set the location of the database.
102 	 *
103 	 * @param dbLocation The location as a string.
104 	 */
setDbLocation(String dbLocation)105     public static void setDbLocation(String dbLocation) {
106     	Assert.isNotNull(dbLocation);
107     	DB_LOCATION = dbLocation;
108     }
109 
110 	/**
111 	 * Get the default baseline prefix.
112 	 *
113 	 * @return The prefix as a string.
114 	 */
getDbBaselinePrefix()115     public static String getDbBaselinePrefix() {
116     	return DB_BASELINE_PREFIX;
117     }
118 
119 	/**
120 	 * Set the baseline prefix of the database.
121 	 *
122 	 * @param baselinePrefix The prefix as a string.
123 	 */
setDbDefaultBaselinePrefix(String baselinePrefix)124     public static void setDbDefaultBaselinePrefix(String baselinePrefix) {
125     	Assert.isNotNull(baselinePrefix);
126     	Assert.isTrue(baselinePrefix.startsWith(DEFAULT_DB_BASELINE_PREFIX));
127     	DB_BASELINE_PREFIX = baselinePrefix;
128     }
129 
130 	/**
131 	 * Get the baseline reference version of the database.
132 	 *
133 	 * @return The version as a string.
134 	 */
getDbBaselineRefVersion()135     public static String getDbBaselineRefVersion() {
136     	if (DB_VERSION_REF == null) initDbContants();
137     	return DB_VERSION_REF;
138     }
139 
140 	/**
141 	 * Get the version of the database.
142 	 *
143 	 * @return The version as a string.
144 	 */
getDbVersion()145     public static String getDbVersion() {
146     	if (DB_VERSION == null) initDbContants();
147     	return DB_VERSION;
148     }
149 
150 	/**
151 	 * Set the version of the database.
152 	 *
153 	 * @param version The version as a string.
154 	 */
setDbVersion(String version)155     public static void setDbVersion(String version) {
156     	Assert.isNotNull(version);
157     	Assert.isTrue(version.startsWith("v3"));
158     	DB_VERSION = version;
159     }
160 
161 	/**
162 	 * Update the database constants from a new database location.
163 	 * @param connected Tells whether the database should be connected or not.
164 	 * @param databaseLocation The database location.
165 	 * 	May be a path to a local folder or a net address
166 	 * 	(see {@link IPerformancesConstants#NETWORK_DATABASE_LOCATION}).
167 	 */
updateDbConstants(boolean connected, int eclipseVersion, String databaseLocation)168 	public static boolean updateDbConstants(boolean connected, int eclipseVersion, String databaseLocation) {
169 		if (DB_CONNECTION != connected || DB_LOCATION == null || DB_NAME == null ||
170 			((databaseLocation == null && !DB_LOCATION.equals(IPerformancesConstants.NETWORK_DATABASE_LOCATION)) ||
171 					!DB_LOCATION.equals(databaseLocation)) ||
172 			!DB_NAME.equals(IPerformancesConstants.DATABASE_NAME_PREFIX + eclipseVersion)) {
173 			shutdown();
174 			DB_CONNECTION = connected;
175 			DB_LOCATION = databaseLocation == null ? IPerformancesConstants.NETWORK_DATABASE_LOCATION : databaseLocation;
176 			DB_NAME = IPerformancesConstants.DATABASE_NAME_PREFIX + eclipseVersion;
177 			DB_VERSION = "v" + eclipseVersion;
178 			DB_VERSION_REF = "R-3." + (eclipseVersion % 10 - 1);
179 			if (connected) {
180 				return getDefault().fSQL != null;
181 			}
182 		}
183 		return true;
184 	}
185 
186 	/**
187 	 * Returns a title including DB version and name.
188 	 *
189 	 * @return A title as a string.
190 	 */
getDbTitle()191 	public static String getDbTitle() {
192     	if (!DB_CONNECTION) return null;
193 		String title = "Eclipse " + DB_VERSION + " - ";
194 		if (DB_LOCATION.startsWith("net:")) {
195 			title += " Network DB";
196 		} else {
197 			title += " Local DB";
198 		}
199 		return title;
200 	}
201 
202 	/**
203 	 * The list of all the configurations (i.e. machine) stored in the database.
204 	 */
205 	private static String[] CONFIGS;
206 
207 	/**
208 	 * The list of all the components stored in the database.
209 	 */
210 	private static String[] COMPONENTS;
211 
212 	/**
213 	 * The list of all the builds stored in the database.
214 	 */
215 	private static String[] BUILDS;
216 
217 	/**
218 	 * The list of all the dimensions stored in the database.
219 	 */
220 	private static int[] DIMENSIONS;
221 
222 	/**
223 	 * The default dimension used to display results (typically in fingerprints).
224 	 */
225 	private static Dim DEFAULT_DIM;
226 	private static int DEFAULT_DIM_INDEX;
227 
228 	/**
229 	 * The list of all the dimensions displayed while generating results.
230 	 */
231 	private static Dim[] RESULTS_DIMENSIONS;
232 
233 	/**
234 	 * The list of all the VMs stored in the database.
235 	 */
236 	private static String[] VMS;
237 
238 	/**
239 	 * The list of possible test boxes.
240 	 * <p>
241 	 * Only used if no specific configurations are specified
242 	 * (see {@link PerformanceResults#readAll(String, String[][], String, File, int, org.eclipse.core.runtime.IProgressMonitor)}.
243 	 * </p>
244 	 * Note that this is a copy of the the property "eclipse.perf.config.descriptors"
245 	 * defined in org.eclipse.releng.eclipsebuilder/eclipse/helper.xml file
246 	 */
247 	private static String[] CONFIG_DESCRIPTIONS;
248 
249 	/**
250 	 * The list of known Eclipse components.
251 	 */
252 	private final static String[] ECLIPSE_COMPONENTS = {
253 		"org.eclipse.ant", //$NON-NLS-1$
254 		"org.eclipse.compare", //$NON-NLS-1$
255 		"org.eclipse.core", //$NON-NLS-1$
256 		"org.eclipse.help", //$NON-NLS-1$
257 		"org.eclipse.jdt.core", //$NON-NLS-1$
258 		"org.eclipse.jdt.debug", //$NON-NLS-1$
259 		"org.eclipse.jdt.text", //$NON-NLS-1$
260 		"org.eclipse.jdt.ui", //$NON-NLS-1$
261 		"org.eclipse.jface", //$NON-NLS-1$
262 		"org.eclipse.osgi", //$NON-NLS-1$
263 		"org.eclipse.pde.api.tools", //$NON-NLS-1$
264 		"org.eclipse.pde.ui", //$NON-NLS-1$
265 		"org.eclipse.swt", //$NON-NLS-1$
266 		"org.eclipse.team", //$NON-NLS-1$
267 		"org.eclipse.ua", //$NON-NLS-1$
268 		"org.eclipse.ui" //$NON-NLS-1$
269 	};
270 	private static String[] KNOWN_COMPONENTS = ECLIPSE_COMPONENTS;
271 
272 
273 	    // Store debug info
274 	final static StringWriter DEBUG_STR_WRITER;
275 	final static PrintWriter DEBUG_WRITER;
276 	static {
277 		if (DEBUG) {
278 			DEBUG_STR_WRITER= new StringWriter();
279 			DEBUG_WRITER= new PrintWriter(DEBUG_STR_WRITER);
280 		} else {
281 			DEBUG_STR_WRITER= null;
282 			DEBUG_WRITER= null;
283 		}
284 	}
285 
286     // Store log info
287     final static StringWriter LOG_STR_WRITER = new StringWriter();
288     final static LogWriter LOG_WRITER = new LogWriter();
289     static class LogWriter extends PrintWriter {
290 		long[] starts = new long[10];
291 		long[] times = new long[10];
292     	StringBuffer[] buffers = new StringBuffer[10];
293     	int depth = -1, max = -1;
LogWriter()294     	public LogWriter() {
295 	        super(LOG_STR_WRITER);
296         }
starts(String log)297 		void starts(String log) {
298     		if (++this.depth >= this.buffers.length) {
299     			System.arraycopy(this.times, 0, this.times = new long[this.depth+10], 0, this.depth);
300     			System.arraycopy(this.buffers, 0, this.buffers= new StringBuffer[this.depth+10], 0, this.depth);
301     		}
302     		StringBuffer buffer = this.buffers[this.depth];
303     		if (this.buffers[this.depth] == null) buffer = this.buffers[this.depth] = new StringBuffer();
304     		buffer.append(log);
305     		this.starts[this.depth] = System.currentTimeMillis();
306     		if (this.depth > this.max) this.max = this.depth;
307     	}
ends(String log)308 		void ends(String log) {
309 			if (this.depth < 0)
310 				throw new RuntimeException("Invalid call to ends (missing corresponding starts call)!"); //$NON-NLS-1$
311     		this.buffers[this.depth].append(log);
312     		if (this.depth > 0) {
313     			this.times[this.depth] += System.currentTimeMillis() - this.starts[this.depth];
314     			this.depth--;
315     			return;
316     		}
317     		for (int i=0; i<this.max; i++) {
318 	    		print(this.buffers[i].toString());
319 	    		print(" ( in "); //$NON-NLS-1$
320 	    		print(this.times[this.depth]);
321     			println("ms)"); //$NON-NLS-1$
322     		}
323     		this.depth = this.max = -1;
324 			this.starts = new long[10];
325 			this.times = new long[10];
326     		this.buffers = new StringBuffer[10];
327     	}
toString()328 		public String toString() {
329 	        return LOG_STR_WRITER.toString();
330         }
331     }
332 
333 	// Data storage from queries
334 	static String LAST_CURRENT_BUILD, LAST_BASELINE_BUILD;
335 	private static int BUILDS_LENGTH;
336 	private static String[] SCENARII;
337 	private static String[] COMMENTS;
338 
339     //---- private implementation
340 
341 	/**
342      * Private constructor to block instance creation.
343      */
DB_Results()344     private DB_Results() {
345     	// empty implementation
346     }
347 
getDefault()348     synchronized static DB_Results getDefault() {
349         if (fgDefault == null) {
350             fgDefault= new DB_Results();
351             fgDefault.connect();
352             if (PerformanceTestPlugin.getDefault() == null) {
353             	// not started as plugin
354 	            Runtime.getRuntime().addShutdownHook(
355 	                new Thread() {
356 	                    public void run() {
357 	                    	shutdown();
358 	                    }
359 	                }
360 	            );
361             }
362         } else if (fgDefault.fSQL == null) {
363         	fgDefault.connect();
364         }
365         return fgDefault;
366     }
367 
shutdown()368     public static void shutdown() {
369         if (fgDefault != null) {
370             fgDefault.disconnect();
371             fgDefault= null;
372             BUILDS = null;
373             LAST_BASELINE_BUILD = null;
374             LAST_CURRENT_BUILD = null;
375             DIMENSIONS = null;
376             CONFIGS = null;
377             COMPONENTS = null;
378             SCENARII = null;
379             COMMENTS = null;
380             DB_VERSION = null;
381             DB_VERSION_REF = null;
382             DEFAULT_DIM =null;
383             DEFAULT_DIM_INDEX = -1;
384             RESULTS_DIMENSIONS = null;
385             VMS = null;
386             CONFIG_DESCRIPTIONS = null;
387             KNOWN_COMPONENTS = ECLIPSE_COMPONENTS;
388         }
389         if (DEBUG) {
390         	DEBUG_WRITER.println("DB.shutdown"); //$NON-NLS-1$
391         	System.out.println(DEBUG_STR_WRITER.toString());
392         }
393         if (LOG) {
394         	System.out.println(LOG_STR_WRITER.toString());
395         }
396     }
397 
398 /**
399  * Return the build id from a given name.
400  *
401  * @param name The build name (eg. I20070615-1200)
402  * @return The id of the build (ie. the index in the {@link #BUILDS} list)
403  */
getBuildId(String name)404 static int getBuildId(String name) {
405 	if (BUILDS == null) return -1;
406 	return Arrays.binarySearch(BUILDS, name, Util.BUILD_DATE_COMPARATOR);
407 }
408 
409 /**
410  * Return the build name from a given id.
411  *
412  * @param id The build id
413  * @return The name of the build (eg. I20070615-1200)
414  */
getBuildName(int id)415 static String getBuildName(int id) {
416 	if (BUILDS == null) return null;
417 	return BUILDS[id];
418 }
419 
420 /**
421  * Returns all the builds names read from the database.
422  *
423  * @return The list of all builds names matching the scenario pattern used while reading data
424  */
getBuilds()425 public static String[] getBuilds() {
426 	if (BUILDS == null) {
427 		queryAllVariations("%"); //$NON-NLS-1$
428 	}
429 	if (BUILDS_LENGTH == 0) return EMPTY_LIST;
430 	String[] builds = new String[BUILDS_LENGTH];
431 	System.arraycopy(BUILDS, 0, builds, 0, BUILDS_LENGTH);
432 	return builds;
433 }
434 
435 /**
436  * Returns the number of builds stored int the database.
437  *
438  * @return The number of builds stored in the database.
439  */
getBuildsNumber()440 public static int getBuildsNumber() {
441 	if (BUILDS == null) {
442 		queryAllVariations("%"); //$NON-NLS-1$
443 	}
444 	return BUILDS_LENGTH;
445 }
446 
447 /**
448  * Get component name from a scenario.
449  *
450  * @param scenarioName The name of the scenario
451  * @return The component name
452  */
getComponentNameFromScenario(String scenarioName)453 static String getComponentNameFromScenario(String scenarioName) {
454 	int length = KNOWN_COMPONENTS.length;
455 	for (int i=0; i<length; i++) {
456 		if (scenarioName.startsWith(KNOWN_COMPONENTS[i])) {
457 			return KNOWN_COMPONENTS[i];
458 		}
459 	}
460 	StringTokenizer tokenizer = new StringTokenizer(scenarioName, ".");
461 	StringBuffer buffer = new StringBuffer(tokenizer.nextToken());
462 	if (tokenizer.hasMoreTokens()) {
463 		buffer.append('.');
464 		buffer.append(tokenizer.nextToken());
465 		if (tokenizer.hasMoreTokens()) {
466 			buffer.append('.');
467 			buffer.append(tokenizer.nextToken());
468 		}
469 	}
470 	String componentName = buffer.toString();
471 	System.err.println(scenarioName+" does not belongs to a known Eclipse component. So use scenario prefix "+componentName+" as component name by default and add it to the know components"); //$NON-NLS-1$
472 	System.arraycopy(KNOWN_COMPONENTS, 0, KNOWN_COMPONENTS = new String[length+1], 0, length);
473 	KNOWN_COMPONENTS[length] = componentName;
474 	return componentName;
475 }
476 
477 /**
478  * Get all components read from database.
479  *
480  * @return A list of component names matching the given pattern
481  */
getComponents()482 public static String[] getComponents() {
483 	if (COMPONENTS == null) return EMPTY_LIST;
484 	int length = COMPONENTS.length;
485 	String[] components = new String[length];
486 	System.arraycopy(COMPONENTS, 0, components, 0, length);
487 	return components;
488 }
489 
490 /**
491  * Return the name of the configuration from the given id.
492  *
493  * @param id The index of the configuration in the stored list.
494  * @return The name of the configuration (eg. eclipseperflnx1_R3.3)
495  */
getConfig(int id)496 static String getConfig(int id) {
497 	return CONFIGS[id];
498 }
499 
500 /**
501  * Get all configurations read from the database.
502  *
503  * @return A list of configuration names
504  */
getConfigs()505 public static String[] getConfigs() {
506 	if (CONFIGS == null) return EMPTY_LIST;
507 	int length = CONFIGS.length;
508 	String[] configs = new String[length];
509 	System.arraycopy(CONFIGS, 0, configs, 0, length);
510 	return configs;
511 }
512 
513 /**
514  * Set the default dimension used for performance results.
515  */
setConfigs(String[] configs)516 public static void setConfigs(String[] configs) {
517 	CONFIGS = configs;
518 }
519 
520 /**
521  * Get all configurations read from the database.
522  *
523  * @return A list of configuration names
524  */
getConfigDescriptions()525 public static String[] getConfigDescriptions() {
526 	if (CONFIG_DESCRIPTIONS == null) {
527 		if (CONFIGS == null) return null;
528 		int length = CONFIGS.length;
529 		CONFIG_DESCRIPTIONS = new String[length];
530 		String[][] configDescriptors = PerformanceTestPlugin.getConfigDescriptors();
531 		int cdLength = configDescriptors.length;
532 		for (int i = 0; i < length; i++) {
533 			boolean found = false;
534 			for (int j = 0; j < cdLength; j++) {
535 				if (configDescriptors[j][0].equals(CONFIGS[i])) {
536 			        CONFIG_DESCRIPTIONS[i] = configDescriptors[j][1];
537 			        found = true;
538 			        break;
539 				}
540 			}
541 			if (!found) {
542 				String kind = CONFIGS[i].indexOf("epwin") < 0 ? "Linux" : "Win XP";
543 				CONFIG_DESCRIPTIONS[i] = kind+" perf test box "+CONFIGS[i].substring(5);
544 			}
545         }
546 	}
547 	int length = CONFIG_DESCRIPTIONS.length;
548 	String[] descriptions = new String[length];
549 	System.arraycopy(CONFIG_DESCRIPTIONS, 0, descriptions, 0, length);
550 	return descriptions;
551 }
552 
553 /**
554  * Set the default dimension used for performance results.
555  */
556 public static void setConfigDescriptions(String[] descriptions) {
557 	CONFIG_DESCRIPTIONS = descriptions;
558 }
559 
560 /**
561  * Get all dimensions read from the database.
562  *
563  * @return A list of dimensions.
564  */
565 public static Dim[] getDimensions() {
566 	if (DIMENSIONS == null) return NO_DIMENSION;
567 	int length = DIMENSIONS.length;
568 	Dim[] dimensions = new Dim[length];
569 	for (int i = 0; i < length; i++) {
570 		Dimension dimension = PerformanceTestPlugin.getDimension(DIMENSIONS[i]);
571 		if (dimension == null) {
572 			throw new RuntimeException("There is an unsupported dimension stored in the database: " +DIMENSIONS[i]);
573 		}
574 		dimensions[i] = (Dim) dimension;
575     }
576 	return dimensions;
577 }
578 
579 /**
580  * Return the default dimension used for performance results.
581  *
582  * @return The {@link Dim default dimension}.
583  */
584 public static Dim getDefaultDimension() {
585 	if (DEFAULT_DIM == null) {
586 		DEFAULT_DIM = (Dim) PerformanceTestPlugin.getDefaultDimension();
587 	}
588 	return DEFAULT_DIM;
589 }
590 
591 /**
592  * Set the default dimension used for performance results.
593  */
594 public static void setDefaultDimension(String dim) {
595 	DEFAULT_DIM = (Dim) PerformanceTestPlugin.getDimension(dim);
596 	if (DIMENSIONS != null) {
597 		DEFAULT_DIM_INDEX = Arrays.binarySearch(DIMENSIONS, DEFAULT_DIM.getId());
598 	}
599 }
600 
601 public static Dim[] getResultsDimensions() {
602 	if (RESULTS_DIMENSIONS == null) {
603 		Dimension[] resultsDimensions = PerformanceTestPlugin.getResultsDimensions();
604 		int length = resultsDimensions.length;
605 		RESULTS_DIMENSIONS = new Dim[length];
606 		for (int i = 0; i < length; i++) {
607 			RESULTS_DIMENSIONS[i] = (Dim) resultsDimensions[i];
608 		}
609 	}
610 	return RESULTS_DIMENSIONS;
611 }
612 
613 /**
614  * Set the default dimension used for performance results.
615  */
616 public static void setResultsDimensions(String[] dimensions) {
617 	int length = dimensions.length;
618 	RESULTS_DIMENSIONS = new Dim[length];
619 	for (int i = 0; i < length; i++) {
620 		RESULTS_DIMENSIONS[i] = (Dim) PerformanceTestPlugin.getDimension(dimensions[i]);
621 	}
622 }
623 
624 /**
625  * Return the default dimension used for performance results.
626  *
627  * @return The {@link Dim default dimension}.
628  */
629 public static int getDefaultDimensionIndex() {
630 	if (DEFAULT_DIM == null || DEFAULT_DIM_INDEX == -1) {
631 		getDefaultDimension(); // init default dimension
632 		getDimensions(); // init dimensions
633 		DEFAULT_DIM_INDEX = Arrays.binarySearch(DIMENSIONS, DEFAULT_DIM.getId());
634 	}
635 	return DEFAULT_DIM_INDEX;
636 }
637 
638 /**
639  * Return the ID of the last baseline build before the given date.
640  *
641  * @param date The date the baseline must be run before. If <code>null</code>
642  * 	return the last baseline build stored in the DB.
643  *
644  * @return the ID of the last baseline build before the given date or
645  * 	<code>null</code> if none was run before it...
646  */
647 public static String getLastBaselineBuild(String date) {
648 	if (BUILDS == null) {
649 		queryAllVariations("%"); //$NON-NLS-1$
650 	}
651 	if (date == null) {
652 		if (LAST_BASELINE_BUILD == null) {
653 			return BUILDS[0];
654 		}
655 		return LAST_BASELINE_BUILD;
656 	}
657 	String lastBaselineBuild = null;
658 	for (int i=0; i<BUILDS_LENGTH; i++) {
659 		String build = BUILDS[i];
660 		if (build.startsWith(DB_VERSION_REF)) {
661 			String buildDate = build.substring(build.indexOf('_')+1);
662 			if (buildDate.compareTo(date) < 0) {
663 				if (lastBaselineBuild == null || build.compareTo(lastBaselineBuild) > 0) {
664 					lastBaselineBuild = build;
665 				}
666 			}
667 		}
668 	}
669 	if (lastBaselineBuild == null) {
670 		return BUILDS[0];
671 	}
672 	return lastBaselineBuild;
673 }
674 
675 /**
676  * Return the ID of the last baseline build.
677  *
678  * @return the ID of the last baseline build.
679  */
680 public static String getLastCurrentBuild() {
681 	if (BUILDS == null) {
682 		queryAllVariations("%"); //$NON-NLS-1$
683 	}
684 	return LAST_CURRENT_BUILD;
685 }
686 
687 /**
688  * Returns all the scenarios names read from the database.
689  *
690  * @return The list of all scenarios matching the pattern for a given build.
691  * @see #internalQueryBuildScenarios(String, String)
692  */
693 public static List getScenarios() {
694 	return Arrays.asList(SCENARII);
695 }
696 
697 /**
698  * Init the constants if necessary.
699  */
700 public static void initDbContants() {
701 	if (DB_LOCATION == null) {
702 		DB_LOCATION = PerformanceTestPlugin.getDBLocation();
703 		if (DB_LOCATION == null) {
704 			new RuntimeException("Cannot connect to the DB without a location!");
705 		}
706 	}
707 	if (DB_NAME == null) {
708 		DB_NAME = PerformanceTestPlugin.getDBName();
709 		if (DB_NAME == null) {
710 			new RuntimeException("Cannot connect to the DB without a name!");
711 		}
712 	}
713 	if (DB_VERSION == null) {
714 		DB_VERSION = "v" + DB_NAME.substring(DB_NAME.length()-2);
715 		DB_VERSION_REF = "R-3."+(Character.digit(DB_NAME.charAt(DB_NAME.length()-1), 10)-1);
716 	}
717 }
718 
719 /**
720  * Get all scenarios read from database.
721  *
722  * @return A list of all scenario names matching the default pattern
723  */
724 public static Map queryAllScenarios() {
725 	return getDefault().internalQueryBuildScenarios("%", null); //$NON-NLS-1$
726 }
727 
728 /**
729  * Get all scenarios read from database matching a given pattern.
730  * Note that all scenarios are returned if the pattern is <code>null</code>.
731  *
732  * @param scenarioPattern The pattern of the requested scenarios
733  * @return A map of all scenarios matching the given pattern.
734  * 	The map keys are component names and values are the scenarios list for
735  * 	each component.
736  */
737 static Map queryAllScenarios(String scenarioPattern) {
738 	String pattern = scenarioPattern==null ? "%" : scenarioPattern; //$NON-NLS-1$
739 	return getDefault().internalQueryBuildScenarios(pattern, null);
740 }
741 
742 /**
743  * Get all scenarios read from database matching a given pattern.
744  * Note that all scenarios are returned if the pattern is <code>null</code>.
745  *
746  * @param scenarioPattern The pattern of the requested scenarios
747  * @param buildName The build name
748  * @return A list of scenario names matching the given pattern
749  */
750 static Map queryAllScenarios(String scenarioPattern, String buildName) {
751 	return getDefault().internalQueryBuildScenarios(scenarioPattern, buildName);
752 }
753 
754 /**
755  * Get all variations read from database matching a given configuration pattern.
756  *
757  * @param configPattern The pattern of the requested configurations
758  */
759 static void queryAllVariations(String configPattern) {
760 	getDefault().internalQueryAllVariations(configPattern);
761 }
762 
763 /**
764  * Get all summaries from DB for a given scenario and configuration pattern
765  *
766  * @param scenarioResults The scenario results where to store data
767  * @param configPattern The configuration pattern concerned by the query
768  * @param builds All builds to get summaries, if <code>null</code>, then all DB
769  * 	builds will be concerned.
770  */
771 static void queryScenarioSummaries(ScenarioResults scenarioResults, String configPattern, String[] builds) {
772 	getDefault().internalQueryScenarioSummaries(scenarioResults, configPattern, builds);
773 }
774 
775 /**
776  * Query and store all values for given scenario results
777  *
778  * @param scenarioResults The scenario results where the values has to be put
779  * @param configPattern The pattern of the configuration concerned by the query
780  * @param buildName Name of the last build on which data were stored locally
781  *
782 */
783 static void queryScenarioValues(ScenarioResults scenarioResults, String configPattern, String buildName) {
784 	getDefault().internalQueryScenarioValues(scenarioResults, configPattern, buildName);
785 }
786 
787 /**
788  * dbloc=						embed in home directory
789  * dbloc=/tmp/performance			embed given location
790  * dbloc=net://localhost			connect to local server
791  * dbloc=net://www.eclipse.org	connect to remove server
792  */
793 private void connect() {
794 
795 	if (this.fConnection != null || !DB_CONNECTION)
796 		return;
797 
798 	if (DEBUG) DriverManager.setLogWriter(new PrintWriter(System.out));
799 
800 	// Init DB location and name if not already done
801 	if (DB_LOCATION == null) {
802 		initDbContants();
803 	}
804 
805 	String url = null;
806 	java.util.Properties info = new java.util.Properties();
807 
808 	if (DEBUG) {
809 		DEBUG_WRITER.println();
810 		DEBUG_WRITER.println("==========================================================="); //$NON-NLS-1$
811 		DEBUG_WRITER.println("Database debug information stored while processing"); //$NON-NLS-1$
812 	}
813 	if (LOG) {
814 		LOG_WRITER.println();
815 		LOG_WRITER.println("==========================================================="); //$NON-NLS-1$
816 		LOG_WRITER.println("Database log information stored while processing"); //$NON-NLS-1$
817 	}
818 
819 	this.fDBType = DERBY; // assume we are using Derby
820 	try {
821 		if (DB_LOCATION.startsWith("net://")) { //$NON-NLS-1$
822 			// remote
823 //			fIsEmbedded = false;
824 			// connect over network
825 			if (DEBUG)
826 				DEBUG_WRITER.println("Trying to connect over network..."); //$NON-NLS-1$
827 			Class.forName("com.ibm.db2.jcc.DB2Driver"); //$NON-NLS-1$
828 			info.put("user", PerformanceTestPlugin.getDBUser()); //$NON-NLS-1$
829 			info.put("password", PerformanceTestPlugin.getDBPassword()); //$NON-NLS-1$
830 			info.put("retrieveMessagesFromServerOnGetMessage", "true"); //$NON-NLS-1$ //$NON-NLS-2$
831 			info.put("create", "true"); //$NON-NLS-1$ //$NON-NLS-2$
832 			url = DB_LOCATION + '/' + DB_NAME;
833 		} else if (DB_LOCATION.startsWith("//")) { //$NON-NLS-1$
834 			// remote
835 //			fIsEmbedded = false;
836 			// connect over network
837 			if (DEBUG)
838 				DEBUG_WRITER.println("Trying to connect over network..."); //$NON-NLS-1$
839 			Class.forName("org.apache.derby.jdbc.ClientDriver"); //$NON-NLS-1$
840 			info.put("user", PerformanceTestPlugin.getDBUser()); //$NON-NLS-1$
841 			info.put("password", PerformanceTestPlugin.getDBPassword()); //$NON-NLS-1$
842 			info.put("create", "true"); //$NON-NLS-1$ //$NON-NLS-2$
843 			url = DB_LOCATION + '/' + DB_NAME;
844 		} else {
845 			// workaround for Derby issue:
846 			// http://nagoya.apache.org/jira/browse/DERBY-1
847 			if ("Mac OS X".equals(System.getProperty("os.name"))) //$NON-NLS-1$//$NON-NLS-2$
848 				System.setProperty("derby.storage.fileSyncTransactionLog", "true"); //$NON-NLS-1$ //$NON-NLS-2$
849 
850 			// embedded
851 			try {
852 				Class.forName("org.apache.derby.jdbc.EmbeddedDriver"); //$NON-NLS-1$
853 //				fIsEmbedded = true;
854 			} catch (ClassNotFoundException e) {
855 				Class.forName("com.ihost.cs.jdbc.CloudscapeDriver"); //$NON-NLS-1$
856 				this.fDBType = CLOUDSCAPE;
857 			}
858 			if (DEBUG)
859 				DEBUG_WRITER.println("Loaded embedded " + this.fDBType); //$NON-NLS-1$
860 			File f;
861 			if (DB_LOCATION.length() == 0) {
862 				String user_home = System.getProperty("user.home"); //$NON-NLS-1$
863 				if (user_home == null)
864 					return;
865 				f = new File(user_home, this.fDBType);
866 			} else
867 				f = new File(DB_LOCATION);
868 			url = new File(f, DB_NAME).getAbsolutePath();
869 			info.put("user", PerformanceTestPlugin.getDBUser()); //$NON-NLS-1$
870 			info.put("password", PerformanceTestPlugin.getDBPassword()); //$NON-NLS-1$
871 			info.put("create", "true"); //$NON-NLS-1$ //$NON-NLS-2$
872 		}
873 		try {
874 			this.fConnection = DriverManager.getConnection("jdbc:" + this.fDBType + ":" + url, info); //$NON-NLS-1$ //$NON-NLS-2$
875 		} catch (SQLException e) {
876 			if ("08001".equals(e.getSQLState()) && DERBY.equals(this.fDBType)) { //$NON-NLS-1$
877 				if (DEBUG)
878 					DEBUG_WRITER.println("DriverManager.getConnection failed; retrying for cloudscape"); //$NON-NLS-1$
879 				// try Cloudscape
880 				this.fDBType = CLOUDSCAPE;
881 				this.fConnection = DriverManager.getConnection("jdbc:" + this.fDBType + ":" + url, info); //$NON-NLS-1$ //$NON-NLS-2$
882 			} else
883 				throw e;
884 		}
885 		if (DEBUG)
886 			DEBUG_WRITER.println("connect succeeded!"); //$NON-NLS-1$
887 
888 		this.fConnection.setAutoCommit(false);
889 		this.fSQL = new SQL_Results(this.fConnection);
890 		this.fConnection.commit();
891 
892 	} catch (SQLException ex) {
893 		PerformanceTestPlugin.logError(ex.getMessage());
894 
895 	} catch (ClassNotFoundException e) {
896 		PerformanceTestPlugin.log(e);
897 	}
898 }
899 
900 private void disconnect() {
901 	if (DEBUG)
902 		DEBUG_WRITER.println("disconnecting from DB"); //$NON-NLS-1$
903 	if (this.fSQL != null) {
904 		try {
905 			this.fSQL.dispose();
906 		} catch (SQLException e1) {
907 			PerformanceTestPlugin.log(e1);
908 		}
909 		this.fSQL = null;
910 	}
911 	if (this.fConnection != null) {
912 		try {
913 			this.fConnection.commit();
914 		} catch (SQLException e) {
915 			PerformanceTestPlugin.log(e);
916 		}
917 		try {
918 			this.fConnection.close();
919 		} catch (SQLException e) {
920 			PerformanceTestPlugin.log(e);
921 		}
922 		this.fConnection = null;
923 	}
924 
925 	/*
926 	if (fIsEmbedded) {
927 		try {
928 			DriverManager.getConnection("jdbc:" + fDBType + ":;shutdown=true"); //$NON-NLS-1$ //$NON-NLS-2$
929 		} catch (SQLException e) {
930 			String message = e.getMessage();
931 			if (message.indexOf("system shutdown.") < 0) //$NON-NLS-1$
932 				e.printStackTrace();
933 		}
934 	}
935 	*/
936 }
937 
938 /*
939  * Return the index of the given configuration in the stored list.
940  */
941 private int getConfigId(String config) {
942 	if (CONFIGS == null) return -1;
943 	return Arrays.binarySearch(CONFIGS, config);
944 }
945 
946 SQL_Results getSQL() {
947     return this.fSQL;
948 }
949 
950 /*
951  * Query all comments from database
952  */
953 private void internalQueryAllComments() {
954 	if (this.fSQL == null) return;
955 	if (COMMENTS != null) return;
956 	long start = System.currentTimeMillis();
957 	if (DEBUG) DEBUG_WRITER.print("		[DB query all comments..."); //$NON-NLS-1$
958 	ResultSet result = null;
959 	try {
960 		String[] comments = null;
961 		result = this.fSQL.queryAllComments();
962 		while (result.next()) {
963 			int commentID = result.getInt(1);
964 			// Ignore kind as there's only one
965 			// int commentKind = result.getInt(2);
966 			String comment = result.getString(3);
967 			if (comments == null) {
968 				comments = new String[commentID+10];
969 			} else if (commentID >= comments.length) {
970 				int length = comments.length;
971 				System.arraycopy(comments, 0, comments = new String[commentID+10], 0, length);
972 			}
973 			comments[commentID] = comment;
974 		}
975 		COMMENTS = comments;
976 	} catch (SQLException e) {
977 		PerformanceTestPlugin.log(e);
978 	} finally {
979 		if (result != null) {
980 			try {
981 				result.close();
982 			} catch (SQLException e1) {
983 				// ignored
984 			}
985 		}
986 		if (DEBUG) DEBUG_WRITER.println("done in " + (System.currentTimeMillis() - start) + "ms]"); //$NON-NLS-1$ //$NON-NLS-2$
987 	}
988 }
989 
990 /*
991  * Query all variations. This method stores all config and build names.
992  */
993 private void internalQueryAllVariations(String configPattern) {
994 	if (this.fSQL == null) return;
995 	if (BUILDS != null) return;
996 	long start = System.currentTimeMillis();
997 	if (DEBUG) {
998 		DEBUG_WRITER.print("	- DB query all variations for configuration pattern: "+configPattern); //$NON-NLS-1$
999 		DEBUG_WRITER.print("..."); //$NON-NLS-1$
1000 	}
1001 	ResultSet result = null;
1002 	try {
1003 		CONFIGS = null;
1004 		BUILDS = null;
1005 		BUILDS_LENGTH = 0;
1006 		result = this.fSQL.queryAllVariations(configPattern);
1007 		while (result.next()) {
1008 			String variation = result.getString(1); //  something like "||build=I20070615-1200||config=eclipseperfwin2_R3.3||jvm=sun|"
1009 			StringTokenizer tokenizer = new StringTokenizer(variation, "=|"); //$NON-NLS-1$
1010 			tokenizer.nextToken(); 												// 'build'
1011 			storeBuildName(tokenizer.nextToken());				// 'I20070615-1200'
1012 			tokenizer.nextToken();												// 'config'
1013 			storeConfig(tokenizer.nextToken()); 	// 'eclipseperfwin2_R3.3'
1014 			tokenizer.nextToken();												// 'jvm'
1015 			storeVm(tokenizer.nextToken());					// 'sun'
1016 		}
1017 		if (BUILDS_LENGTH == 0) {
1018 			BUILDS = EMPTY_LIST;
1019 		}
1020 	} catch (SQLException e) {
1021 		PerformanceTestPlugin.log(e);
1022 	} finally {
1023 		if (result != null) {
1024 			try {
1025 				result.close();
1026 			} catch (SQLException e1) {
1027 				// ignored
1028 			}
1029 		}
1030 		if (DEBUG) DEBUG_WRITER.println("done in " + (System.currentTimeMillis() - start) + "ms]"); //$NON-NLS-1$ //$NON-NLS-2$
1031 	}
1032 }
1033 
1034 private Map internalQueryBuildScenarios(String scenarioPattern, String buildName) {
1035 	if (this.fSQL == null) return null;
1036 	long start = System.currentTimeMillis();
1037 	if (DEBUG) {
1038 		DEBUG_WRITER.print("	- DB query all scenarios"); //$NON-NLS-1$
1039 		if (scenarioPattern != null) DEBUG_WRITER.print(" with pattern "+scenarioPattern); //$NON-NLS-1$
1040 		if (buildName != null) DEBUG_WRITER.print(" for build: "+buildName); //$NON-NLS-1$
1041 	}
1042 	ResultSet result = null;
1043 	Map allScenarios = new HashMap();
1044 	try {
1045 		if (buildName == null) {
1046 			result = this.fSQL.queryBuildAllScenarios(scenarioPattern);
1047 		} else {
1048 			result = this.fSQL.queryBuildScenarios(scenarioPattern, buildName);
1049 		}
1050 		int previousId = -1;
1051 		List scenarios = null;
1052 		List scenariosNames = new ArrayList();
1053 		for (int i = 0; result.next(); i++) {
1054 			int id = result.getInt(1);
1055 			String name = result.getString(2);
1056 			scenariosNames.add(name);
1057 			String shortName = result.getString(3);
1058 			int component_id = storeComponent(getComponentNameFromScenario(name));
1059 			if (component_id != previousId) {
1060 				allScenarios.put(COMPONENTS[component_id], scenarios = new ArrayList());
1061 				previousId = component_id;
1062 			}
1063 			scenarios.add(new ScenarioResults(id, name, shortName));
1064 		}
1065 		SCENARII = new String[scenariosNames.size()];
1066 		scenariosNames.toArray(SCENARII);
1067 	} catch (SQLException e) {
1068 		PerformanceTestPlugin.log(e);
1069 	} finally {
1070 		if (result != null) {
1071 			try {
1072 				result.close();
1073 			} catch (SQLException e1) { // ignored
1074 			}
1075 		}
1076 		if (DEBUG) DEBUG_WRITER.println("done in " + (System.currentTimeMillis() - start) + "ms]"); //$NON-NLS-1$ //$NON-NLS-2$
1077 	}
1078 	return allScenarios;
1079 }
1080 
1081 private void internalQueryScenarioValues(ScenarioResults scenarioResults, String configPattern, String buildName) {
1082 	if (this.fSQL == null) return;
1083 	if (DEBUG) {
1084 		DEBUG_WRITER.print("	- DB query all data points for config pattern: "+configPattern+" for scenario: " + scenarioResults.getShortName()); //$NON-NLS-1$ //$NON-NLS-2$
1085 		if (buildName != null) DEBUG_WRITER.print(" for build: "+buildName); //$NON-NLS-1$
1086 	}
1087 	internalQueryAllVariations(configPattern); // need to read all variations to have all build names
1088 	ResultSet result = null;
1089 	try {
1090 		int count = 0;
1091 
1092 		result = buildName == null
1093 			?	this.fSQL.queryScenarioDataPoints(configPattern, scenarioResults.getId())
1094 			:	this.fSQL.queryScenarioBuildDataPoints(configPattern, scenarioResults.getId(), buildName);
1095 		while (result.next()) {
1096 			int dp_id = result.getInt(1);
1097 			int step = result.getInt(2);
1098 			String variation = result.getString(3); //  something like "|build=I20070615-1200||config=eclipseperfwin2_R3.3||jvm=sun|"
1099 			StringTokenizer tokenizer = new StringTokenizer(variation, "=|"); //$NON-NLS-1$
1100 			tokenizer.nextToken(); 													// 'build'
1101 			int build_id = getBuildId(tokenizer.nextToken());		// 'I20070615-1200'
1102 			tokenizer.nextToken();													// 'config'
1103 			int config_id = getConfigId(tokenizer.nextToken()); 		// 'eclipseperflnx3'
1104 			ResultSet rs2 = this.fSQL.queryDimScalars(dp_id);
1105 			while (rs2.next()) {
1106 				int dim_id = rs2.getInt(1);
1107 				storeDimension(dim_id);
1108 				BigDecimal decimalValue = rs2.getBigDecimal(2);
1109 				long value = decimalValue.longValue();
1110 				if (build_id >= 0) { // build id may be negative (i.e. not stored in the array) if new run starts while we're getting results
1111 					scenarioResults.setValue(build_id, dim_id, config_id, step, value);
1112 				}
1113 				count++;
1114 			}
1115 		}
1116 		if (LOG) LOG_WRITER.ends("		-> " + count + " values read");  //$NON-NLS-1$ //$NON-NLS-2$
1117 	} catch (SQLException e) {
1118 		PerformanceTestPlugin.log(e);
1119 	} finally {
1120 		if (result != null) {
1121 			try {
1122 				result.close();
1123 			} catch (SQLException e1) {
1124 				// ignored
1125 			}
1126 		}
1127 	}
1128 }
1129 
1130 private void internalQueryScenarioSummaries(ScenarioResults scenarioResults, String config, String[] builds) {
1131 	if (this.fSQL == null) return;
1132 	long start = System.currentTimeMillis();
1133 	if (DEBUG) {
1134 		DEBUG_WRITER.print("	- DB query all summaries for scenario '"+scenarioResults.getShortName()+"' of '"+config+"' config"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1135 	}
1136 	internalQueryAllComments();
1137 	ResultSet result = null;
1138 	try {
1139 		int scenarioID = scenarioResults.getId();
1140 		// First try to get summaries of elapsed process dimension
1141 		result = this.fSQL.queryScenarioSummaries(scenarioID, config, builds);
1142 		while (result.next()) {
1143 			String variation = result.getString(1); //  something like "|build=I20070615-1200||config=eclipseperfwin2_R3.3||jvm=sun|"
1144 			int summaryKind = result.getShort(2);
1145 			int comment_id = result.getInt(3);
1146 			int dim_id = result.getInt(4);
1147 			if (dim_id != 0) storeDimension(dim_id);
1148 			StringTokenizer tokenizer = new StringTokenizer(variation, "=|"); //$NON-NLS-1$
1149 			tokenizer.nextToken(); 													// 'build'
1150 			String buildName = tokenizer.nextToken();					// 'I20070615-1200'
1151 			tokenizer.nextToken();													// 'config'
1152 			int config_id = getConfigId(tokenizer.nextToken()); 		// 'eclipseperflnx3'
1153 			int build_id = getBuildId(buildName);
1154 			if (build_id >= 0) {
1155 				scenarioResults.setInfos(config_id, build_id, dim_id==0?-1:summaryKind, COMMENTS[comment_id]);
1156 			}
1157 		}
1158 	} catch (SQLException e) {
1159 		PerformanceTestPlugin.log(e);
1160 	} finally {
1161 		if (result != null) {
1162 			try {
1163 				result.close();
1164 			} catch (SQLException e1) {
1165 				// ignored
1166 			}
1167 		}
1168 		if (DEBUG) DEBUG_WRITER.println("done in " + (System.currentTimeMillis() - start) + "ms]"); //$NON-NLS-1$ //$NON-NLS-2$
1169 	}
1170 }
1171 
1172 /*
1173  * Store a build name in the dynamic list.
1174  * The list is sorted alphabetically.
1175  */
1176 private int storeBuildName(String build) {
1177 	boolean isVersion = build.startsWith(DB_BASELINE_PREFIX);
1178 	if (BUILDS == null) {
1179 		BUILDS = new String[1];
1180 		BUILDS[BUILDS_LENGTH++] = build;
1181 		if (isVersion) {
1182 			LAST_BASELINE_BUILD = build;
1183 		} else {
1184 			LAST_CURRENT_BUILD = build;
1185 		}
1186 		return 0;
1187 	}
1188 	int idx = Arrays.binarySearch(BUILDS, build, Util.BUILD_DATE_COMPARATOR);
1189 	if (idx >= 0) return idx;
1190 	int index = -idx-1;
1191 	int length = BUILDS.length;
1192 	if (BUILDS_LENGTH == length) {
1193 		String[] array = new String[length+1];
1194 		if (index > 0) System.arraycopy(BUILDS, 0, array, 0, index);
1195 		array[index] = build;
1196 		if (index < length) {
1197 			System.arraycopy(BUILDS, index, array, index+1, length-index);
1198 		}
1199 		BUILDS = array;
1200 	}
1201 	BUILDS_LENGTH++;
1202 	if (isVersion) {
1203 		if (LAST_BASELINE_BUILD == null || LAST_CURRENT_BUILD == null) {
1204 			LAST_BASELINE_BUILD = build;
1205 		} else {
1206 			String buildDate = LAST_CURRENT_BUILD.substring(1, 9)+LAST_CURRENT_BUILD.substring(10, LAST_CURRENT_BUILD.length());
1207 			String baselineDate = LAST_BASELINE_BUILD.substring(LAST_BASELINE_BUILD.indexOf('_')+1);
1208 			if (build.compareTo(LAST_BASELINE_BUILD) > 0 && baselineDate.compareTo(buildDate) < 0) {
1209 				LAST_BASELINE_BUILD = build;
1210 			}
1211 		}
1212 	} else {
1213 		if (LAST_CURRENT_BUILD == null || build.substring(1).compareTo(LAST_CURRENT_BUILD.substring(1)) >= 0) {
1214 			LAST_CURRENT_BUILD = build;
1215 		}
1216 	}
1217 	return index;
1218 }
1219 
1220 /*
1221  * Store a configuration in the dynamic list.
1222  * The list is sorted alphabetically.
1223  */
storeConfig(String config)1224 private int storeConfig(String config) {
1225 	if (CONFIGS== null) {
1226 		CONFIGS= new String[1];
1227 		CONFIGS[0] = config;
1228 		return 0;
1229 	}
1230 	int idx = Arrays.binarySearch(CONFIGS, config);
1231 	if (idx >= 0) return idx;
1232 	int length = CONFIGS.length;
1233 	System.arraycopy(CONFIGS, 0, CONFIGS = new String[length+1], 0, length);
1234 	CONFIGS[length] = config;
1235 	Arrays.sort(CONFIGS);
1236 	return length;
1237 }
1238 
1239 /*
1240  * Store a component in the dynamic list. The list is sorted alphabetically.
1241  * Note that the array is rebuilt each time a new component is discovered
1242  * as this does not happen so often (e.g. eclipse only has 10 components).
1243  */
storeComponent(String component)1244 private int storeComponent(String component) {
1245 	if (COMPONENTS== null) {
1246 		COMPONENTS= new String[1];
1247 		COMPONENTS[0] = component;
1248 		return 0;
1249 	}
1250 	int idx = Arrays.binarySearch(COMPONENTS, component);
1251 	if (idx >= 0) return idx;
1252 	int length = COMPONENTS.length;
1253 	System.arraycopy(COMPONENTS, 0, COMPONENTS = new String[length+1], 0, length);
1254 	COMPONENTS[length] = component;
1255 	Arrays.sort(COMPONENTS);
1256 	return length;
1257 }
1258 
1259 /*
1260  * Store a dimension in the dynamic list. The list is sorted in ascending order.
1261  * Note that the array is rebuilt each time a new dimension is discovered
1262  * as this does not happen so often (e.g. eclipse only stores two dimensions).
1263  */
storeDimension(int id)1264 public static int storeDimension(int id) {
1265 	if (DIMENSIONS == null) {
1266 		DIMENSIONS = new int[1];
1267 		DIMENSIONS[0] = id;
1268 		return 0;
1269 	}
1270 	int idx = Arrays.binarySearch(DIMENSIONS, id);
1271 	if (idx >= 0) return idx;
1272 	int length = DIMENSIONS.length;
1273 	System.arraycopy(DIMENSIONS, 0, DIMENSIONS = new int[length+1], 0, length);
1274 	DIMENSIONS[length] = id;
1275 	Arrays.sort(DIMENSIONS);
1276 	return length;
1277 }
1278 
1279 /*
1280  * Store a dimension in the dynamic list. The list is sorted alphabetically.
1281  * Note that the array is rebuilt each time a new dimension is discovered
1282  * as this does not happen so often (e.g. eclipse only stores two dimensions).
1283  */
storeVm(String vm)1284 private int storeVm(String vm) {
1285 	if (VMS == null) {
1286 		VMS = new String[1];
1287 		VMS[0] = vm;
1288 		return 0;
1289 	}
1290 	int idx = Arrays.binarySearch(VMS, vm);
1291 	if (idx >= 0) return idx;
1292 	int length = VMS.length;
1293 	System.arraycopy(VMS, 0, VMS = new String[length+1], 0, length);
1294 	VMS[length] = vm;
1295 	Arrays.sort(VMS);
1296 	return length;
1297 }
1298 
1299 }
1300