001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026: package org.cougaar.util;
027:
028: import java.io.File;
029: import java.io.IOException;
030: import java.net.MalformedURLException;
031: import java.net.URL;
032: import java.security.AccessControlException;
033: import java.util.Collections;
034: import java.util.HashMap;
035: import java.util.Map;
036: import org.cougaar.bootstrap.SystemProperties;
037:
038: /**
039: * Configuration is a holder of a collection of static configuration utility methods,
040: * mostly for use by ConfigFinder et al.
041: **/
042: public final class Configuration {
043:
044: public static final char SEP_CHAR = ';';
045: public static final String SEP = "" + SEP_CHAR;
046:
047: public static final String RUNTIME_PATH_PROP = "org.cougaar.runtime.path";
048: public static final String SOCIETY_PATH_PROP = "org.cougaar.society.path";
049: public static final String INSTALL_PATH_PROP = "org.cougaar.install.path";
050: public static final String CONFIG_PATH_PROP = "org.cougaar.config.path";
051: public static final String WORKSPACE_PROP = "org.cougaar.workspace";
052: public static final String CONFIG_PROP = "org.cougaar.config";
053: public static final String USER_HOME_PROP = "user.home";
054: public static final String USER_DIR_PROP = "user.dir";
055:
056: public static final String DEFAULT_CONFIG_PATH = "$CWD" + SEP
057: + "$RUNTIME/configs/$CONFIG" + SEP
058: + "$RUNTIME/configs/common" + SEP
059: + "$SOCIETY/configs/$CONFIG" + SEP
060: + "$SOCIETY/configs/common" + SEP
061: + "$INSTALL/configs/$CONFIG" + SEP
062: + "$INSTALL/configs/common";
063:
064: // these are initialized at the end
065: private static Map defaultProperties;
066: private static URL installUrl;
067: private static URL configUrl;
068: private static URL workspaceUrl;
069: private static String configPath;
070:
071: /** Configuration is uninstantiable **/
072: private Configuration() {
073: }
074:
075: /** get the config path as an unmodifiable List of URL instances
076: * which describes, in order, the set of base locations searched by
077: * this instance of the ConfigFinder.
078: **/
079: public static String getConfigPath() {
080: return configPath;
081: }
082:
083: /** @return the current Cougaar Install Path **/
084: public static URL getInstallURL() {
085: return installUrl;
086: }
087:
088: /** @return the current config directory (or common, if undefined) **/
089: public static URL getConfigURL() {
090: return configUrl;
091: }
092:
093: /** @return the workspace location **/
094: public static URL getWorkspaceURL() {
095: return workspaceUrl;
096: }
097:
098: /** @return the (static) default properties **/
099: public static Map getDefaultProperties() {
100: return defaultProperties;
101: }
102:
103: /** return the index of the first non-alphanumeric, non-underbar character
104: * at or after i.
105: **/
106: private static int indexOfNonAlpha(String s, int i) {
107: int l = s.length();
108: for (int j = i; j < l; j++) {
109: char c = s.charAt(j);
110: if (!Character.isLetterOrDigit(c) && c != '_')
111: return j;
112: }
113: return -1;
114: }
115:
116: static String substituteProperties(String s, Map props) {
117: int i = s.indexOf('$');
118: if (i >= 0) {
119: int j = indexOfNonAlpha(s, i + 1);
120: String s0 = s.substring(0, i);
121: String s2 = (j < 0) ? "" : s.substring(j);
122: String k = s.substring(i + 1, (j < 0) ? s.length() : j);
123: Object o = props.get(k);
124: if (o == null) {
125: throw new IllegalArgumentException(
126: "No such path property \"" + k + "\"");
127: }
128: return substituteProperties(s0 + o.toString() + s2, props);
129: }
130: return s;
131: }
132:
133: public static final URL urlify(String s)
134: throws MalformedURLException {
135: // MalformedURLException savedx = null;
136: s = s.replace('\\', '/').replace('\\', '/'); // These should be URL-like
137: if (s.startsWith("resource://")) {
138: s = "file:/IN_COUGAAR_JARS/"
139: + s.substring("resource://".length());
140: }
141: if (!s.endsWith("/"))
142: s += "/";
143: if (s.indexOf(":/") >= 0) {
144: if (s.charAt(0) == '/' && s.matches("^/\\w{3,}:/.*$")) {
145: // remove the leading (erroneous) "/" character.
146: //
147: // The File constructor does this automatically:
148: // "//foo/" --> "/foo/"
149: // so we want similar support for URLs:
150: // "/file:/foo/" --> "file:/foo/"
151: // Without this fix, we'd get:
152: // "/file:/foo/" --> "file:/file:/foo/"
153: s = s.substring(1);
154: }
155: try {
156: return new URL(s);
157: } catch (MalformedURLException mue) {
158: // savedx = mue;
159: }
160: }
161:
162: try {
163: return filenameToURL(s);
164: } catch (MalformedURLException mue) {
165: // would be nice to use savedx, too
166: throw new MalformedURLException("Could not convert \"" + s
167: + "\" to a URL");
168: }
169: }
170:
171: private static final String getCanonicalPath(String s) {
172: File f = new File(s);
173: try {
174: f = f.getCanonicalFile();
175: } catch (IOException ioe) {
176: // okay
177: } catch (AccessControlException ace) {
178: String msg = ace.getMessage();
179: if (msg != null
180: && msg
181: .equals("access denied (java.util.PropertyPermission user.dir read)")) {
182: // okay, must be in sandbox
183: //
184: // Usually we'd return f, but for some reason the file wrapper
185: // turns "http://x" into "http:/x", which is broken.
186: return s;
187: } else {
188: throw new RuntimeException("Security exception", ace);
189: }
190: }
191: return f.toString();
192: }
193:
194: private static final URL filenameToURL(String s)
195: throws MalformedURLException {
196: try {
197: File f = new File(s);
198: return f.getCanonicalFile().toURL();
199: } catch (Exception e) {
200: throw new MalformedURLException(
201: "Cannot convert string to file URL " + s);
202: }
203: }
204:
205: /** Utility method for resolving filename or url-like path elements to URLs.
206: * These are to be interpreted as filenames, never directories.
207: * additionally interprets the url as relative to COUGAAR_INSTALL_PATH if it resolves
208: * as a relative URL.
209: * @note Since this method is static, only the static defaultProperties are used.
210: **/
211: public final static URL canonicalizeElement(String el)
212: throws MalformedURLException {
213: String rs = substituteProperties(el, defaultProperties);
214: try {
215: return new URL(installUrl, rs);
216: } catch (MalformedURLException mue) {
217: }
218: return filenameToURL(rs);
219: }
220:
221: /** resolve Configuration variables (default ones only) in the argument
222: * string. For example, convert "$INSTALL/foo.txt" to "/opt/cougaar/030330/foo.txt"
223: **/
224: public final static String resolveValue(String el) {
225: return substituteProperties(el, defaultProperties);
226: }
227:
228: static {
229: Map m = new HashMap();
230:
231: String runtime_path = SystemProperties
232: .getProperty(RUNTIME_PATH_PROP);
233: if (runtime_path != null && runtime_path.length() > 0) {
234: runtime_path = getCanonicalPath(runtime_path);
235: m.put("RUNTIME", runtime_path);
236: m.put("CRP", runtime_path); // alias for RUNTIME
237: m.put("COUGAAR_RUNTIME_PATH", runtime_path); // for completeness
238: }
239:
240: String society_path = SystemProperties
241: .getProperty(SOCIETY_PATH_PROP);
242: if (society_path != null && society_path.length() > 0) {
243: society_path = getCanonicalPath(society_path);
244: m.put("SOCIETY", society_path);
245: m.put("CSP", society_path); // alias for SOCIETY
246: m.put("COUGAAR_SOCIETY_PATH", society_path); // for completeness
247: }
248:
249: String install_path = SystemProperties
250: .getProperty(INSTALL_PATH_PROP);
251: if (install_path != null && install_path.length() > 0) {
252: install_path = getCanonicalPath(install_path);
253: m.put("INSTALL", install_path);
254: m.put("CIP", install_path); // alias for INSTALL
255: m.put("COUGAAR_INSTALL_PATH", install_path); // for completeness
256: try {
257: installUrl = urlify(install_path);
258: } catch (MalformedURLException e) {
259: e.printStackTrace();
260: }
261: }
262:
263: String workspace = SystemProperties.getProperty(WORKSPACE_PROP);
264: if (workspace == null || workspace.length() <= 0) {
265: for (int i = 0; i < 3; i++) {
266: String key = (i == 0 ? "RUNTIME" : i == 1 ? "SOCIETY"
267: : "INSTALL");
268: String base = (String) m.get(key);
269: if (base != null) {
270: workspace = base + "/workspace";
271: break;
272: }
273: }
274: }
275: if (workspace != null) {
276: m.put("WORKSPACE", workspace);
277: try {
278: workspaceUrl = urlify(workspace);
279: } catch (MalformedURLException e) {
280: e.printStackTrace();
281: }
282: }
283:
284: m.put("HOME", SystemProperties.getProperty(USER_HOME_PROP));
285: m.put("CWD", SystemProperties.getProperty(USER_DIR_PROP));
286:
287: String configs_path = null;
288: for (int i = 0; i < 3; i++) {
289: String key = (i == 0 ? "RUNTIME" : i == 1 ? "SOCIETY"
290: : "INSTALL");
291: String base = (String) m.get(key);
292: if (base != null) {
293: configs_path = base + "/configs";
294: break;
295: }
296: }
297: if (configs_path != null) {
298: configs_path = getCanonicalPath(configs_path);
299: m.put("CONFIGS", configs_path);
300: try {
301: configUrl = urlify(configs_path);
302: } catch (MalformedURLException e) {
303: e.printStackTrace();
304: }
305: }
306:
307: m.put("CONFIG", SystemProperties.getProperty(CONFIG_PROP,
308: "common"));
309:
310: defaultProperties = Collections.unmodifiableMap(m);
311:
312: String config_path = SystemProperties
313: .getProperty(CONFIG_PATH_PROP);
314: if (config_path != null && config_path.length() > 0
315: && config_path.charAt(0) == '"'
316: && config_path.charAt(config_path.length() - 1) == '"') {
317: config_path = config_path.substring(1,
318: config_path.length() - 1);
319: }
320: boolean append_default = false;
321: if (config_path == null) {
322: config_path = "";
323: append_default = true;
324: } else if (config_path.length() > 0) {
325: config_path = config_path.replace('\\', '/'); // Make sure its a URL and not a file path
326: append_default = config_path.endsWith(SEP);
327: }
328: if (append_default) {
329: // append default path, but only path elements that contain known keys.
330: //
331: // For example, ignore "$RUNTIME/configs/common" if "$RUNTIME" is not set.
332: String[] sa = DEFAULT_CONFIG_PATH.split("\\s*" + SEP
333: + "\\s*");
334: boolean needs_sep = false;
335: loop: for (int i = 0; i < sa.length; i++) {
336: String path = sa[i].trim();
337: if (path.length() <= 0) {
338: continue;
339: }
340: String[] sai = path.split("/");
341: for (int j = 0; j < sai.length; j++) {
342: String sj = sai[j];
343: if (sj.length() > 0 && sj.charAt(0) == '$') {
344: String key = sj.substring(1);
345: if (!defaultProperties.containsKey(key)) {
346: continue loop;
347: }
348: }
349: }
350: if (needs_sep) {
351: config_path += SEP;
352: } else {
353: needs_sep = true;
354: }
355: config_path += path;
356: }
357: }
358:
359: configPath = config_path;
360: }
361: }
|