001/*
002 * Copyright 2006-2007 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.batch.support;
018
019import java.io.IOException;
020import java.io.StringReader;
021import java.io.StringWriter;
022import java.util.Arrays;
023import java.util.List;
024import java.util.Properties;
025
026import org.springframework.util.DefaultPropertiesPersister;
027import org.springframework.util.PropertiesPersister;
028import org.springframework.util.StringUtils;
029
030/**
031 * Utility to convert a Properties object to a String and back. Ideally this
032 * utility should have been used to convert to string in order to convert that
033 * string back to a Properties Object. Attempting to convert a string obtained
034 * by calling Properties.toString() will return an invalid Properties object.
035 * The format of Properties is that used by {@link PropertiesPersister} from the
036 * Spring Core, so a String in the correct format for a Spring property editor
037 * is fine (key=value pairs separated by new lines).
038 * 
039 * @author Lucas Ward
040 * @author Dave Syer
041 * 
042 * @see PropertiesPersister
043 */
044public final class PropertiesConverter {
045
046        private static final PropertiesPersister propertiesPersister = new DefaultPropertiesPersister();
047
048        private static final String LINE_SEPARATOR = System.getProperty("line.separator");
049
050        // prevents the class from being instantiated
051        private PropertiesConverter() {
052        }
053
054        /**
055         * Parse a String to a Properties object. If string is null, an empty
056         * Properties object will be returned. The input String is a set of
057         * name=value pairs, delimited by either newline or comma (for brevity). If
058         * the input String contains a newline it is assumed that the separator is
059         * newline, otherwise comma.
060         * 
061         * @param stringToParse String to parse.
062         * @return Properties parsed from each string.
063         * @see PropertiesPersister
064         */
065        public static Properties stringToProperties(String stringToParse) {
066
067                if (stringToParse == null) {
068                        return new Properties();
069                }
070
071                if (!contains(stringToParse, "\n")) {
072                        stringToParse = StringUtils.arrayToDelimitedString(
073                                        StringUtils.commaDelimitedListToStringArray(stringToParse), "\n");
074                }
075
076                StringReader stringReader = new StringReader(stringToParse);
077
078                Properties properties = new Properties();
079
080                try {
081                        propertiesPersister.load(properties, stringReader);
082                        // Exception is only thrown by StringReader after it is closed,
083                        // so never in this case.
084                }
085                catch (IOException ex) {
086                        throw new IllegalStateException("Error while trying to parse String to java.util.Properties,"
087                                        + " given String: " + properties);
088                }
089
090                return properties;
091        }
092
093        /**
094         * Convert Properties object to String. This is only necessary for
095         * compatibility with converting the String back to a properties object. If
096         * an empty properties object is passed in, a blank string is returned,
097         * otherwise it's string representation is returned.
098         * 
099         * @param propertiesToParse contains the properties be converted.
100         * @return String representation of properties object
101         */
102        public static String propertiesToString(Properties propertiesToParse) {
103
104                // If properties is empty, return a blank string.
105                if (propertiesToParse == null || propertiesToParse.size() == 0) {
106                        return "";
107                }
108
109                StringWriter stringWriter = new StringWriter();
110
111                try {
112                        propertiesPersister.store(propertiesToParse, stringWriter, null);
113                }
114                catch (IOException ex) {
115                        // Exception is never thrown by StringWriter
116                        throw new IllegalStateException("Error while trying to convert properties to string");
117                }
118
119                // If the value is short enough (and doesn't contain commas), convert to
120                // comma-separated...
121                String value = stringWriter.toString();
122                if (value.length() < 160) {
123                        List<String> list = Arrays.asList(StringUtils.delimitedListToStringArray(value, LINE_SEPARATOR,
124                                        LINE_SEPARATOR));
125                        String shortValue = StringUtils.collectionToCommaDelimitedString(list.subList(1, list.size()));
126                        int count = StringUtils.countOccurrencesOf(shortValue, ",");
127                        if (count == list.size() - 2) {
128                                value = shortValue;
129                        }
130                        if (value.endsWith(",")) {
131                                value = value.substring(0, value.length() - 1);
132                        }
133                }
134                return value;
135        }
136
137        private static boolean contains(String str, String searchStr) {
138                return str.indexOf(searchStr) != -1;
139        }
140}