JiveGlobals.java 28.1 KB
Newer Older
Matt Tucker's avatar
Matt Tucker committed
1 2 3 4 5
/**
 * $RCSfile$
 * $Revision$
 * $Date$
 *
Matt Tucker's avatar
Matt Tucker committed
6
 * Copyright (C) 2004 Jive Software. All rights reserved.
Matt Tucker's avatar
Matt Tucker committed
7
 *
Matt Tucker's avatar
Matt Tucker committed
8 9
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution.
Matt Tucker's avatar
Matt Tucker committed
10 11
 */

12
package org.jivesoftware.util;
Matt Tucker's avatar
Matt Tucker committed
13

14 15
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
16

17
import javax.naming.InitialContext;
Matt Tucker's avatar
Matt Tucker committed
18 19 20 21
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
22 23
import java.util.*;

Matt Tucker's avatar
Matt Tucker committed
24
/**
Matt Tucker's avatar
Matt Tucker committed
25 26
 * Controls Jive properties. Jive properties are only meant to be set and retrieved
 * by core Jive classes.
Matt Tucker's avatar
Matt Tucker committed
27
 * <p/>
28
 * The location of the home directory should be specified one of
Matt Tucker's avatar
Matt Tucker committed
29 30
 * three ways:
 * <ol>
31 32
 * <li>Set a Java system property named <tt>home</tt> with the full path to your
 * home directory.
Matt Tucker's avatar
Matt Tucker committed
33
 * <li>Indicate its value in the <tt>messenger_init.xml</tt> file. This
Matt Tucker's avatar
Matt Tucker committed
34
 * is a simple xml file that should look something like:<br>
35
 * <tt><home>c:\JiveMessenger</home></tt> (Windows) <br>
Matt Tucker's avatar
Matt Tucker committed
36
 * or <br>
37
 * <tt><home>/var/JiveMessenger</home></tt> (Unix) <p>
Matt Tucker's avatar
Matt Tucker committed
38 39
 * <p/>
 * The file must be in your classpath so that it can be loaded by Java's classloader.
40
 * <li>Use another class in your VM to set the <tt>JiveGlobals.home</tt> variable.
Matt Tucker's avatar
Matt Tucker committed
41 42 43 44
 * This must be done before the rest of Jive starts up, for example: in a servlet that
 * is set to run as soon as the appserver starts up.
 * </ol>
 * <p/>
Matt Tucker's avatar
Matt Tucker committed
45
 * All property names must be in the form <code>prop.name</code> - parts of the name must
Matt Tucker's avatar
Matt Tucker committed
46 47 48 49
 * be seperated by ".". The value can be any valid String, including strings with line breaks.
 */
public class JiveGlobals {

50
    private static String JIVE_CONFIG_FILENAME = null;
51

Matt Tucker's avatar
Matt Tucker committed
52 53 54 55
    /**
     * Location of the jiveHome directory. All configuration files should be
     * located here.
     */
56
    public static String home = null;
Matt Tucker's avatar
Matt Tucker committed
57 58 59

    public static boolean failedLoading = false;

60 61
    private static XMLProperties xmlProperties = null;
    private static JiveProperties properties = null;
Matt Tucker's avatar
Matt Tucker committed
62 63 64 65 66

    private static Locale locale = null;
    private static TimeZone timeZone = null;
    private static DateFormat dateFormat = null;
    private static DateFormat dateTimeFormat = null;
67
    private static DateFormat timeFormat = null;
Matt Tucker's avatar
Matt Tucker committed
68 69 70 71 72 73 74 75 76 77

    /**
     * Returns the global Locale used by Jive. A locale specifies language
     * and country codes, and is used for internationalization. The default
     * locale is system dependant - Locale.getDefault().
     *
     * @return the global locale used by Jive.
     */
    public static Locale getLocale() {
        if (locale == null) {
Matt Tucker's avatar
Matt Tucker committed
78
            if (xmlProperties != null) {
79 80 81 82 83 84 85 86
                String [] localeArray;
                String localeProperty = (String) xmlProperties.getProperty("locale");
                if (localeProperty != null) {
                    localeArray = localeProperty.split("_");
                }
                else {
                    localeArray = new String[] {"", ""};
                }
Matt Tucker's avatar
Matt Tucker committed
87 88

                String language = localeArray[0];
89 90 91
                if (language == null) {
                    language = "";
                }
Matt Tucker's avatar
Matt Tucker committed
92 93 94
                String country = "";
                if (localeArray.length == 2) {
                    country = localeArray[1];
95 96 97 98 99 100 101 102 103 104 105 106
                }
                // If no locale info is specified, return the system default Locale.
                if (language.equals("") && country.equals("")) {
                    locale = Locale.getDefault();
                }
                else {
                    locale = new Locale(language, country);
                }
            }
            else {
                return Locale.getDefault();
            }
Matt Tucker's avatar
Matt Tucker committed
107
        }
108
        return locale;
Matt Tucker's avatar
Matt Tucker committed
109 110 111 112 113 114 115 116 117 118 119 120
    }

    /**
     * Sets the global locale used by Jive. A locale specifies language
     * and country codes, and is used for formatting dates and numbers.
     * The default locale is Locale.US.
     *
     * @param newLocale the global Locale for Jive.
     */
    public static void setLocale(Locale newLocale) {
        locale = newLocale;
        // Save values to Jive properties.
Matt Tucker's avatar
Matt Tucker committed
121 122
        setXMLProperty("locale", locale.toString());

Matt Tucker's avatar
Matt Tucker committed
123
        // Reset the date formatter objects
124
        timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT, locale);
Matt Tucker's avatar
Matt Tucker committed
125 126 127
        dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
        dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
                DateFormat.MEDIUM, locale);
128
        timeFormat.setTimeZone(timeZone);
Matt Tucker's avatar
Matt Tucker committed
129 130 131 132 133 134 135 136 137 138 139
        dateFormat.setTimeZone(timeZone);
        dateTimeFormat.setTimeZone(timeZone);
    }

    /**
     * Returns the global TimeZone used by Jive. The default is the VM's
     * default time zone.
     *
     * @return the global time zone used by Jive.
     */
    public static TimeZone getTimeZone() {
140 141 142 143 144 145 146 147 148 149 150 151 152
        if (timeZone == null) {
            if (properties != null) {
                String timeZoneID = (String)properties.get("locale.timeZone");
                if (timeZoneID == null) {
                    timeZone = TimeZone.getDefault();
                }
                else {
                    timeZone = TimeZone.getTimeZone(timeZoneID);
                }
            }
            else {
                return TimeZone.getDefault();
            }
Matt Tucker's avatar
Matt Tucker committed
153 154 155 156 157 158 159 160 161 162
        }
        return timeZone;
    }

    /**
     * Sets the global time zone used by Jive. The default time zone is the VM's
     * time zone.
     */
    public static void setTimeZone(TimeZone newTimeZone) {
        timeZone = newTimeZone;
163
        timeFormat.setTimeZone(timeZone);
Matt Tucker's avatar
Matt Tucker committed
164 165
        dateFormat.setTimeZone(timeZone);
        dateTimeFormat.setTimeZone(timeZone);
166
        setProperty("locale.timeZone", timeZone.getID());
Matt Tucker's avatar
Matt Tucker committed
167 168
    }

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    /**
     * Formats a Date object to return a time using the global locale.
     *
     * @param date the Date to format.
     * @return a String representing the time.
     */
    public static String formatTime(Date date) {
        if (timeFormat == null) {
            if (properties != null) {
                timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT, getLocale());
                timeFormat.setTimeZone(getTimeZone());
            }
            else {
                DateFormat instance = DateFormat.getTimeInstance(DateFormat.SHORT, getLocale());
                instance.setTimeZone(getTimeZone());
                return instance.format(date);
            }
        }
        return timeFormat.format(date);
    }

Matt Tucker's avatar
Matt Tucker committed
190 191 192 193 194 195 196
    /**
     * Formats a Date object to return a date using the global locale.
     *
     * @param date the Date to format.
     * @return a String representing the date.
     */
    public static String formatDate(Date date) {
197 198 199 200 201 202 203 204 205 206
        if (dateFormat == null) {
            if (properties != null) {
                dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale());
                dateFormat.setTimeZone(getTimeZone());
            }
            else {
                DateFormat instance = DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale());
                instance.setTimeZone(getTimeZone());
                return instance.format(date);
            }
Matt Tucker's avatar
Matt Tucker committed
207 208 209 210 211 212 213 214 215 216 217
        }
        return dateFormat.format(date);
    }

    /**
     * Formats a Date object to return a date and time using the global locale.
     *
     * @param date the Date to format.
     * @return a String representing the date and time.
     */
    public static String formatDateTime(Date date) {
218 219 220 221 222 223 224 225 226 227 228 229
        if (dateTimeFormat == null) {
            if (properties != null) {
                dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
                        DateFormat.MEDIUM, getLocale());
                dateTimeFormat.setTimeZone(getTimeZone());
            }
            else {
                DateFormat instance = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
                        DateFormat.MEDIUM, getLocale());
                instance.setTimeZone(getTimeZone());
                return instance.format(date);
            }
Matt Tucker's avatar
Matt Tucker committed
230 231 232 233 234
        }
        return dateTimeFormat.format(date);
    }

    /**
235
     * Returns the location of the <code>home</code> directory.
Matt Tucker's avatar
Matt Tucker committed
236
     *
237
     * @return the location of the home dir.
Matt Tucker's avatar
Matt Tucker committed
238
     */
239 240
    public static String getHomeDirectory() {
        if (home == null) {
241
            loadSetupProperties();
Matt Tucker's avatar
Matt Tucker committed
242
        }
243
        return home;
Matt Tucker's avatar
Matt Tucker committed
244 245 246
    }

    /**
247 248
     * Returns a local property. Local properties are stored in the file defined in
     * <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt> directory.
Matt Tucker's avatar
Matt Tucker committed
249 250 251 252 253 254 255 256 257 258 259 260 261
     * Properties are always specified as "foo.bar.prop", which would map to
     * the following entry in the XML file:
     * <pre>
     * &lt;foo&gt;
     *     &lt;bar&gt;
     *         &lt;prop&gt;some value&lt;/prop&gt;
     *     &lt;/bar&gt;
     * &lt;/foo&gt;
     * </pre>
     *
     * @param name the name of the property to return.
     * @return the property value specified by name.
     */
262 263 264
    public static String getXMLProperty(String name) {
        if (xmlProperties == null) {
            loadSetupProperties();
Matt Tucker's avatar
Matt Tucker committed
265 266
        }

267
        // home not loaded?
268
        if (xmlProperties == null) {
Matt Tucker's avatar
Matt Tucker committed
269 270 271
            return null;
        }

272
        return xmlProperties.getProperty(name);
Matt Tucker's avatar
Matt Tucker committed
273 274
    }

Matt Tucker's avatar
Matt Tucker committed
275
    /**
276 277
     * Returns a local property. Local properties are stored in the file defined in
     * <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt> directory.
Matt Tucker's avatar
Matt Tucker committed
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
     * Properties are always specified as "foo.bar.prop", which would map to
     * the following entry in the XML file:
     * <pre>
     * &lt;foo&gt;
     *     &lt;bar&gt;
     *         &lt;prop&gt;some value&lt;/prop&gt;
     *     &lt;/bar&gt;
     * &lt;/foo&gt;
     * </pre>
     *
     * If the specified property can't be found, the <tt>defaultValue</tt> will be returned.
     *
     * @param name the name of the property to return.
     * @param defaultValue the default value for the property.
     * @return the property value specified by name.
     */
    public static String getXMLProperty(String name, String defaultValue) {
        if (xmlProperties == null) {
            loadSetupProperties();
        }

299
        // home not loaded?
Matt Tucker's avatar
Matt Tucker committed
300 301 302 303 304 305 306 307 308 309 310
        if (xmlProperties == null) {
            return null;
        }

        String value = xmlProperties.getProperty(name);
        if (value == null) {
            value = defaultValue;
        }
        return value;
    }

Matt Tucker's avatar
Matt Tucker committed
311
    /**
312 313
     * Returns an integer value local property. Local properties are stored in the file defined in
     * <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt> directory.
Matt Tucker's avatar
Matt Tucker committed
314 315 316 317 318 319 320 321 322 323
     * Properties are always specified as "foo.bar.prop", which would map to
     * the following entry in the XML file:
     * <pre>
     * &lt;foo&gt;
     *     &lt;bar&gt;
     *         &lt;prop&gt;some value&lt;/prop&gt;
     *     &lt;/bar&gt;
     * &lt;/foo&gt;
     * </pre>
     *
324 325 326 327 328 329 330 331 332
     * If the specified property can't be found, or if the value is not a number, the
     * <tt>defaultValue</tt> will be returned.
     *
     * @param name the name of the property to return.
     * @param defaultValue value returned if the property could not be loaded or was not
     *      a number.
     * @return the property value specified by name or <tt>defaultValue</tt>.
     */
    public static int getXMLProperty(String name, int defaultValue) {
333
        String value = getXMLProperty(name);
334 335 336 337 338 339 340 341 342 343 344
        if (value != null) {
            try {
                return Integer.parseInt(value);
            }
            catch (NumberFormatException nfe) { }
        }
        return defaultValue;
    }

    /**
     * Sets a local property. If the property doesn't already exists, a new
345 346
     * one will be created. Local properties are stored in the file defined in
     * <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt> directory.
347 348 349 350 351 352 353 354 355 356 357
     * Properties are always specified as "foo.bar.prop", which would map to
     * the following entry in the XML file:
     * <pre>
     * &lt;foo&gt;
     *     &lt;bar&gt;
     *         &lt;prop&gt;some value&lt;/prop&gt;
     *     &lt;/bar&gt;
     * &lt;/foo&gt;
     * </pre>
     *
     * @param name the name of the property being set.
Matt Tucker's avatar
Matt Tucker committed
358 359
     * @param value the value of the property being set.
     */
360 361 362
    public static void setXMLProperty(String name, String value) {
        if (xmlProperties == null) {
            loadSetupProperties();
Matt Tucker's avatar
Matt Tucker committed
363 364
        }

365 366 367
        // jiveHome not loaded?
        if (xmlProperties != null) {
            xmlProperties.setProperty(name, value);
Matt Tucker's avatar
Matt Tucker committed
368 369 370 371
        }
    }

    /**
372
     * Sets multiple local properties at once. If a property doesn't already exists, a new
373 374
     * one will be created. Local properties are stored in the file defined in
     * <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt> directory.
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
     * Properties are always specified as "foo.bar.prop", which would map to
     * the following entry in the XML file:
     * <pre>
     * &lt;foo&gt;
     *     &lt;bar&gt;
     *         &lt;prop&gt;some value&lt;/prop&gt;
     *     &lt;/bar&gt;
     * &lt;/foo&gt;
     * </pre>
     *
     * @param propertyMap a map of properties, keyed on property name.
     */
    public static void setXMLProperties(Map propertyMap) {
        if (xmlProperties == null) {
            loadSetupProperties();
        }

        if (xmlProperties != null) {
            xmlProperties.setProperties(propertyMap);
        }
    }

    /**
     * Return all immediate children property values of a parent local property as a list of strings,
     * or an empty list if there are no children. For example, given
     * the properties <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, <tt>X.Y.C</tt> and <tt>X.Y.C.D</tt>, then
     * the immediate child properties of <tt>X.Y</tt> are <tt>A</tt>, <tt>B</tt>, and
     * <tt>C</tt> (the value of <tt>C.D</tt> would not be returned using this method).<p>
     *
404 405
     * Local properties are stored in the file defined in <tt>JIVE_CONFIG_FILENAME</tt> that exists
     * in the <tt>home</tt> directory. Properties are always specified as "foo.bar.prop",
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
     * which would map to the following entry in the XML file:
     * <pre>
     * &lt;foo&gt;
     *     &lt;bar&gt;
     *         &lt;prop&gt;some value&lt;/prop&gt;
     *     &lt;/bar&gt;
     * &lt;/foo&gt;
     * </pre>
     *
     *
     * @param parent the name of the parent property to return the children for.
     * @return all child property values for the given parent.
     */
    public static List getXMLProperties(String parent) {
        if (xmlProperties == null) {
            loadSetupProperties();
        }

        // jiveHome not loaded?
        if (xmlProperties == null) {
            return Collections.EMPTY_LIST;
        }

        String[] propNames = xmlProperties.getChildrenProperties(parent);
        List values = new ArrayList();
        for (int i = 0; i < propNames.length; i++) {
            String propName = propNames[i];
            String value = getProperty(parent + "." + propName);
            if (value != null) {
                values.add(value);
            }
        }

        return values;
    }

    /**
     * Deletes a locale property. If the property doesn't exist, the method
Matt Tucker's avatar
Matt Tucker committed
444 445 446 447
     * does nothing.
     *
     * @param name the name of the property to delete.
     */
448 449 450 451 452 453
    public static void deleteXMLProperty(String name) {
        if (xmlProperties == null) {
            loadSetupProperties();
        }
        xmlProperties.deleteProperty(name);
    }
Matt Tucker's avatar
Matt Tucker committed
454

455 456 457 458 459 460 461 462
    /**
     * Returns a Jive property.
     *
     * @param name the name of the property to return.
     * @return the property value specified by name.
     */
    public static String getProperty(String name) {
        if (properties == null) {
Matt Tucker's avatar
Matt Tucker committed
463 464 465
            if (isSetupMode()) {
                return null;
            }
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
            properties = JiveProperties.getInstance();
        }
        return (String)properties.get(name);
    }

    /**
     * Returns a Jive property. If the specified property doesn't exist, the
     * <tt>defaultValue</tt> will be returned.
     *
     * @param name the name of the property to return.
     * @param defaultValue value returned if the property doesn't exist.
     * @return the property value specified by name.
     */
    public static String getProperty(String name, String defaultValue) {
        if (properties == null) {
Matt Tucker's avatar
Matt Tucker committed
481 482 483
            if (isSetupMode()) {
                return defaultValue;
            }
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
            properties = JiveProperties.getInstance();
        }
        String value = (String)properties.get(name);
        if (value != null) {
            return value;
        }
        else {
            return defaultValue;
        }
    }

    /**
     * Returns an integer value Jive property. If the specified property doesn't exist, the
     * <tt>defaultValue</tt> will be returned.
     *
     * @param name the name of the property to return.
     * @param defaultValue value returned if the property doesn't exist or was not
     *      a number.
     * @return the property value specified by name or <tt>defaultValue</tt>.
     */
    public static int getIntProperty(String name, int defaultValue) {
        String value = getProperty(name);
        if (value != null) {
            try {
                return Integer.parseInt(value);
            }
            catch (NumberFormatException nfe) { }
        }
        return defaultValue;
    }

    /**
     * Returns a boolean value Jive property.
     *
     * @param name the name of the property to return.
     * @return true if the property value exists and is set to <tt>"true"</tt> (ignoring case).
     *      Otherwise <tt>false</tt> is returned.
     */
    public static boolean getBooleanProperty(String name) {
        return Boolean.valueOf(getProperty(name)).booleanValue();
    }

    /**
     * Returns a boolean value Jive property. If the property doesn't exist, the <tt>defaultValue</tt>
     * will be returned.
     *
     * If the specified property can't be found, or if the value is not a number, the
     * <tt>defaultValue</tt> will be returned.
     *
     * @param name the name of the property to return.
     * @param defaultValue value returned if the property doesn't exist.
     * @return true if the property value exists and is set to <tt>"true"</tt> (ignoring case).
     *      Otherwise <tt>false</tt> is returned.
     */
    public static boolean getBooleanProperty(String name, boolean defaultValue) {
        String value = getProperty(name);
        if (value != null) {
            return Boolean.valueOf(getProperty(name)).booleanValue();
        }
        else {
            return defaultValue;
        }
    }

    /**
     * Return all immediate children property names of a parent Jive property as a list of strings,
     * or an empty list if there are no children. For example, given
     * the properties <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, <tt>X.Y.C</tt> and <tt>X.Y.C.D</tt>, then
     * the immediate child properties of <tt>X.Y</tt> are <tt>A</tt>, <tt>B</tt>, and
     * <tt>C</tt> (<tt>C.D</tt> would not be returned using this method).<p>
     *
     * @return a List of all immediate children property names (Strings).
     */
Matt Tucker's avatar
Matt Tucker committed
557
    public static List<String> getPropertyNames(String parent) {
558
        if (properties == null) {
Matt Tucker's avatar
Matt Tucker committed
559 560 561
            if (isSetupMode()) {
                return new ArrayList<String>();
            }
562 563
            properties = JiveProperties.getInstance();
        }
Matt Tucker's avatar
Matt Tucker committed
564
        return new ArrayList<String>(properties.getChildrenNames(parent));
565 566 567 568 569 570 571 572 573 574 575 576
    }

    /**
     * Return all immediate children property values of a parent Jive property as a list of strings,
     * or an empty list if there are no children. For example, given
     * the properties <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, <tt>X.Y.C</tt> and <tt>X.Y.C.D</tt>, then
     * the immediate child properties of <tt>X.Y</tt> are <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, and
     * <tt>X.Y.C</tt> (the value of <tt>X.Y.C.D</tt> would not be returned using this method).<p>
     *
     * @param parent the name of the parent property to return the children for.
     * @return all child property values for the given parent.
     */
577
    public static List<String> getProperties(String parent) {
Matt Tucker's avatar
Matt Tucker committed
578
        if (properties == null) {
Matt Tucker's avatar
Matt Tucker committed
579 580 581
            if (isSetupMode()) {
                return new ArrayList<String>();
            }
582 583 584
            properties = JiveProperties.getInstance();
        }

585 586
        Collection<String> propertyNames = properties.getChildrenNames(parent);
        List<String> values = new ArrayList<String>();
587 588 589 590 591 592
        for (Iterator i=propertyNames.iterator(); i.hasNext(); ) {
            String propName = (String)i.next();
            String value = getProperty(propName);
            if (value != null) {
                values.add(value);
            }
Matt Tucker's avatar
Matt Tucker committed
593
        }
594 595 596 597 598 599 600 601 602

        return values;
    }

    /**
     * Returns all Jive property names.
     *
     * @return a List of all property names (Strings).
     */
Matt Tucker's avatar
Matt Tucker committed
603
    public static List<String> getPropertyNames() {
604
        if (properties == null) {
Matt Tucker's avatar
Matt Tucker committed
605 606 607
            if (isSetupMode()) {
                return new ArrayList<String>();
            }
608
            properties = JiveProperties.getInstance();
Matt Tucker's avatar
Matt Tucker committed
609
        }
Matt Tucker's avatar
Matt Tucker committed
610
        return new ArrayList<String>(properties.getPropertyNames());
611 612 613 614 615 616 617 618 619 620 621
    }

    /**
     * Sets a Jive property. If the property doesn't already exists, a new
     * one will be created.
     *
     * @param name the name of the property being set.
     * @param value the value of the property being set.
     */
    public static void setProperty(String name, String value) {
        if (properties == null) {
Matt Tucker's avatar
Matt Tucker committed
622 623 624
            if (isSetupMode()) {
                return;
            }
625 626 627 628 629 630 631 632 633 634 635 636 637
            properties = JiveProperties.getInstance();
        }
        properties.put(name, value);
    }

   /**
     * Sets multiple Jive properties at once. If a property doesn't already exists, a new
     * one will be created.
     *
     * @param propertyMap a map of properties, keyed on property name.
     */
    public static void setProperties(Map propertyMap) {
        if (properties == null) {
Matt Tucker's avatar
Matt Tucker committed
638 639 640
            if (isSetupMode()) {
                return;
            }
641 642 643 644 645 646 647 648 649 650 651 652 653 654
            properties = JiveProperties.getInstance();
        }

        properties.putAll(propertyMap);
    }

    /**
     * Deletes a Jive property. If the property doesn't exist, the method
     * does nothing. All children of the property will be deleted as well.
     *
     * @param name the name of the property to delete.
     */
    public static void deleteProperty(String name) {
        if (properties == null) {
Matt Tucker's avatar
Matt Tucker committed
655 656 657
            if (isSetupMode()) {
                return;
            }
658 659 660 661 662 663 664
            properties = JiveProperties.getInstance();;
        }
        properties.remove(name);
    }

   /**
    * Allows the name of the local config file name to be changed. The
665
    * default is "jive-messenger.xml".
666 667 668 669 670
    *
    * @param configName the name of the config file.
    */
    public static void setConfigName(String configName) {
        JIVE_CONFIG_FILENAME = configName;
Matt Tucker's avatar
Matt Tucker committed
671 672
    }

673 674 675 676 677
    /**
     * Returns the name of the local config file name.
     *
     * @return the name of the config file.
     */
678 679 680 681
    static String getConfigName() {
        if (JIVE_CONFIG_FILENAME == null) {
            JIVE_CONFIG_FILENAME = "jive-messenger.xml";
        };
682
        return JIVE_CONFIG_FILENAME;
683
    }
684

Matt Tucker's avatar
Matt Tucker committed
685 686 687 688 689 690 691 692 693
    /**
     * Returns true if in setup mode.
     *
     * @return true if in setup mode.
     */
    private static boolean isSetupMode() {
        return !(Boolean.valueOf(JiveGlobals.getXMLProperty("setup")).booleanValue());
    }

Matt Tucker's avatar
Matt Tucker committed
694 695
    /**
     * Loads properties if necessary. Property loading must be done lazily so
696
     * that we give outside classes a chance to set <tt>home</tt>.
Matt Tucker's avatar
Matt Tucker committed
697
     */
698
    private synchronized static void loadSetupProperties() {
Matt Tucker's avatar
Matt Tucker committed
699 700 701
        if (failedLoading) {
            return;
        }
702 703 704 705
        if (xmlProperties == null) {
            // If jiveHome is still null, no outside process has set it and
            // we have to attempt to load the value from jive_init.xml,
            // which must be in the classpath.
706 707
            if (home == null) {
                home = new InitPropLoader().getHome();
Matt Tucker's avatar
Matt Tucker committed
708
            }
709
            // If that failed, try loading it from JNDI
710
            if (home == null) {
Matt Tucker's avatar
Matt Tucker committed
711
                try {
712
                    InitialContext context = new InitialContext();
713
                    home = (String)context.lookup("java:comp/env/home");
Matt Tucker's avatar
Matt Tucker committed
714
                }
715
                catch (Exception e) { }
Matt Tucker's avatar
Matt Tucker committed
716
            }
717
            // Finally, try to load it jiveHome as a system property.
718 719
            if (home == null) {
                home = System.getProperty("home");
Matt Tucker's avatar
Matt Tucker committed
720
            }
721

722
            if(home == null){
723
                try {
724 725 726
                    home = new File("..").getCanonicalPath();
                    if(!new File(home, "conf/" + getConfigName()).exists()){
                        home = null;
727 728 729 730 731 732 733
                    }
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }

734
             if(home == null){
735
                try {
736 737 738
                    home = new File("").getCanonicalPath();
                    if(!new File(home, "conf/" + getConfigName()).exists()){
                        home = null;
739 740 741 742 743 744 745
                    }
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }

746 747
            // If still null, finding home failed.
            if (home == null) {
Matt Tucker's avatar
Matt Tucker committed
748
                failedLoading = true;
749
                StringBuilder msg = new StringBuilder();
750
                msg.append("Critical Error! The home directory could not be loaded, \n");
751
                msg.append("which will prevent the application from working correctly.\n\n");
752
                msg.append("You must set home in one of four ways:\n");
753 754
                msg.append("    1) Add a messenger_init.xml file to your classpath, which points \n ");
                msg.append("       to home.\n");
755 756 757 758
                msg.append("    3) Set the JNDI value \"java:comp/env/home\" with a String \n");
                msg.append("       that points to your home directory. \n");
                msg.append("    4) Set the Java system property \"home\".\n\n");
                msg.append("Further instructions for setting home can be found in the \n");
759 760
                msg.append("installation documentation.");
                System.err.println(msg.toString());
Matt Tucker's avatar
Matt Tucker committed
761 762
                return;
            }
763 764 765
            // Create a manager with the full path to the xml config file.
            try {
                // Do a permission check on the jiveHome directory:
766
                File mh = new File(home);
Matt Tucker's avatar
Matt Tucker committed
767
                if (!mh.exists()) {
768
                    Log.error("Error - the specified home directory does not exist (" + home + ")");
Matt Tucker's avatar
Matt Tucker committed
769
                }
770
                else {
Matt Tucker's avatar
Matt Tucker committed
771
                    if (!mh.canRead() || !mh.canWrite()) {
772 773 774
                        Log.error("Error - the user running this application can not read " +
                                "and write to the specified home directory (" + home + "). " +
                                "Please grant the executing user read and write permissions.");
775
                    }
Matt Tucker's avatar
Matt Tucker committed
776
                }
777 778
                xmlProperties = new XMLProperties(home + File.separator + "conf" +
                        File.separator + getConfigName());
Matt Tucker's avatar
Matt Tucker committed
779
            }
780 781 782 783
            catch (IOException ioe) {
                Log.error(ioe);
                failedLoading = true;
                return;
Matt Tucker's avatar
Matt Tucker committed
784 785 786 787 788 789
            }
        }
    }
}

/**
790
 * A very small class to load the file defined in JiveGlobals.JIVE_CONFIG_FILENAME. The class is
Matt Tucker's avatar
Matt Tucker committed
791 792 793 794 795
 * needed since loading files from the classpath in a static context often
 * fails.
 */
class InitPropLoader {

796 797
    public String getHome() {
        String home = null;
Matt Tucker's avatar
Matt Tucker committed
798 799
        InputStream in = null;
        try {
800
            in = getClass().getResourceAsStream("/messenger_init.xml");
Matt Tucker's avatar
Matt Tucker committed
801
            if (in != null) {
Matt Tucker's avatar
Matt Tucker committed
802 803
                SAXReader reader = new SAXReader();
                Document doc = reader.read(in);
804
                home = doc.getRootElement().getText();
Matt Tucker's avatar
Matt Tucker committed
805 806 807
            }
        }
        catch (Exception e) {
808
            Log.error("Error loading messenger_init.xml to find home.", e);
Matt Tucker's avatar
Matt Tucker committed
809 810
        }
        finally {
Matt Tucker's avatar
Matt Tucker committed
811 812
            try { if (in != null) { in.close(); } }
            catch (Exception e) { }
Matt Tucker's avatar
Matt Tucker committed
813
        }
814 815
        if (home != null) {
            home = home.trim();
Matt Tucker's avatar
Matt Tucker committed
816
            // Remove trailing slashes.
817 818
            while (home.endsWith("/") || home.endsWith("\\")) {
                home = home.substring(0, home.length() - 1);
Matt Tucker's avatar
Matt Tucker committed
819 820
            }
        }
821 822
        if ("".equals(home)) {
            home = null;
Matt Tucker's avatar
Matt Tucker committed
823
        }
824
        return home;
Matt Tucker's avatar
Matt Tucker committed
825
    }
826
}