1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package nl.toolforge.karma.core.boot;
20
21 import nl.toolforge.karma.core.ErrorCode;
22 import nl.toolforge.karma.core.KarmaRuntimeException;
23 import nl.toolforge.karma.core.location.LocationException;
24 import nl.toolforge.karma.core.location.LocationLoader;
25 import nl.toolforge.karma.core.manifest.ManifestCollector;
26 import nl.toolforge.karma.core.manifest.ManifestLoader;
27 import org.apache.commons.io.FileUtils;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.log4j.FileAppender;
31 import org.apache.log4j.Level;
32 import org.apache.log4j.Logger;
33 import org.apache.log4j.PatternLayout;
34
35 import java.io.File;
36 import java.io.FileInputStream;
37 import java.io.FileNotFoundException;
38 import java.io.IOException;
39 import java.util.Properties;
40
41 /***
42 * <p>A <code>WorkingContext</code> is used by Karma to determine the environment in which the user wants to use Karma. A
43 * working context is represented on your local harddisk by a directory in which a developers' project work will be
44 * stored. The <code>WorkingContext</code> class is the bridge from Karma domain objects (<code>Manifest</code> and
45 * <code>Module</code> to name the most important ones) to a developer's harddisk.
46 *
47 * <p>A WorkingContext should be configured before it can be constructed. The
48 * {@link #configure(WorkingContextConfiguration)}-method should be called to configure a WorkingContext.
49 *
50 * @author D.A. Smedes
51 * @version $Id: WorkingContext.java,v 1.24 2004/11/16 22:18:28 hippe Exp $
52 */
53 public final class WorkingContext {
54
55 public final static ErrorCode CANNOT_REMOVE_ACTIVE_WORKING_CONTEXT = new ErrorCode("WCO-00001");
56
57 public final static String WORKING_CONTEXT_PREFERENCE = "karma.working-context";
58
59 private final static String DEFAULT_CONVERSION_PATTERN = "%d{HH:mm:ss} [%5p] - %m%n";
60
61 static {
62
63
64
65 try {
66
67 if (WorkingContext.class.getClassLoader().getResource("log4j.xml") != null) {
68
69 Logger.getLogger(WorkingContext.class).info("'Log4j.xml' used to for logging configuration.");
70
71 } else {
72
73
74
75 Logger root = Logger.getRootLogger();
76
77 String karmaHome = System.getProperty("karma.home", System.getProperty("user.home"));
78
79
80
81 new File(karmaHome, "logs").mkdirs();
82
83 File defaultLogFile = new File(karmaHome, "logs/karma-default.log");
84
85 PatternLayout patternLayout = new PatternLayout(DEFAULT_CONVERSION_PATTERN);
86
87 FileAppender fileAppender = new FileAppender(patternLayout, defaultLogFile.getPath(), false);
88 fileAppender.setName("Default Karma logging appender.");
89
90
91
92 root.removeAppender(root.getAppender("console"));
93
94 root.addAppender(fileAppender);
95
96 String logLevel = null;
97 logLevel = (System.getProperty("loglevel") == null ? "DEBUG" : System.getProperty("loglevel"));
98 logLevel = (logLevel.toUpperCase().matches("ALL|DEBUG|ERROR|FATAL|INFO|OFF|WARN") ? logLevel : "DEBUG");
99
100 root.setLevel(Level.toLevel(logLevel));
101
102
103
104 Logger dig = Logger.getLogger("org.apache.commons.digester");
105 dig.isAttached(fileAppender);
106 dig.setLevel(Level.OFF);
107
108 Logger.getLogger(WorkingContext.class).info(
109 "Default logging configuration enabled; override by placing 'log4j.xml' and 'log4j.dtd' on your classpath.");
110 }
111
112 } catch (Exception e) {
113 e.printStackTrace();
114 throw new KarmaRuntimeException("*** PANIC *** Log4j system could not be initialized.");
115 }
116 }
117
118 public static final String CONFIGURATION_BASE_DIRECTORY = System.getProperty("user.home") + File.separator + ".karma";
119
120
121 /***
122 * Property indicating the base directory for development projects. All manifests will be checked out under this
123 * directory, and the manifest store and location store are checked out at this location as well.
124 */
125 public static final String PROJECT_BASE_DIRECTORY_PROPERTY = "project.basedir";
126
127 /***
128 * Property indicating the root of a repository directory `Maven style`. For those who don't know Maven, check out
129 * the <a href="http://maven.apache.org">Maven</a> website. This directory does not have to be the default Maven
130 * repository directory. It can be any directory on a users' harddisk, as long as binary dependencies can be resolved
131 * `Maven style`, because that is what Karma does as well.
132 */
133 public static final String PROJECT_LOCAL_REPOSITORY_PROPERTY = "project.local.repository";
134
135 public static final String MANIFEST_STORE_MODULE = "manifest-store.module";
136 public static final String LOCATION_STORE_MODULE = "location-store.module";
137
138 /***
139 * The property that identifies the local directory where jar dependencies can be found. Dependencies are
140 * resolved Maven style, but to support environments where Maven is not available, the directory is configurable.
141 * The default Maven repository is used when this property is not set in <code>karma.properties</code>.
142 */
143
144 /*** The default working context. */
145 public static final String DEFAULT = "default";
146
147 private static File localRepository = null;
148
149 private String workingContext = null;
150
151 private ManifestCollector manifestCollector = null;
152 private ManifestLoader manifestLoader = null;
153 private LocationLoader locationLoader = null;
154
155 private WorkingContextConfiguration configuration = null;
156
157 private static final Log logger = LogFactory.getLog(WorkingContext.class);
158
159 private static File configurationBaseDir = null;
160
161 /***
162 * Constructs a <code>WorkingContext</code> in the default configuration base directory. The
163 * {@link #configure(WorkingContextConfiguration)}-method should be called to configure this working context.
164 *
165 * @param workingContext A working context name. If <code>workingContext</code> doesn't match the <code>\w+</code>
166 * pattern, {@link DEFAULT} is assumed.
167 */
168 public WorkingContext(String workingContext) {
169 this(workingContext, new File(CONFIGURATION_BASE_DIRECTORY));
170 }
171
172 /***
173 * Constructs a <code>WorkingContext</code> with <code>configBaseDir</code> as the configuration base directory. When
174 * <code>configBaseDir</code> does not exist, it will be created. The {@link #configure(WorkingContextConfiguration)}-
175 * method should be called to configure this working context.
176 *
177 * @param workingContext A working context name. If <code>workingContext</code> doesn't match the <code>\w+</code>
178 * pattern, {@link DEFAULT} is assumed.
179 * @param configBaseDir The configuration base directory. If the directory does not exist, it will be created.
180 */
181 public WorkingContext(String workingContext, File configBaseDir) {
182
183 if (!workingContext.matches("//w[//w//-]*")) {
184 workingContext = DEFAULT;
185 }
186 this.workingContext = workingContext;
187
188 if (configBaseDir == null) {
189 throw new IllegalArgumentException("Configuration base directory cannot be null.");
190 }
191 configurationBaseDir = configBaseDir;
192 configurationBaseDir.mkdirs();
193 }
194
195 /***
196 * Returns a <code>File</code> reference to the default base directory for Karma configuration files. When the
197 * directory does not exist, it is created.
198 *
199 * @return A <code>File</code> reference to the default base directory for Karma configuration files.
200 */
201 public static File getConfigurationBaseDir() {
202
203 if (configurationBaseDir == null) {
204 throw new KarmaRuntimeException(
205 "For all practical purposes, the configuration base directory has to " +
206 "be initialized. The static call you made should be preceded once by calling the " +
207 "WorkingContext constructor (will be replaced by a better solution in later releases).");
208 }
209 return configurationBaseDir;
210 }
211
212 public void configure(WorkingContextConfiguration configuration) {
213 if (configuration == null) {
214 throw new IllegalArgumentException("Configuration cannot be null for a working context.");
215 }
216
217 this.configuration = configuration;
218
219 String p = configuration.getProperty(PROJECT_LOCAL_REPOSITORY_PROPERTY);
220 if (p == null || "".equals(p)) {
221 localRepository = new File(System.getProperty("user.home"), ".maven/repository");
222 } else {
223 localRepository = new File(p);
224 }
225 }
226
227 /***
228 * Returns the name of this working context.
229 *
230 * @return The name of this working context.
231 */
232 public String getName() {
233 return workingContext;
234 }
235
236 /***
237 * Get the configuration for this working context or <code>null</code> it this working context had not been
238 * configured.
239 *
240 * @return The configuration for this working context.
241 */
242 public WorkingContextConfiguration getConfiguration() {
243 return configuration;
244 }
245
246 /***
247 * Get the properties of this working context. The properties are
248 * stored in the karma.properties, which are located in the project base dir.
249 *
250 * @return A Properties object containing the properties of this working
251 * context or an empty Properties object when something went wrong.
252 */
253 public Properties getProperties() {
254 Properties properties = new Properties();
255 try {
256 properties.load(new FileInputStream(new File(getProjectBaseDirectory(), "karma.properties")));
257 } catch (FileNotFoundException fnfe) {
258 logger.info("karma.properties not found for working context '"+getName()+"'.");
259 } catch (IOException ioe) {
260 logger.error("karma.properties could not be loaded for working context '"+getName()+"'", ioe);
261 }
262 return properties;
263 }
264
265 /***
266 * Removes a working contexts' configuration directory.
267 */
268 public synchronized void remove() throws IOException {
269 FileUtils.deleteDirectory(getWorkingContextConfigurationBaseDir());
270 }
271
272
273 /***
274 * Returns a <code>File</code> reference to the configuration directory for the current working context. When the
275 * directory does not exist, it is created. This method will return the directory <code>File</code> reference to
276 * <code>$HOME/.karma/working-contexts/<working-context-name></code>.
277 *
278 * @return a <code>File</code> reference to the configuration directory for the current working context.
279 */
280 public File getWorkingContextConfigurationBaseDir() {
281
282
283
284 File workingContextsDir = new File(configurationBaseDir, "working-contexts");
285 workingContextsDir.mkdir();
286
287 File file = new File(workingContextsDir, workingContext);
288 if (!file.exists()) {
289 file.mkdir();
290 }
291 return file;
292 }
293
294 /***
295 * Returns a <code>File</code> reference to the project base directory, which can be configured by the
296 * <code>projects.basedir</code> property in the <code>working-context.xml</code> file.
297 *
298 * @return a <code>File</code> reference to the project base directory.
299 */
300 public File getProjectBaseDirectory() {
301
302 String projectBaseDirProperty = getConfiguration().getProperty(PROJECT_BASE_DIRECTORY_PROPERTY);
303
304 if (projectBaseDirProperty == null) {
305 throw new KarmaRuntimeException("Property `project.basedir` is not configured for working context `" + this + "`.");
306 }
307
308 File projectBaseDir = new File(projectBaseDirProperty);
309 if (!projectBaseDir.exists()) {
310 projectBaseDir.mkdir();
311 }
312 return projectBaseDir;
313 }
314
315 /***
316 * Returns a <code>File</code> reference to the administration directory for the working context. In the
317 * administration directory, the manifest store and the location store are located for the current working context.
318 *
319 * @return A reference to the administration directory for the current working context.
320 */
321 public File getAdminDir() {
322
323 File m = new File(getProjectBaseDirectory(), ".admin");
324 if (!m.exists()) {
325 m.mkdir();
326 }
327
328 return m;
329 }
330
331 /***
332 * Returns a <code>File</code> reference to the manifest store directory for the working context. When the directory
333 * does not exist, it will be created. In this directory, the manifest store will be checked out.
334 *
335 * @return A reference to the manifest store directory.
336 */
337 public File getManifestStoreBasedir() {
338
339 File l = new File(getAdminDir(), "manifest-store");
340 if (!l.exists()) {
341 l.mkdirs();
342 }
343
344 return l;
345 }
346
347 /***
348 * Returns a <code>File</code> reference to the location store directory for the working context. When the directory
349 * does not exist, it will be created. In this directory, the location store will be checked out.
350 *
351 * @return A reference to the location store directory.
352 */
353 public File getLocationStoreBasedir() {
354
355 File l = new File(getAdminDir(), "location-store");
356 if (!l.exists()) {
357 l.mkdirs();
358 }
359
360 return l;
361 }
362
363 /***
364 * See {@link PROJECT_LOCAL_REPOSITORY_PROPERTY}. When the property is not set, the default repository is
365 * assumed to be in {@link #getConfigurationBaseDir()}/<code>.repository</code>.
366 *
367 * @return See method description.
368 *
369 * @see PROJECT_LOCAL_REPOSITORY_PROPERTY
370 */
371 public static File getLocalRepository() {
372 return localRepository;
373 }
374
375 public static File getKarmaHome() {
376
377 if (System.getProperty("karma.home") == null) {
378 throw new KarmaRuntimeException("KARMA_HOME (karma.home) environment variable has not been set.");
379 }
380
381 return new File(System.getProperty("karma.home"));
382 }
383
384 /***
385 * <p>Determines the last used manifest for this working context. This fact is maintained in the <code>.java</code> file
386 * on a users' harddisk, as per the specification for <code>java.template.prefs</code>, included in the JDK since
387 * <code>1.4</code>.
388 *
389 * <p>A <code>String</code> made up of the working context name and <code>karma.manifest.last</code>.
390 */
391 public String getContextManifestPreference() {
392 return getName() + "." + "karma.manifest.last";
393 }
394
395 /***
396 * Returns a reference to the <code>LocationLoader</code> for the working context.
397 * @return A location loader.
398 */
399 public LocationLoader getLocationLoader() throws LocationException {
400 if (locationLoader == null) {
401 locationLoader = new LocationLoader(this);
402 locationLoader.load();
403 }
404 return locationLoader;
405 }
406
407 /***
408 * Returns a reference to the <code>ManifestCollector</code> for the working context.
409 * @return A manifest loader.
410 */
411 public ManifestCollector getManifestCollector() {
412 if (manifestCollector == null) {
413 manifestCollector = new ManifestCollector(this);
414 }
415 return manifestCollector;
416 }
417
418 /***
419 * Returns a reference to the <code>ManifestLoader</code> for the working context.
420 * @return A manifest loader.
421 */
422 public ManifestLoader getManifestLoader() {
423 if (manifestLoader == null) {
424 manifestLoader = new ManifestLoader(this);
425 }
426 return manifestLoader;
427 }
428
429 /***
430 * Returns the working contexts' name.
431 *
432 * @return The working contexts' name.
433 */
434 public String toString() {
435 return getName();
436 }
437
438 }