001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.beans.factory.config;
018
019import java.util.Properties;
020import java.util.prefs.BackingStoreException;
021import java.util.prefs.Preferences;
022
023import org.springframework.beans.factory.BeanDefinitionStoreException;
024import org.springframework.beans.factory.InitializingBean;
025
026/**
027 * Subclass of PropertyPlaceholderConfigurer that supports JDK 1.4's
028 * Preferences API ({@code java.util.prefs}).
029 *
030 * <p>Tries to resolve placeholders as keys first in the user preferences,
031 * then in the system preferences, then in this configurer's properties.
032 * Thus, behaves like PropertyPlaceholderConfigurer if no corresponding
033 * preferences defined.
034 *
035 * <p>Supports custom paths for the system and user preferences trees. Also
036 * supports custom paths specified in placeholders ("myPath/myPlaceholderKey").
037 * Uses the respective root node if not specified.
038 *
039 * @author Juergen Hoeller
040 * @since 16.02.2004
041 * @see #setSystemTreePath
042 * @see #setUserTreePath
043 * @see java.util.prefs.Preferences
044 */
045public class PreferencesPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements InitializingBean {
046
047        private String systemTreePath;
048
049        private String userTreePath;
050
051        private Preferences systemPrefs;
052
053        private Preferences userPrefs;
054
055
056        /**
057         * Set the path in the system preferences tree to use for resolving
058         * placeholders. Default is the root node.
059         */
060        public void setSystemTreePath(String systemTreePath) {
061                this.systemTreePath = systemTreePath;
062        }
063
064        /**
065         * Set the path in the system preferences tree to use for resolving
066         * placeholders. Default is the root node.
067         */
068        public void setUserTreePath(String userTreePath) {
069                this.userTreePath = userTreePath;
070        }
071
072
073        /**
074         * This implementation eagerly fetches the Preferences instances
075         * for the required system and user tree nodes.
076         */
077        @Override
078        public void afterPropertiesSet() {
079                this.systemPrefs = (this.systemTreePath != null) ?
080                                Preferences.systemRoot().node(this.systemTreePath) : Preferences.systemRoot();
081                this.userPrefs = (this.userTreePath != null) ?
082                                Preferences.userRoot().node(this.userTreePath) : Preferences.userRoot();
083        }
084
085        /**
086         * This implementation tries to resolve placeholders as keys first
087         * in the user preferences, then in the system preferences, then in
088         * the passed-in properties.
089         */
090        @Override
091        protected String resolvePlaceholder(String placeholder, Properties props) {
092                String path = null;
093                String key = placeholder;
094                int endOfPath = placeholder.lastIndexOf('/');
095                if (endOfPath != -1) {
096                        path = placeholder.substring(0, endOfPath);
097                        key = placeholder.substring(endOfPath + 1);
098                }
099                String value = resolvePlaceholder(path, key, this.userPrefs);
100                if (value == null) {
101                        value = resolvePlaceholder(path, key, this.systemPrefs);
102                        if (value == null) {
103                                value = props.getProperty(placeholder);
104                        }
105                }
106                return value;
107        }
108
109        /**
110         * Resolve the given path and key against the given Preferences.
111         * @param path the preferences path (placeholder part before '/')
112         * @param key the preferences key (placeholder part after '/')
113         * @param preferences the Preferences to resolve against
114         * @return the value for the placeholder, or {@code null} if none found
115         */
116        protected String resolvePlaceholder(String path, String key, Preferences preferences) {
117                if (path != null) {
118                        // Do not create the node if it does not exist...
119                        try {
120                                if (preferences.nodeExists(path)) {
121                                        return preferences.node(path).get(key, null);
122                                }
123                                else {
124                                        return null;
125                                }
126                        }
127                        catch (BackingStoreException ex) {
128                                throw new BeanDefinitionStoreException("Cannot access specified node path [" + path + "]", ex);
129                        }
130                }
131                else {
132                        return preferences.get(key, null);
133                }
134        }
135
136}