001/*
002 * HA-JDBC: High-Availability JDBC
003 * Copyright (C) 2012  Paul Ferraro
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Lesser General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package net.sf.hajdbc.xml;
019
020import java.util.Properties;
021import java.util.regex.Matcher;
022import java.util.regex.Pattern;
023
024import net.sf.hajdbc.util.Strings;
025import net.sf.hajdbc.util.SystemProperties;
026
027import org.xml.sax.Attributes;
028import org.xml.sax.SAXException;
029import org.xml.sax.XMLReader;
030import org.xml.sax.helpers.AttributesImpl;
031import org.xml.sax.helpers.XMLFilterImpl;
032
033/**
034 * @author Paul Ferraro
035 */
036public class PropertyReplacementFilter extends XMLFilterImpl
037{
038        private static final Pattern PATTERN = Pattern.compile("\\$\\{([^\\}]+)\\}");
039        private final Properties properties;
040        
041        public PropertyReplacementFilter()
042        {
043                super();
044                this.properties = SystemProperties.getSystemProperties();
045        }
046        
047        public PropertyReplacementFilter(XMLReader parent)
048        {
049                this(parent, SystemProperties.getSystemProperties());
050        }
051        
052        public PropertyReplacementFilter(XMLReader parent, Properties properties)
053        {
054                super(parent);
055                this.properties = properties;
056        }
057        
058        /**
059         * {@inheritDoc}
060         * @see org.xml.sax.helpers.XMLFilterImpl#characters(char[], int, int)
061         */
062        @Override
063        public void characters(char[] data, int start, int length) throws SAXException
064        {
065                char[] value = this.replace(String.copyValueOf(data, start, length)).toCharArray();
066                super.characters(value, 0, value.length);
067        }
068
069        /**
070         * {@inheritDoc}
071         * @see org.xml.sax.helpers.XMLFilterImpl#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
072         */
073        @Override
074        public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException
075        {
076                AttributesImpl attributes = (attrs instanceof AttributesImpl) ? (AttributesImpl) attrs : new AttributesImpl(attrs);
077                
078                int length = attributes.getLength();
079                for (int i = 0; i < length; ++i)
080                {
081                        attributes.setValue(i, this.replace(attributes.getValue(i)));
082                }
083                
084                super.startElement(uri, localName, qName, attributes);
085        }
086        
087        private String replace(String input)
088        {
089                StringBuilder builder = new StringBuilder();
090                Matcher matcher = PATTERN.matcher(input);
091
092                int tail = 0;
093                
094                while (matcher.find())
095                {
096                        builder.append(input, tail, matcher.start());
097
098                        String group = matcher.group(1);
099
100                        if (group.equals("/"))
101                        {
102                                builder.append(Strings.FILE_SEPARATOR);
103                        }
104                        else if (group.equals(":"))
105                        {
106                                builder.append(Strings.PATH_SEPARATOR);
107                        }
108                        else
109                        {
110                                String key = group;
111                                String defaultValue = null;
112                                
113                                int index = group.indexOf(":");
114                                
115                                if (index > 0)
116                                {
117                                        key = group.substring(0, index);
118                                        defaultValue = group.substring(index + 1);
119                                }
120                                
121                                String value = this.getProperty(key.split(","), defaultValue);
122
123                                builder.append((value != null) ? value : matcher.group());
124                        }
125                        
126                        tail = matcher.end();
127                }
128                
129                builder.append(input, tail, input.length());
130                
131                return builder.toString();
132        }
133        
134        private String getProperty(String[] keys, String defaultValue)
135        {
136                for (String key: keys)
137                {
138                        String value = this.properties.getProperty(key.trim());
139                        
140                        if (value != null) return value;
141                }
142
143                return defaultValue;
144        }
145}