| %line | %branch | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| nl.toolforge.karma.core.boot.WorkingContextConfiguration |
|
|
| 1 | /* |
|
| 2 | Karma core - Core of the Karma application |
|
| 3 | Copyright (C) 2004 Toolforge <www.toolforge.nl> |
|
| 4 | ||
| 5 | This library is free software; you can redistribute it and/or |
|
| 6 | modify it under the terms of the GNU Lesser General Public |
|
| 7 | License as published by the Free Software Foundation; either |
|
| 8 | version 2.1 of the License, or (at your option) any later version. |
|
| 9 | ||
| 10 | This library is distributed in the hope that it will be useful, |
|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 13 | Lesser General Public License for more details. |
|
| 14 | ||
| 15 | You should have received a copy of the GNU Lesser General Public |
|
| 16 | License along with this library; if not, write to the Free Software |
|
| 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
| 18 | */ |
|
| 19 | package nl.toolforge.karma.core.boot; |
|
| 20 | ||
| 21 | import nl.toolforge.karma.core.ErrorCode; |
|
| 22 | import nl.toolforge.karma.core.location.Location; |
|
| 23 | import nl.toolforge.karma.core.location.LocationDescriptor; |
|
| 24 | import nl.toolforge.karma.core.location.LocationException; |
|
| 25 | import nl.toolforge.karma.core.location.LocationFactory; |
|
| 26 | import org.apache.commons.digester.Digester; |
|
| 27 | import org.apache.commons.logging.Log; |
|
| 28 | import org.apache.commons.logging.LogFactory; |
|
| 29 | import org.xml.sax.SAXException; |
|
| 30 | ||
| 31 | import java.io.BufferedWriter; |
|
| 32 | import java.io.File; |
|
| 33 | import java.io.FileWriter; |
|
| 34 | import java.io.IOException; |
|
| 35 | import java.io.Writer; |
|
| 36 | import java.text.MessageFormat; |
|
| 37 | import java.util.ArrayList; |
|
| 38 | import java.util.Enumeration; |
|
| 39 | import java.util.Iterator; |
|
| 40 | import java.util.List; |
|
| 41 | import java.util.Properties; |
|
| 42 | ||
| 43 | /** |
|
| 44 | * <p>Configuration class for a <code>WorkingContext</code>. A <code>WorkingContextConfiguration</code> consists of the |
|
| 45 | * following configuration: |
|
| 46 | * |
|
| 47 | * <ul> |
|
| 48 | * <li>Properties that can be used by Karma. Three properties are mandatory : |
|
| 49 | * <ul> |
|
| 50 | * <li> |
|
| 51 | * <code>project.baseDir</code>, indicating the directory where projects for a working context are stored. |
|
| 52 | * </li> |
|
| 53 | * <li> |
|
| 54 | 520 | * <code>manifest-store.module</code>, which is the module name for the manifest store in a version control |
| 55 | * system. Note that the format of the module name might be version control system dependent. |
|
| 56 | 720 | * </li> |
| 57 | * <li> |
|
| 58 | 720 | * <code>location-store.module</code>, which is the module name for the location store in a version control |
| 59 | 720 | * system. Note that the format of the module name might be version control system dependent. |
| 60 | * </li> |
|
| 61 | 720 | * </ul> |
| 62 | * <li/> |
|
| 63 | 720 | * <li>A manifest store <code>Location</code>, describing the version control system where the |
| 64 | * <code>manifest-store.module</code> module can be found. |
|
| 65 | 720 | * <li/> |
| 66 | 720 | * <li>A location store <code>Location</code>, describing the version control system where the |
| 67 | 720 | * <code>location-store.module</code> module can be found. |
| 68 | 720 | * <li/> |
| 69 | * </ul> |
|
| 70 | * |
|
| 71 | 10 | * <p>The configuration is not loaded automatically. By calling the {@link #load()}-method the configuration will be |
| 72 | * loaded. |
|
| 73 | * |
|
| 74 | * @author D.A. Smedes |
|
| 75 | 0 | * @version $Id: WorkingContextConfiguration.java,v 1.6 2004/11/03 20:54:14 asmedes Exp $ |
| 76 | 0 | */ |
| 77 | public final class WorkingContextConfiguration { |
|
| 78 | ||
| 79 | 180 | public static final ErrorCode CONFIGURATION_LOAD_ERROR = new ErrorCode("WCC-00001"); |
| 80 | 12 | |
| 81 | 690 | private static Log logger = LogFactory.getLog(WorkingContextConfiguration.class); |
| 82 | 46 | |
| 83 | 45 | // private File workingContextConfigurationFile = null; |
| 84 | 35 | |
| 85 | 525 | private ManifestStore manifestStore = null; |
| 86 | 560 | private LocationStore locationStore = null; |
| 87 | 35 | |
| 88 | 525 | private Properties configuration = null; |
| 89 | 35 | |
| 90 | 525 | private WorkingContext workingContext = null; |
| 91 | 35 | |
| 92 | ||
| 93 | 7330 | |
| 94 | /** |
|
| 95 | * Creates a configuration object using <code>configFile</code> as the configuration file. The configuration is |
|
| 96 | * loaded by calling {@link #load()}. |
|
| 97 | 7330 | * |
| 98 | * @param workingContext The <code>WorkingContext</code> for this configuration. |
|
| 99 | */ |
|
| 100 | 525 | public WorkingContextConfiguration(WorkingContext workingContext) { |
| 101 | 35 | |
| 102 | 525 | if (workingContext == null) { |
| 103 | 50 | throw new IllegalArgumentException("Working context cannot be null."); |
| 104 | 1 | } |
| 105 | 384 | |
| 106 | 894 | this.workingContext = workingContext; |
| 107 | 544 | configuration = new Properties(); |
| 108 | 510 | } |
| 109 | ||
| 110 | 64 | private File getConfigFile() { |
| 111 | 960 | return new File(workingContext.getWorkingContextConfigurationBaseDir(), "working-context.xml"); |
| 112 | } |
|
| 113 | ||
| 114 | 63 | /** |
| 115 | 63 | * Returns the <code>LocationStore</code> for this configuration. Can be <code>null</code> if not configured properly. |
| 116 | * |
|
| 117 | * @return The <code>LocationStore</code> for this configuration. Can be <code>null</code> if not configured properly. |
|
| 118 | 710 | */ |
| 119 | 0 | public LocationStore getLocationStore() { |
| 120 | 448 | return locationStore; |
| 121 | } |
|
| 122 | 710 | |
| 123 | 0 | /** |
| 124 | 710 | * Returns the <code>ManifestStore</code> for this configuration. Can be <code>null</code> if not configured properly. |
| 125 | * |
|
| 126 | 63 | * @return The <code>ManifestStore</code> for this configuration. Can be <code>null</code> if not configured properly. |
| 127 | 773 | */ |
| 128 | public ManifestStore getManifestStore() { |
|
| 129 | 602 | return manifestStore; |
| 130 | } |
|
| 131 | ||
| 132 | /** |
|
| 133 | * Sets the manifest store for this configuration. <code>null</code>s are allowed. |
|
| 134 | * |
|
| 135 | * @param manifestStore The manifest store for this configuration. |
|
| 136 | 710 | */ |
| 137 | public void setManifestStore(ManifestStore manifestStore) { |
|
| 138 | 837 | this.manifestStore = manifestStore; |
| 139 | 2967 | } |
| 140 | 2840 | |
| 141 | /** |
|
| 142 | 127 | * Sets the location store for this configuration. <code>null</code>s are allowed. |
| 143 | 127 | * |
| 144 | * @param locationStore The location store for this configuration. |
|
| 145 | 710 | */ |
| 146 | public void setLocationStore(LocationStore locationStore) { |
|
| 147 | 710 | this.locationStore = locationStore; |
| 148 | 0 | } |
| 149 | ||
| 150 | 710 | |
| 151 | /** |
|
| 152 | 32 | * |
| 153 | 64 | * @param key |
| 154 | 32 | * @return <code>null</code> if the property is not found. |
| 155 | */ |
|
| 156 | public String getProperty(String key) { |
|
| 157 | ||
| 158 | 1778 | if (configuration == null) { |
| 159 | 710 | return null; |
| 160 | } |
|
| 161 | 710 | |
| 162 | 1778 | return configuration.getProperty(key); |
| 163 | } |
|
| 164 | ||
| 165 | ||
| 166 | ||
| 167 | /** |
|
| 168 | 710 | * Adds or changes a property in the current configuration. When a property with key <code>name</code> exists, its |
| 169 | * value is overwritten with <code>value</code>. |
|
| 170 | 730 | */ |
| 171 | public void setProperty(String name, String value) { |
|
| 172 | 1178 | configuration.setProperty(name, value); |
| 173 | 448 | } |
| 174 | 730 | |
| 175 | ||
| 176 | ||
| 177 | /** |
|
| 178 | 730 | * Thorough checks of this configuration is valid, and if it is not, returns the <code>ErrorCode</code> to indicate |
| 179 | * what went wrong or <code>null</code> if nothing went wrong, and this configuration is ready to use. |
|
| 180 | 730 | * |
| 181 | 710 | * @return An <code>ErrorCode</code> indicating the exact failure or <code>null</code> of nothing it wrong. |
| 182 | 710 | */ |
| 183 | public ErrorCode check() { |
|
| 184 | ||
| 185 | 710 | try { |
| 186 | 690 | if (load()) { |
| 187 | 690 | // ok |
| 188 | 20 | } |
| 189 | 0 | } catch (WorkingContextException e) { |
| 190 | 20 | return CONFIGURATION_LOAD_ERROR; |
| 191 | 20 | } |
| 192 | 20 | |
| 193 | 0 | return null; |
| 194 | } |
|
| 195 | 20 | |
| 196 | ||
| 197 | ||
| 198 | 20 | |
| 199 | ||
| 200 | 32 | /** |
| 201 | 32 | * <p>Loads the configuration from <code>working-context.xml</code>. When the file did not exists, <code>false</code> |
| 202 | * will be returned. Otherwise, this method returns <code>true</code> and the configuration succeeded. Note that |
|
| 203 | * this method performs no validation on the configuration itself. This is left to the user. |
|
| 204 | 32 | * |
| 205 | 32 | * <p>When the configuration could be loaded, this method returns <code>true</code>. This is not to say that the |
| 206 | 32 | * configuration is correct. The configuration should still be checked for correctness by the client. |
| 207 | 52 | * |
| 208 | * <p>Calling this method overwrites any properties already set for this configuration. |
|
| 209 | 32 | * |
| 210 | 32 | * @return <code>true</code> when the configuration could be loaded, <code>false</code> if it |
| 211 | 20 | * couldn't. |
| 212 | * |
|
| 213 | * @throws WorkingContextException When an <code>IOException</code> or <code>SAXException</code> occurs, indicating |
|
| 214 | * an error when reading a configuration file, which could result by the client in |
|
| 215 | * specific actions (thus the exception and not the <code>true</code> or |
|
| 216 | 32 | * <code>false</code>. |
| 217 | 32 | */ |
| 218 | 32 | public boolean load() throws WorkingContextException { |
| 219 | 160 | |
| 220 | 704 | configuration = new Properties(); |
| 221 | 128 | |
| 222 | // Read properties |
|
| 223 | // |
|
| 224 | 448 | Digester propertyDigester = getPropertyDigester(); |
| 225 | 32 | |
| 226 | 480 | List properties = null; |
| 227 | 32 | |
| 228 | 32 | try { |
| 229 | 448 | properties = (List) propertyDigester.parse(getConfigFile()); |
| 230 | 32 | } catch (SAXException e) { |
| 231 | 32 | logger.error(e); |
| 232 | 0 | throw new WorkingContextException("XML error in configuration for working context `" + workingContext + "`. ", e); |
| 233 | 0 | } catch (IOException e) { |
| 234 | 0 | logger.error(e); |
| 235 | 0 | throw new WorkingContextException(e); |
| 236 | 448 | } |
| 237 | 32 | |
| 238 | 480 | for (Iterator i = properties.iterator(); i.hasNext();) { |
| 239 | 1824 | Property property = (Property) i.next(); |
| 240 | 1824 | configuration.put(property.getName(), property.getValue()); |
| 241 | } |
|
| 242 | ||
| 243 | // Read manifests-store and location-store data |
|
| 244 | // |
|
| 245 | 480 | Digester locationDigester = LocationDescriptor.getDigester(); |
| 246 | 32 | |
| 247 | 512 | List locations = null; |
| 248 | 64 | |
| 249 | 64 | try { |
| 250 | 512 | locations = (List) locationDigester.parse(getConfigFile()); |
| 251 | 64 | } catch (SAXException e) { |
| 252 | 64 | logger.error(e); |
| 253 | 0 | throw new WorkingContextException("XML error in configuration for working context `" + workingContext + "`. ", e); |
| 254 | 64 | } catch (IOException e) { |
| 255 | 64 | logger.error(e); |
| 256 | 64 | throw new WorkingContextException(e); |
| 257 | 544 | } |
| 258 | 32 | |
| 259 | 480 | if (locations == null) { |
| 260 | 64 | return false; |
| 261 | 32 | } |
| 262 | ||
| 263 | // Expecting exactly two items !!! Only 'manifest-store' and 'location-store' are accepted. |
|
| 264 | // |
|
| 265 | 448 | for (Iterator i = locations.iterator(); i.hasNext();) { |
| 266 | ||
| 267 | 896 | LocationDescriptor descriptor = (LocationDescriptor) i.next(); |
| 268 | ||
| 269 | 896 | Location location = null; |
| 270 | 32 | try { |
| 271 | 928 | location = LocationFactory.getInstance().createLocation(descriptor); |
| 272 | 0 | } catch (LocationException e) { |
| 273 | 0 | return false; |
| 274 | 928 | } |
| 275 | 32 | |
| 276 | 896 | location.setWorkingContext(workingContext); |
| 277 | ||
| 278 | 896 | if ("manifest-store".equals(location.getId())) { |
| 279 | ||
| 280 | 448 | String moduleName = (String) configuration.get(WorkingContext.MANIFEST_STORE_MODULE); |
| 281 | 448 | manifestStore = new ManifestStore(workingContext, moduleName, location); |
| 282 | ||
| 283 | 448 | } else if ("location-store".equals(location.getId())) { |
| 284 | ||
| 285 | 448 | String moduleName = (String) configuration.get(WorkingContext.LOCATION_STORE_MODULE); |
| 286 | 448 | locationStore = new LocationStore(workingContext, moduleName, location); |
| 287 | ||
| 288 | } else { |
|
| 289 | 0 | logger.error( |
| 290 | "Invalid location element in `working-context.xml`. " + |
|
| 291 | "Expecting a `manifest-store` and `location-store` entry."); |
|
| 292 | 0 | return false; |
| 293 | } |
|
| 294 | } |
|
| 295 | ||
| 296 | 448 | if (manclass="keyword">ifestStore == null || locationStore == null) { |
| 297 | 0 | return false; |
| 298 | 710 | } |
| 299 | ||
| 300 | 1158 | return true; |
| 301 | } |
|
| 302 | 710 | |
| 303 | /** |
|
| 304 | 710 | * Stores the all configuration items in <code>configuration</code> in the <code>working-context.xml</code> file. |
| 305 | 710 | * |
| 306 | 710 | * @throws WorkingContextException When storing failed. |
| 307 | */ |
|
| 308 | 710 | public void store() throws WorkingContextException { |
| 309 | ||
| 310 | // todo this implementation can be made more efficient, but it's ok for now. |
|
| 311 | ||
| 312 | 0 | if (configuration == null) { |
| 313 | 0 | throw new NullPointerException("Configuration cannot be null."); |
| 314 | } |
|
| 315 | ||
| 316 | // Check the (mandatory) configuration |
|
| 317 | // |
|
| 318 | ||
| 319 | 0 | StringBuffer buffer = new StringBuffer(); |
| 320 | 0 | buffer.append("<?xml version=\ŕ.0\"?>\n"); |
| 321 | ||
| 322 | 0 | buffer.append( |
| 323 | "<wc:working-context\n" + |
|
| 324 | " xmlns:wc=\"http://www.toolforge.org/specifications/working-context\"\n" + |
|
| 325 | " xmlns:loc=\"http://www.toolforge.org/specifications/location\">\n"); |
|
| 326 | ||
| 327 | // <properties>-element |
|
| 328 | // |
|
| 329 | 0 | buffer.append(" <wc:properties>\n"); |
| 330 | ||
| 331 | 0 | MessageFormat formatter = new MessageFormat(" <wc:property name=\"{0}\" value=\"{1}\"/>\n"); |
| 332 | ||
| 333 | 0 | Enumeration e = configuration.propertyNames(); |
| 334 | ||
| 335 | 0 | while (e.hasMoreElements()) { |
| 336 | ||
| 337 | 0 | String key = (String) e.nextElement(); |
| 338 | 0 | String value = configuration.getProperty(key); |
| 339 | ||
| 340 | 0 | buffer.append(formatter.format(new String[]{key, value})); |
| 341 | } |
|
| 342 | ||
| 343 | 0 | buffer.append(" </wc:properties>\n\n"); |
| 344 | // |
|
| 345 | // </properties>-element |
|
| 346 | ||
| 347 | 0 | if (manclass="keyword">ifestStore == null && locationStore == null) { |
| 348 | // |
|
| 349 | } else { |
|
| 350 | ||
| 351 | 0 | buffer.append(" <loc:locations>\n"); |
| 352 | ||
| 353 | 0 | if (manclass="keyword">ifestStore != null) { |
| 354 | 0 | buffer.append(manifestStore.getLocation().asXML()); |
| 355 | } |
|
| 356 | 0 | if (locationStore != null) { |
| 357 | 0 | buffer.append(locationStore.getLocation().asXML()); |
| 358 | } |
|
| 359 | ||
| 360 | 0 | buffer.append(" </loc:locations>\n"); |
| 361 | ||
| 362 | } |
|
| 363 | ||
| 364 | 0 | buffer.append("\n"); |
| 365 | ||
| 366 | 0 | buffer.append("</wc:working-context>\n"); |
| 367 | ||
| 368 | 32 | // Write to file `working-context.xml` |
| 369 | 32 | // |
| 370 | 32 | try { |
| 371 | 32 | if (!getConfigFile().exists()) { |
| 372 | 32 | getConfigFile().createNewFile(); |
| 373 | 32 | } |
| 374 | 32 | Writer writer = new BufferedWriter(class="keyword">new FileWriter(getConfigFile())); |
| 375 | 64 | writer.write(buffer.toString()); |
| 376 | 64 | writer.flush(); |
| 377 | 32 | } catch (IOException ioe) { |
| 378 | 32 | logger.error(ioe); |
| 379 | 32 | throw new WorkingContextException(ioe); |
| 380 | 0 | } |
| 381 | 0 | } |
| 382 | ||
| 383 | ||
| 384 | ||
| 385 | /* |
|
| 386 | * The working-context configuration file is populated with elements from two different namespaces. One is the |
|
| 387 | * working context stuff itself (all sorts of properties), the other is from the <code>location</code> namespace, |
|
| 388 | * configuration for the manifest store and the location store. |
|
| 389 | * |
|
| 390 | * <p>This method gets a <code>Digester</code> for the general properties for the working context. |
|
| 391 | */ |
|
| 392 | private Digester getPropertyDigester() { |
|
| 393 | ||
| 394 | 448 | Digester digester = new Digester(); |
| 395 | ||
| 396 | 448 | digester.setNamespaceAware(true); |
| 397 | ||
| 398 | 448 | digester.addObjectCreate("working-context/properties", ArrayList.class); |
| 399 | ||
| 400 | 448 | digester.addObjectCreate("working-context/properties/property", Property.class); |
| 401 | 448 | digester.addSetProperties("working-context/properties/property"); |
| 402 | 448 | digester.addSetNext("working-context/properties/property", "add"); |
| 403 | ||
| 404 | 448 | return digester; |
| 405 | } |
|
| 406 | } |
| This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |