openlr.mapviewer.properties.MapViewerProperties.java Source code

Java tutorial

Introduction

Here is the source code for openlr.mapviewer.properties.MapViewerProperties.java

Source

/**
* Licensed to the TomTom International B.V. under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  TomTom International B.V.
* licenses this file to you under the Apache License, 
* Version 2.0 (the "License"); you may not use this file except 
* in compliance with the License.  You may obtain a copy of the License at
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/**
 *  Copyright (C) 2009-2012 TomTom International B.V.
 *
 *   TomTom (Legal Department)
 *   Email: legal@tomtom.com
 *
 *   TomTom (Technical contact)
 *   Email: openlr@tomtom.com
 *
 *   Address: TomTom International B.V., Oosterdoksstraat 114, 1011DK Amsterdam,
 *   the Netherlands
 */
package openlr.mapviewer.properties;

import java.awt.Color;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Properties;
import java.util.WeakHashMap;

import openlr.map.FormOfWay;
import openlr.map.FunctionalRoadClass;
import openlr.mapviewer.gui.layer.DefaultColors;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.log4j.Logger;

/**
 * The Class MapViewerProperties.
 * 
 * <p>
 * OpenLR is a trade mark of TomTom International B.V.
 * <p>
 * email: software@openlr.org
 * 
 * @author TomTom International B.V.
 */
public class MapViewerProperties extends Properties {

    /**
     * The base defining hex number format.
     */
    private static final int RADIX_HEX = 16;

    /**
     * The file the user specific settings are stored.
     */
    private static final String USER_PROPERTIES_FILE = ".mapviewer";

    /**
     * A list of observers interested in changes to properties. It uses weak
     * references because this list shouldn't be to blame for remaining
     * references in the memory if observers are volatile objects.
     */
    private WeakHashMap<MapViewerPropertiesObserver, MapViewerPropertiesObserver> observers = new WeakHashMap<MapViewerPropertiesObserver, MapViewerPropertiesObserver>();

    /** The Constant COLOR_STORAGE. */
    private static final HashMap<String, Color> COLOR_STORAGE = new HashMap<String, Color>();

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = -8077795903835854942L;

    /** The user specific settings that overlay the system properties. */
    private Properties userProperties = new Properties();

    /** The logger. */
    private static final Logger LOG = Logger.getLogger(MapViewerProperties.class);

    /**
     * Creates
     */
    public MapViewerProperties() {
        try {
            Properties userProps = loadUserProperties();
            if (userProps != null) {
                userProperties = userProps;
            }
        } catch (IOException e) {
            LOG.error("Error loading the user specific properties!", e);
        }
    }

    /**
     * Resolve color.
     * 
     * @param v
     *            the v
     * @return the color
     */
    private Color resolveColor(final String v) {
        if (COLOR_STORAGE.containsKey(v)) {
            return COLOR_STORAGE.get(v);
        }
        Color c = null;
        try {
            int rgbVal = 0;
            if (v.startsWith("#")) {
                rgbVal = Integer.parseInt(v.substring(1), RADIX_HEX);
            } else {
                rgbVal = Integer.parseInt(v);
            }
            c = new Color(rgbVal);
        } catch (NumberFormatException nfe) {
            System.err.println("Properties file contains invalid color code!");
        }
        if (c != null) {
            COLOR_STORAGE.put(v, c);
        }
        return c;
    }

    /**
     * Gets the color.
     * 
     * @param defaultColor
     *            the default color
     * @param key
     *            the key
     * @return the color
     */
    private Color getColor(final Color defaultColor, final String key) {
        Color c = defaultColor;
        String value = getProperty(key);
        if (value != null) {
            Color rc = resolveColor(value);
            if (rc != null) {
                c = rc;
            }
        }
        return c;
    }

    /**
     * Delivers the value of the specified key respecting user setting that
     * overly the system settings.
     * 
     * @param key
     *            The property key.
     * @param defaultValue
     *            The default value that shall be returned if no property with
     *            the given key was found.
     * @return The value string assigned to the property key.
     */
    @Override
    public final String getProperty(final String key, final String defaultValue) {

        String result = getProperty(key);

        if (result == null) {
            result = defaultValue;
        }

        return result;
    }

    /**
     * Delivers the value for the given well-known MapViewer property
     * 
     * @param prop
     *            The property
     * @return The value string assigned to the property key.
     */
    public final String getProperty(final MapViewerProperty prop) {
        return getProperty(prop.key());
    }

    /**
     * Delivers the value of the specified key respecting user setting that
     * overly the system settings.
     * 
     * @param key
     *            The property key.
     * @return The value string assigned to the property key.
     */
    @Override
    public final String getProperty(final String key) {

        String result = null;
        if (userProperties != null) {
            String userValue = userProperties.getProperty(key);
            if (userValue != null) {
                result = userValue;
            }
        }
        if (result == null) {
            result = super.getProperty(key);
        }

        return result;
    }

    /**
     * Convenience method that sets a color property value from the given
     * {@link Color} object.
     * 
     * @param key
     *            The property key.
     * @param value
     *            The color value for this property.
     */
    public final void setColorProperty(final String key, final Color value) {
        String rgb = Integer.toHexString(value.getRGB());
        rgb = rgb.substring(2, rgb.length());
        setProperty(key, "#" + rgb);
    }

    /**
     * Convenience method that delivers a {@link Color} object for the specified
     * color property.
     * 
     * @param key
     *            The property key.
     * @return The {@link Color} object created the from the property value.
     */
    public final Color getColorProperty(final String key) {
        return getColor(null, key);
    }

    /**
     * Gets the line color.
     * 
     * @return the line color
     */
    public final Color getLineColor() {
        return getColor(DefaultColors.DEFAULT_LINE_COLOR, MapDrawingProperties.LINE.key());
    }

    /**
     * Gets the map pane scale color.
     * 
     * @return the map pane scale color
     */
    public final Color getMapPaneScaleColor() {
        return getColor(DefaultColors.SCALE_COLOR, MapDrawingProperties.MAPPANE_SCALE.key());
    }

    /**
     * Gets the map pane measure color.
     * 
     * @return the map pane measure color
     */
    public final Color getMapPaneMeasureColor() {
        return getColor(DefaultColors.SCALE_COLOR, MapDrawingProperties.MAPPANE_MEASURE.key());
    }

    /**
     * Gets the selected location color.
     * 
     * @return the selected location color
     */
    public final Color getSelectedLocationColor() {
        return getColor(DefaultColors.SELECTED_LOCATION, MapDrawingProperties.LOCATION_SELECTED.key());
    }

    /**
     * Gets the search color.
     * 
     * @return the search color
     */
    public final Color getSearchColor() {
        return getColor(DefaultColors.SEARCH_COLOR, MapDrawingProperties.SEARCH_RESULT.key());
    }

    /**
     * Gets the line start node color.
     * 
     * @return the line start node color
     */
    public final Color getLineStartNodeColor() {
        return getColor(DefaultColors.START_NODE_COLOR, MapDrawingProperties.LINE_START_NODE.key());
    }

    /**
     * Gets the nodes color.
     * 
     * @return the nodes color
     */
    public final Color getNodeColor() {
        return getColor(DefaultColors.NODE_COLOR, MapDrawingProperties.NODE.key());
    }

    /**
     * Gets the location start node color.
     * 
     * @return the location start node color
     */
    public final Color getLocationStartNodeColor() {
        return getColor(DefaultColors.LOC_START_NODE_COLOR, MapDrawingProperties.LOCATION_START_NODE.key());
    }

    /**
     * Gets the location geo coord color.
     * 
     * @return the location geo coord color
     */
    public final Color getLocationGeoCoordColor() {
        return getColor(DefaultColors.LOC_GEO_COORD_COLOR, MapDrawingProperties.LOCATION_GEO_COORD.key());
    }

    /**
     * Gets the pos off color.
     * 
     * @return the pos off color
     */
    public final Color getPosOffColor() {
        return getColor(DefaultColors.LOC_POS_OFF_COLOR, MapDrawingProperties.LOCATION_POS_OFF.key());
    }

    /**
     * Gets the neg off color.
     * 
     * @return the neg off color
     */
    public final Color getNegOffColor() {
        return getColor(DefaultColors.LOC_NEG_OFF_COLOR, MapDrawingProperties.LOCATION_NEG_OFF.key());
    }

    /**
     * Gets the highlighted line color.
     * 
     * @return the highlighted line color
     */
    public final Color getHighlightedLineColor() {
        return getColor(DefaultColors.HIGHLIGHT_LINE_COLOR, MapDrawingProperties.HIGHLIGHTED_LINE.key());
    }

    /**
     * Gets the locations all color.
     * 
     * @return the locations all color
     */
    public final Color getLocationsAllColor() {
        return getColor(DefaultColors.ALL_LOCATIONS_COLOR, MapDrawingProperties.LOCATIONS_ALL.key());
    }

    /**
     * Gets the location encoder color.
     * 
     * @return the location encoder color
     */
    public final Color getLocationEncoderColor() {
        return getColor(DefaultColors.ENCODER_LOCATION_COLOR, MapDrawingProperties.LOCATION_ENCODER.key());
    }

    /**
     * Gets the location decoder color.
     * 
     * @return the location decoder color
     */
    public final Color getLocationDecoderColor() {
        return getColor(DefaultColors.DECODER_LOCATION_COLOR, MapDrawingProperties.LOCATION_DECODER.key());
    }

    /**
     * Gets the location stored color.
     * 
     * @return the location stored color
     */
    public final Color getLocationStoredColor() {
        return getColor(DefaultColors.STORED_LOCATION_COLOR, MapDrawingProperties.LOCATION_STORED.key());
    }

    /**
     * 
     * Gets the area location covered lines color.
     * 
     * @return the area location covered lines color
     */
    public final Color getAreaLocationCoveredLinesColor() {
        return getColor(DefaultColors.COVERED_LINE_AREA_LOCATION_COLOR,
                MapDrawingProperties.AREA_LOCATION_COVERED_LINE.key());
    }

    /**
     * 
     * Gets the area location intersected lines color.
     * 
     * @return the area location intersected lines color
     */
    public final Color getAreaLocationIntersectedLinesColor() {
        return getColor(DefaultColors.INTERSECTED_LINE_AREA_LOCATION_COLOR,
                MapDrawingProperties.AREA_LOCATION_INTERSECTED_LINE.key());
    }

    /**
     * Gets the point mark size.
     * 
     * @return the point mark size
     */
    public final int getPointMarkSize() {
        int size = 4;//Styles.POINT_MARK_SIZE;
        String s = getProperty("size.mark.point");
        if (s != null) {
            try {
                size = Integer.parseInt(s);
            } catch (NumberFormatException nfe) {
                System.err.println("Invalid number format in properties file [size.mark.point]");
            }
        }
        return size;
    }

    /**
     * Gets the node mark size.
     * 
     * @return the node mark size
     */
    public final int getNodeMarkSize() {
        int size = 5;
        String s = getProperty("size.mark.node");
        if (s != null) {
            try {
                size = Integer.parseInt(s);
            } catch (NumberFormatException nfe) {
                System.err.println("Invalid number format in properties file [size.mark.node]");
            }
        }
        return size;
    }

    /**
     * Gets the line stroke size.
     *
     * @return the line stroke size
     */
    public final int getLineStrokeSize() {
        int size = 1;
        String s = getProperty("size.stroke.line");
        if (s != null) {
            try {
                size = Integer.parseInt(s);
            } catch (NumberFormatException nfe) {
                System.err.println("Invalid number format in properties file [size.stroke.line]");
            }
        }
        return size;
    }

    /**
     * Gets the node stroke size.
     * 
     * @return the node stroke size
     */
    public final int getNodeStrokeSize() {
        int size = 5;
        String s = getProperty("size.stroke.node");
        if (s != null) {
            try {
                size = Integer.parseInt(s);
            } catch (NumberFormatException nfe) {
                System.err.println("Invalid number format in properties file [size.stroke.node]");
            }
        }
        return size;
    }

    /**
     * Gets the fR c0 color.
     * 
     * @return the fR c0 color
     */
    public final Color getFRC0Color() {
        return getColor(DefaultColors.FRCColors.FRC0.getColor(), MapDrawingProperties.FRC_FRC0.key());
    }

    /**
     * Gets the fR c1 color.
     * 
     * @return the fR c1 color
     */
    public final Color getFRC1Color() {
        return getColor(DefaultColors.FRCColors.FRC1.getColor(), MapDrawingProperties.FRC_FRC1.key());
    }

    /**
     * Gets the fR c2 color.
     * 
     * @return the fR c2 color
     */
    public final Color getFRC2Color() {
        return getColor(DefaultColors.FRCColors.FRC2.getColor(), MapDrawingProperties.FRC_FRC2.key());
    }

    /**
     * Gets the fR c3 color.
     * 
     * @return the fR c3 color
     */
    public final Color getFRC3Color() {
        return getColor(DefaultColors.FRCColors.FRC3.getColor(), MapDrawingProperties.FRC_FRC3.key());
    }

    /**
     * Gets the fR c4 color.
     * 
     * @return the fR c4 color
     */
    public final Color getFRC4Color() {
        return getColor(DefaultColors.FRCColors.FRC4.getColor(), MapDrawingProperties.FRC_FRC4.key());
    }

    /**
     * Gets the fR c5 color.
     * 
     * @return the fR c5 color
     */
    public final Color getFRC5Color() {
        return getColor(DefaultColors.FRCColors.FRC5.getColor(), MapDrawingProperties.FRC_FRC5.key());
    }

    /**
     * Gets the fR c6 color.
     * 
     * @return the fR c6 color
     */
    public final Color getFRC6Color() {
        return getColor(DefaultColors.FRCColors.FRC6.getColor(), MapDrawingProperties.FRC_FRC6.key());
    }

    /**
     * Gets the fR c7 color.
     * 
     * @return the fR c7 color
     */
    public final Color getFRC7Color() {
        return getColor(DefaultColors.FRCColors.FRC7.getColor(), MapDrawingProperties.FRC_FRC7.key());
    }

    /**
     * Gets the frc color.
     * 
     * @param idx
     *            the idx
     * @return the frc color
     */
    public final String getFrcColorProperty(final int idx) {
        if (idx == FunctionalRoadClass.FRC_0.getID()) {
            return MapDrawingProperties.FRC_FRC0.key();
        } else if (idx == FunctionalRoadClass.FRC_1.getID()) {
            return MapDrawingProperties.FRC_FRC1.key();
        } else if (idx == FunctionalRoadClass.FRC_2.getID()) {
            return MapDrawingProperties.FRC_FRC2.key();
        } else if (idx == FunctionalRoadClass.FRC_3.getID()) {
            return MapDrawingProperties.FRC_FRC3.key();
        } else if (idx == FunctionalRoadClass.FRC_4.getID()) {
            return MapDrawingProperties.FRC_FRC4.key();
        } else if (idx == FunctionalRoadClass.FRC_5.getID()) {
            return MapDrawingProperties.FRC_FRC5.key();
        } else if (idx == FunctionalRoadClass.FRC_6.getID()) {
            return MapDrawingProperties.FRC_FRC6.key();
        } else if (idx == FunctionalRoadClass.FRC_7.getID()) {
            return MapDrawingProperties.FRC_FRC7.key();
        } else {
            throw new IllegalArgumentException();
        }
    }

    /**
     * Gets the fow undefined color.
     * 
     * @return the fow undefined color
     */
    public final Color getFowUndefinedColor() {
        return getColor(DefaultColors.FOWColors.UNDEFINED.getColor(), MapDrawingProperties.FOW_UNDEFINED.key());
    }

    /**
     * Gets the fow motorway color.
     * 
     * @return the fow motorway color
     */
    public final Color getFowMotorwayColor() {
        return getColor(DefaultColors.FOWColors.MOTORWAY.getColor(), MapDrawingProperties.FOW_MOTORWAY.key());
    }

    /**
     * Gets the fow multiple carriageway color.
     * 
     * @return the fow multiple carriageway color
     */
    public final Color getFowMultipleCarriagewayColor() {
        return getColor(DefaultColors.FOWColors.MULTIPLE_CARRIAGEWAY.getColor(),
                MapDrawingProperties.FOW_MULTIPLE_CARRIAGEWAY.key());
    }

    /**
     * Gets the fow single carriageway color.
     * 
     * @return the fow single carriageway color
     */
    public final Color getFowSingleCarriagewayColor() {
        return getColor(DefaultColors.FOWColors.SINGLE_CARRIAGEWAY.getColor(),
                MapDrawingProperties.FOW_SINGLE_CARRIAGEWAY.key());
    }

    /**
     * Gets the fow roundabout color.
     * 
     * @return the fow roundabout color
     */
    public final Color getFowRoundaboutColor() {
        return getColor(DefaultColors.FOWColors.ROUNDABOUT.getColor(), MapDrawingProperties.FOW_ROUNDABOUT.key());
    }

    /**
     * Gets the fow traffic square color.
     * 
     * @return the fow traffic square color
     */
    public final Color getFowTrafficSquareColor() {
        return getColor(DefaultColors.FOWColors.TRAFFIC_SQUARE.getColor(),
                MapDrawingProperties.FOW_TRAFFIC_SQUARE.key());
    }

    /**
     * Gets the fow sliproad color.
     * 
     * @return the fow sliproad color
     */
    public final Color getFowSliproadColor() {
        return getColor(DefaultColors.FOWColors.SLIPROAD.getColor(), MapDrawingProperties.FOW_SLIPROAD.key());
    }

    /**
     * Gets the fow other color.
     * 
     * @return the fow other color
     */
    public final Color getFowOtherColor() {
        return getColor(DefaultColors.FOWColors.OTHER.getColor(), MapDrawingProperties.FOW_OTHER.key());
    }

    /**
     * Gets the fow color.
     * 
     * @param idx
     *            the idx
     * @return the fow color
     */
    public final String getFowColorProperty(final int idx) {
        if (idx == FormOfWay.UNDEFINED.getID()) {
            return MapDrawingProperties.FOW_UNDEFINED.key();
        } else if (idx == FormOfWay.MOTORWAY.getID()) {
            return MapDrawingProperties.FOW_MOTORWAY.key();
        } else if (idx == FormOfWay.MULTIPLE_CARRIAGEWAY.getID()) {
            return MapDrawingProperties.FOW_MULTIPLE_CARRIAGEWAY.key();
        } else if (idx == FormOfWay.SINGLE_CARRIAGEWAY.getID()) {
            return MapDrawingProperties.FOW_SINGLE_CARRIAGEWAY.key();
        } else if (idx == FormOfWay.ROUNDABOUT.getID()) {
            return MapDrawingProperties.FOW_ROUNDABOUT.key();
        } else if (idx == FormOfWay.TRAFFIC_SQUARE.getID()) {
            return MapDrawingProperties.FOW_TRAFFIC_SQUARE.key();
        } else if (idx == FormOfWay.SLIPROAD.getID()) {
            return MapDrawingProperties.FOW_SLIPROAD.key();
        } else if (idx == FormOfWay.OTHER.getID()) {
            return MapDrawingProperties.FOW_OTHER.key();
        } else {
            throw new IllegalArgumentException();
        }
    }

    /**
     * Sets the property for the current user.
     * 
     * @param key
     *            The key of the property to set.
     * @param value
     *            The string value for the property.
     * @return The former value for this key in this overlay level if there was
     *         one.
     */
    @Override
    public final Object setProperty(final String key, final String value) {

        Object result;
        if (userProperties == null) {
            userProperties = new Properties();
        }
        synchronized (userProperties) {

            result = userProperties.setProperty(key, value);

            // update color cache
            if (COLOR_STORAGE.containsKey(key)) {
                COLOR_STORAGE.put(key, resolveColor(value));
            }

            try {
                storeUserProperties();
            } catch (IOException e) {
                LOG.error("Error storing the changed properties permanently", e);
            }
        }

        informOberservers(key);
        return result;
    }

    /**
     * Removes the user specific setting for the specified property key.
     * 
     * @param key
     *            The key of the desired property.
     * @return The value of the property before.
     */
    public final Object removeUserProperty(final String key) {
        Object result = null;
        if (userProperties != null) {
            result = userProperties.remove(key);
            try {
                storeUserProperties();
            } catch (IOException e) {
                LOG.error("Error storing the changed properties after removing " + "user property " + key, e);
            }
        }
        informOberservers(key);
        return result;
    }

    /**
    * Adds an observer that will be informed via
    * {@link MapViewerPropertiesObserver#updateProperty(String)} if the value
    * of a property changed. <b>Please notice that observers should unregister
    * themselves when their life-cycle ends!</b>
    * 
    * @param observer
    *            The {@link MapViewerPropertiesObserver} object.
    */
    public final void addObserver(final MapViewerPropertiesObserver observer) {
        synchronized (observers) {
            observers.put(observer, null);
        }
    }

    /**
     * Removes the given property changes observer from the list of observers.
     * 
     * @param observer
     *            The observer instance to remove (should
     */
    public final void removeObserver(final MapViewerPropertiesObserver observer) {

        synchronized (observers) {
            observers.remove(observer);
        }
    }

    /**
     * Informs all the registered observers about a change of the value of the
     * specified property.
     * 
     * @param changedProperty
     *            The key of the changed property.
     */
    private void informOberservers(final String changedProperty) {

        synchronized (observers) {

            for (MapViewerPropertiesObserver observer : observers.keySet()) {
                observer.updateProperty(changedProperty);
            }
        }
    }

    /**
     * Loads the properties for the current user from file
     * {@link #USER_PROPERTIES_FILE}
     * 
     * @return The loaded user specific properties.
     * @throws IOException
     *             In case of an error reading the properties file.
     */
    private Properties loadUserProperties() throws IOException {

        Properties props = null;
        String userHome = System.getProperty("user.home");
        if (userHome == null) {
            LOG.warn("Coudn't determine user home directory. " + "User specific properties wont be restored!");
        }
        File propFile = new File(userHome, USER_PROPERTIES_FILE);
        if (propFile.exists()) {
            props = new Properties();
            FileInputStream stream = new FileInputStream(propFile);
            try {
                props.load(stream);
            } finally {
                try {
                    stream.close();
                } catch (Exception e) {
                    LOG.warn("Error closing stream after loading user " + "properties file", e);
                }
            }

        }
        return props;

    }

    /**
     * Stores the current entries of the {@link #userProperties} to file
     * {@link #USER_PROPERTIES_FILE}.
     * 
     * @throws IOException
     *             In case of an error writing the file.
     */
    private void storeUserProperties() throws IOException {

        String userHome = System.getProperty("user.home");
        if (userHome == null) {
            LOG.warn("Coudn't determine user home directory. " + "Modified properties wont be stored permanently!");
        }
        File propFile = new File(userHome, USER_PROPERTIES_FILE);
        FileOutputStream userPropertiesStream = new FileOutputStream(propFile);

        try {
            userProperties.store(userPropertiesStream, null);
        } finally {
            try {
                userPropertiesStream.close();
            } catch (Exception e) {
                LOG.warn("Error closing stream after writing user properties file", e);
            }
        }
    }

    /**
     * Utility method that evaluates whether the given property key represents a
     * map drawing relevant property.
     * 
     * @param key
     *            The key to check.
     * @return <code>true</code> if the key defines a map drawing property,
     *         otherwise <code>false</code>.
     */
    public static boolean isMapDrawingProperty(final String key) {
        return key.startsWith("colors.") || key.startsWith("size.");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final int hashCode() {
        // we have to override hasCode because a parent class does it
        return new HashCodeBuilder().append(observers).append(userProperties).toHashCode();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final boolean equals(final Object obj) {
        // we have to override equals because a parent class does it
        if (!(obj instanceof MapViewerProperties)) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        MapViewerProperties other = (MapViewerProperties) obj;
        EqualsBuilder builder = new EqualsBuilder();
        builder.append(observers, other.observers).append(userProperties, other.userProperties);

        return builder.isEquals();
    }
}