%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. |