001    /*
002     * Copyright 2005,2009 Ivan SZKIBA
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     *      http://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    package org.ini4j;
017    
018    import org.ini4j.spi.BeanAccess;
019    import org.ini4j.spi.BeanTool;
020    
021    import java.util.regex.Matcher;
022    import java.util.regex.Pattern;
023    
024    public class OptionMapImpl extends MultiMapImpl<String, String> implements OptionMap
025    {
026        private static final char SUBST_CHAR = '$';
027        private static final String SYSTEM_PROPERTY_PREFIX = "@prop/";
028        private static final String ENVIRONMENT_PREFIX = "@env/";
029        private static final int SYSTEM_PROPERTY_PREFIX_LEN = SYSTEM_PROPERTY_PREFIX.length();
030        private static final int ENVIRONMENT_PREFIX_LEN = ENVIRONMENT_PREFIX.length();
031        private static final Pattern EXPRESSION = Pattern.compile("(?<!\\\\)\\$\\{(([^\\[]+)(\\[([0-9]+)\\])?)\\}");
032        private static final int G_OPTION = 2;
033        private static final int G_INDEX = 4;
034        private BeanAccess _defaultBeanAccess;
035    
036        @Override public <T> T as(Class<T> clazz)
037        {
038            return BeanTool.getInstance().proxy(clazz, getDefaultBeanAccess());
039        }
040    
041        @Override public <T> T as(Class<T> clazz, String keyPrefix)
042        {
043            return BeanTool.getInstance().proxy(clazz, newBeanAccess(keyPrefix));
044        }
045    
046        @Override public String fetch(Object key)
047        {
048            int len = length(key);
049    
050            return (len == 0) ? null : fetch(key, len - 1);
051        }
052    
053        @Override public String fetch(Object key, int index)
054        {
055            String value = get(key, index);
056    
057            if ((value != null) && (value.indexOf(SUBST_CHAR) >= 0))
058            {
059                StringBuilder buffer = new StringBuilder(value);
060    
061                resolve(buffer);
062                value = buffer.toString();
063            }
064    
065            return value;
066        }
067    
068        @Override public void from(Object bean)
069        {
070            BeanTool.getInstance().inject(getDefaultBeanAccess(), bean);
071        }
072    
073        @Override public void from(Object bean, String keyPrefix)
074        {
075            BeanTool.getInstance().inject(newBeanAccess(keyPrefix), bean);
076        }
077    
078        @Override public void to(Object bean)
079        {
080            BeanTool.getInstance().inject(bean, getDefaultBeanAccess());
081        }
082    
083        @Override public void to(Object bean, String keyPrefix)
084        {
085            BeanTool.getInstance().inject(bean, newBeanAccess(keyPrefix));
086        }
087    
088        protected synchronized BeanAccess getDefaultBeanAccess()
089        {
090            if (_defaultBeanAccess == null)
091            {
092                _defaultBeanAccess = newBeanAccess();
093            }
094    
095            return _defaultBeanAccess;
096        }
097    
098        protected BeanAccess newBeanAccess()
099        {
100            return new Access();
101        }
102    
103        protected BeanAccess newBeanAccess(String propertyNamePrefix)
104        {
105            return new Access(propertyNamePrefix);
106        }
107    
108        protected void resolve(StringBuilder buffer)
109        {
110            Matcher m = EXPRESSION.matcher(buffer);
111    
112            while (m.find())
113            {
114                String name = m.group(G_OPTION);
115                int index = (m.group(G_INDEX) == null) ? -1 : Integer.parseInt(m.group(G_INDEX));
116                String value;
117    
118                if (name.startsWith(ENVIRONMENT_PREFIX))
119                {
120                    value = System.getenv(name.substring(ENVIRONMENT_PREFIX_LEN));
121                }
122                else if (name.startsWith(SYSTEM_PROPERTY_PREFIX))
123                {
124                    value = System.getProperty(name.substring(SYSTEM_PROPERTY_PREFIX_LEN));
125                }
126                else
127                {
128                    value = (index == -1) ? fetch(name) : fetch(name, index);
129                }
130    
131                if (value != null)
132                {
133                    buffer.replace(m.start(), m.end(), value);
134                    m.reset(buffer);
135                }
136            }
137        }
138    
139        protected class Access implements BeanAccess
140        {
141            private final String _prefix;
142    
143            protected Access()
144            {
145                this(null);
146            }
147    
148            protected Access(String prefix)
149            {
150                _prefix = prefix;
151            }
152    
153            public void propAdd(String propertyName, String value)
154            {
155                add(transform(propertyName), value);
156            }
157    
158            public String propDel(String propertyName)
159            {
160                return remove(transform(propertyName));
161            }
162    
163            public String propGet(String propertyName)
164            {
165                return fetch(transform(propertyName));
166            }
167    
168            public String propGet(String propertyName, int index)
169            {
170                return fetch(transform(propertyName), index);
171            }
172    
173            public int propLength(String propertyName)
174            {
175                return length(transform(propertyName));
176            }
177    
178            public String propSet(String propertyName, String value)
179            {
180                return put(transform(propertyName), value);
181            }
182    
183            public String propSet(String propertyName, String value, int index)
184            {
185                return put(transform(propertyName), value, index);
186            }
187    
188            private String transform(String orig)
189            {
190                return (orig == null) ? null : ((_prefix == null) ? orig : (_prefix + orig));
191            }
192        }
193    }