blob: 2cb4df496adce08ee807fd35c5e30bef1b5a0aed [file] [log] [blame]
<!DOCTYPE HTML>
<html lang="fr">
<head>
<title>Source code</title>
<link rel="stylesheet" type="text/css" href="../../../../../stylesheet.css" title="Style">
</head>
<body>
<main role="main">
<div class="sourceContainer">
<pre><span class="sourceLineNo">001</span><a id="line.1">/*</a>
<span class="sourceLineNo">002</span><a id="line.2"> * Licensed to the Apache Software Foundation (ASF) under one</a>
<span class="sourceLineNo">003</span><a id="line.3"> * or more contributor license agreements. See the NOTICE file</a>
<span class="sourceLineNo">004</span><a id="line.4"> * distributed with this work for additional information</a>
<span class="sourceLineNo">005</span><a id="line.5"> * regarding copyright ownership. The ASF licenses this file</a>
<span class="sourceLineNo">006</span><a id="line.6"> * to you under the Apache License, Version 2.0 (the</a>
<span class="sourceLineNo">007</span><a id="line.7"> * "License"); you may not use this file except in compliance</a>
<span class="sourceLineNo">008</span><a id="line.8"> * with the License. You may obtain a copy of the License at</a>
<span class="sourceLineNo">009</span><a id="line.9"> *</a>
<span class="sourceLineNo">010</span><a id="line.10"> * http://www.apache.org/licenses/LICENSE-2.0</a>
<span class="sourceLineNo">011</span><a id="line.11"> *</a>
<span class="sourceLineNo">012</span><a id="line.12"> * Unless required by applicable law or agreed to in writing,</a>
<span class="sourceLineNo">013</span><a id="line.13"> * software distributed under the License is distributed on an</a>
<span class="sourceLineNo">014</span><a id="line.14"> * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY</a>
<span class="sourceLineNo">015</span><a id="line.15"> * KIND, either express or implied. See the License for the</a>
<span class="sourceLineNo">016</span><a id="line.16"> * specific language governing permissions and limitations</a>
<span class="sourceLineNo">017</span><a id="line.17"> * under the License.</a>
<span class="sourceLineNo">018</span><a id="line.18"> */</a>
<span class="sourceLineNo">019</span><a id="line.19">package org.apache.shiro.config;</a>
<span class="sourceLineNo">020</span><a id="line.20"></a>
<span class="sourceLineNo">021</span><a id="line.21">import org.apache.shiro.io.ResourceUtils;</a>
<span class="sourceLineNo">022</span><a id="line.22">import org.apache.shiro.util.StringUtils;</a>
<span class="sourceLineNo">023</span><a id="line.23">import org.slf4j.Logger;</a>
<span class="sourceLineNo">024</span><a id="line.24">import org.slf4j.LoggerFactory;</a>
<span class="sourceLineNo">025</span><a id="line.25"></a>
<span class="sourceLineNo">026</span><a id="line.26">import java.io.IOException;</a>
<span class="sourceLineNo">027</span><a id="line.27">import java.io.InputStream;</a>
<span class="sourceLineNo">028</span><a id="line.28">import java.io.InputStreamReader;</a>
<span class="sourceLineNo">029</span><a id="line.29">import java.io.Reader;</a>
<span class="sourceLineNo">030</span><a id="line.30">import java.io.UnsupportedEncodingException;</a>
<span class="sourceLineNo">031</span><a id="line.31">import java.util.Collection;</a>
<span class="sourceLineNo">032</span><a id="line.32">import java.util.Collections;</a>
<span class="sourceLineNo">033</span><a id="line.33">import java.util.LinkedHashMap;</a>
<span class="sourceLineNo">034</span><a id="line.34">import java.util.Map;</a>
<span class="sourceLineNo">035</span><a id="line.35">import java.util.Scanner;</a>
<span class="sourceLineNo">036</span><a id="line.36">import java.util.Set;</a>
<span class="sourceLineNo">037</span><a id="line.37"></a>
<span class="sourceLineNo">038</span><a id="line.38">/**</a>
<span class="sourceLineNo">039</span><a id="line.39"> * A class representing the &lt;a href="http://en.wikipedia.org/wiki/INI_file"&gt;INI&lt;/a&gt; text configuration format.</a>
<span class="sourceLineNo">040</span><a id="line.40"> * &lt;p/&gt;</a>
<span class="sourceLineNo">041</span><a id="line.41"> * An Ini instance is a map of {@link Ini.Section Section}s, keyed by section name. Each</a>
<span class="sourceLineNo">042</span><a id="line.42"> * {@code Section} is itself a map of {@code String} name/value pairs. Name/value pairs are guaranteed to be unique</a>
<span class="sourceLineNo">043</span><a id="line.43"> * within each {@code Section} only - not across the entire {@code Ini} instance.</a>
<span class="sourceLineNo">044</span><a id="line.44"> *</a>
<span class="sourceLineNo">045</span><a id="line.45"> * @since 1.0</a>
<span class="sourceLineNo">046</span><a id="line.46"> */</a>
<span class="sourceLineNo">047</span><a id="line.47">public class Ini implements Map&lt;String, Ini.Section&gt; {</a>
<span class="sourceLineNo">048</span><a id="line.48"></a>
<span class="sourceLineNo">049</span><a id="line.49"> private static transient final Logger log = LoggerFactory.getLogger(Ini.class);</a>
<span class="sourceLineNo">050</span><a id="line.50"></a>
<span class="sourceLineNo">051</span><a id="line.51"> public static final String DEFAULT_SECTION_NAME = ""; //empty string means the first unnamed section</a>
<span class="sourceLineNo">052</span><a id="line.52"> public static final String DEFAULT_CHARSET_NAME = "UTF-8";</a>
<span class="sourceLineNo">053</span><a id="line.53"></a>
<span class="sourceLineNo">054</span><a id="line.54"> public static final String COMMENT_POUND = "#";</a>
<span class="sourceLineNo">055</span><a id="line.55"> public static final String COMMENT_SEMICOLON = ";";</a>
<span class="sourceLineNo">056</span><a id="line.56"> public static final String SECTION_PREFIX = "[";</a>
<span class="sourceLineNo">057</span><a id="line.57"> public static final String SECTION_SUFFIX = "]";</a>
<span class="sourceLineNo">058</span><a id="line.58"></a>
<span class="sourceLineNo">059</span><a id="line.59"> protected static final char ESCAPE_TOKEN = '\\';</a>
<span class="sourceLineNo">060</span><a id="line.60"></a>
<span class="sourceLineNo">061</span><a id="line.61"> private final Map&lt;String, Section&gt; sections;</a>
<span class="sourceLineNo">062</span><a id="line.62"></a>
<span class="sourceLineNo">063</span><a id="line.63"> /**</a>
<span class="sourceLineNo">064</span><a id="line.64"> * Creates a new empty {@code Ini} instance.</a>
<span class="sourceLineNo">065</span><a id="line.65"> */</a>
<span class="sourceLineNo">066</span><a id="line.66"> public Ini() {</a>
<span class="sourceLineNo">067</span><a id="line.67"> this.sections = new LinkedHashMap&lt;String, Section&gt;();</a>
<span class="sourceLineNo">068</span><a id="line.68"> }</a>
<span class="sourceLineNo">069</span><a id="line.69"></a>
<span class="sourceLineNo">070</span><a id="line.70"> /**</a>
<span class="sourceLineNo">071</span><a id="line.71"> * Creates a new {@code Ini} instance with the specified defaults.</a>
<span class="sourceLineNo">072</span><a id="line.72"> *</a>
<span class="sourceLineNo">073</span><a id="line.73"> * @param defaults the default sections and/or key-value pairs to copy into the new instance.</a>
<span class="sourceLineNo">074</span><a id="line.74"> */</a>
<span class="sourceLineNo">075</span><a id="line.75"> public Ini(Ini defaults) {</a>
<span class="sourceLineNo">076</span><a id="line.76"> this();</a>
<span class="sourceLineNo">077</span><a id="line.77"> if (defaults == null) {</a>
<span class="sourceLineNo">078</span><a id="line.78"> throw new NullPointerException("Defaults cannot be null.");</a>
<span class="sourceLineNo">079</span><a id="line.79"> }</a>
<span class="sourceLineNo">080</span><a id="line.80"> for (Section section : defaults.getSections()) {</a>
<span class="sourceLineNo">081</span><a id="line.81"> Section copy = new Section(section);</a>
<span class="sourceLineNo">082</span><a id="line.82"> this.sections.put(section.getName(), copy);</a>
<span class="sourceLineNo">083</span><a id="line.83"> }</a>
<span class="sourceLineNo">084</span><a id="line.84"> }</a>
<span class="sourceLineNo">085</span><a id="line.85"></a>
<span class="sourceLineNo">086</span><a id="line.86"> /**</a>
<span class="sourceLineNo">087</span><a id="line.87"> * Returns {@code true} if no sections have been configured, or if there are sections, but the sections themselves</a>
<span class="sourceLineNo">088</span><a id="line.88"> * are all empty, {@code false} otherwise.</a>
<span class="sourceLineNo">089</span><a id="line.89"> *</a>
<span class="sourceLineNo">090</span><a id="line.90"> * @return {@code true} if no sections have been configured, or if there are sections, but the sections themselves</a>
<span class="sourceLineNo">091</span><a id="line.91"> * are all empty, {@code false} otherwise.</a>
<span class="sourceLineNo">092</span><a id="line.92"> */</a>
<span class="sourceLineNo">093</span><a id="line.93"> public boolean isEmpty() {</a>
<span class="sourceLineNo">094</span><a id="line.94"> Collection&lt;Section&gt; sections = this.sections.values();</a>
<span class="sourceLineNo">095</span><a id="line.95"> if (!sections.isEmpty()) {</a>
<span class="sourceLineNo">096</span><a id="line.96"> for (Section section : sections) {</a>
<span class="sourceLineNo">097</span><a id="line.97"> if (!section.isEmpty()) {</a>
<span class="sourceLineNo">098</span><a id="line.98"> return false;</a>
<span class="sourceLineNo">099</span><a id="line.99"> }</a>
<span class="sourceLineNo">100</span><a id="line.100"> }</a>
<span class="sourceLineNo">101</span><a id="line.101"> }</a>
<span class="sourceLineNo">102</span><a id="line.102"> return true;</a>
<span class="sourceLineNo">103</span><a id="line.103"> }</a>
<span class="sourceLineNo">104</span><a id="line.104"></a>
<span class="sourceLineNo">105</span><a id="line.105"> /**</a>
<span class="sourceLineNo">106</span><a id="line.106"> * Returns the names of all sections managed by this {@code Ini} instance or an empty collection if there are</a>
<span class="sourceLineNo">107</span><a id="line.107"> * no sections.</a>
<span class="sourceLineNo">108</span><a id="line.108"> *</a>
<span class="sourceLineNo">109</span><a id="line.109"> * @return the names of all sections managed by this {@code Ini} instance or an empty collection if there are</a>
<span class="sourceLineNo">110</span><a id="line.110"> * no sections.</a>
<span class="sourceLineNo">111</span><a id="line.111"> */</a>
<span class="sourceLineNo">112</span><a id="line.112"> public Set&lt;String&gt; getSectionNames() {</a>
<span class="sourceLineNo">113</span><a id="line.113"> return Collections.unmodifiableSet(sections.keySet());</a>
<span class="sourceLineNo">114</span><a id="line.114"> }</a>
<span class="sourceLineNo">115</span><a id="line.115"></a>
<span class="sourceLineNo">116</span><a id="line.116"> /**</a>
<span class="sourceLineNo">117</span><a id="line.117"> * Returns the sections managed by this {@code Ini} instance or an empty collection if there are</a>
<span class="sourceLineNo">118</span><a id="line.118"> * no sections.</a>
<span class="sourceLineNo">119</span><a id="line.119"> *</a>
<span class="sourceLineNo">120</span><a id="line.120"> * @return the sections managed by this {@code Ini} instance or an empty collection if there are</a>
<span class="sourceLineNo">121</span><a id="line.121"> * no sections.</a>
<span class="sourceLineNo">122</span><a id="line.122"> */</a>
<span class="sourceLineNo">123</span><a id="line.123"> public Collection&lt;Section&gt; getSections() {</a>
<span class="sourceLineNo">124</span><a id="line.124"> return Collections.unmodifiableCollection(sections.values());</a>
<span class="sourceLineNo">125</span><a id="line.125"> }</a>
<span class="sourceLineNo">126</span><a id="line.126"></a>
<span class="sourceLineNo">127</span><a id="line.127"> /**</a>
<span class="sourceLineNo">128</span><a id="line.128"> * Returns the {@link Section} with the given name or {@code null} if no section with that name exists.</a>
<span class="sourceLineNo">129</span><a id="line.129"> *</a>
<span class="sourceLineNo">130</span><a id="line.130"> * @param sectionName the name of the section to retrieve.</a>
<span class="sourceLineNo">131</span><a id="line.131"> * @return the {@link Section} with the given name or {@code null} if no section with that name exists.</a>
<span class="sourceLineNo">132</span><a id="line.132"> */</a>
<span class="sourceLineNo">133</span><a id="line.133"> public Section getSection(String sectionName) {</a>
<span class="sourceLineNo">134</span><a id="line.134"> String name = cleanName(sectionName);</a>
<span class="sourceLineNo">135</span><a id="line.135"> return sections.get(name);</a>
<span class="sourceLineNo">136</span><a id="line.136"> }</a>
<span class="sourceLineNo">137</span><a id="line.137"></a>
<span class="sourceLineNo">138</span><a id="line.138"> /**</a>
<span class="sourceLineNo">139</span><a id="line.139"> * Ensures a section with the specified name exists, adding a new one if it does not yet exist.</a>
<span class="sourceLineNo">140</span><a id="line.140"> *</a>
<span class="sourceLineNo">141</span><a id="line.141"> * @param sectionName the name of the section to ensure existence</a>
<span class="sourceLineNo">142</span><a id="line.142"> * @return the section created if it did not yet exist, or the existing Section that already existed.</a>
<span class="sourceLineNo">143</span><a id="line.143"> */</a>
<span class="sourceLineNo">144</span><a id="line.144"> public Section addSection(String sectionName) {</a>
<span class="sourceLineNo">145</span><a id="line.145"> String name = cleanName(sectionName);</a>
<span class="sourceLineNo">146</span><a id="line.146"> Section section = getSection(name);</a>
<span class="sourceLineNo">147</span><a id="line.147"> if (section == null) {</a>
<span class="sourceLineNo">148</span><a id="line.148"> section = new Section(name);</a>
<span class="sourceLineNo">149</span><a id="line.149"> this.sections.put(name, section);</a>
<span class="sourceLineNo">150</span><a id="line.150"> }</a>
<span class="sourceLineNo">151</span><a id="line.151"> return section;</a>
<span class="sourceLineNo">152</span><a id="line.152"> }</a>
<span class="sourceLineNo">153</span><a id="line.153"></a>
<span class="sourceLineNo">154</span><a id="line.154"> /**</a>
<span class="sourceLineNo">155</span><a id="line.155"> * Removes the section with the specified name and returns it, or {@code null} if the section did not exist.</a>
<span class="sourceLineNo">156</span><a id="line.156"> *</a>
<span class="sourceLineNo">157</span><a id="line.157"> * @param sectionName the name of the section to remove.</a>
<span class="sourceLineNo">158</span><a id="line.158"> * @return the section with the specified name or {@code null} if the section did not exist.</a>
<span class="sourceLineNo">159</span><a id="line.159"> */</a>
<span class="sourceLineNo">160</span><a id="line.160"> public Section removeSection(String sectionName) {</a>
<span class="sourceLineNo">161</span><a id="line.161"> String name = cleanName(sectionName);</a>
<span class="sourceLineNo">162</span><a id="line.162"> return this.sections.remove(name);</a>
<span class="sourceLineNo">163</span><a id="line.163"> }</a>
<span class="sourceLineNo">164</span><a id="line.164"></a>
<span class="sourceLineNo">165</span><a id="line.165"> private static String cleanName(String sectionName) {</a>
<span class="sourceLineNo">166</span><a id="line.166"> String name = StringUtils.clean(sectionName);</a>
<span class="sourceLineNo">167</span><a id="line.167"> if (name == null) {</a>
<span class="sourceLineNo">168</span><a id="line.168"> log.trace("Specified name was null or empty. Defaulting to the default section (name = \"\")");</a>
<span class="sourceLineNo">169</span><a id="line.169"> name = DEFAULT_SECTION_NAME;</a>
<span class="sourceLineNo">170</span><a id="line.170"> }</a>
<span class="sourceLineNo">171</span><a id="line.171"> return name;</a>
<span class="sourceLineNo">172</span><a id="line.172"> }</a>
<span class="sourceLineNo">173</span><a id="line.173"></a>
<span class="sourceLineNo">174</span><a id="line.174"> /**</a>
<span class="sourceLineNo">175</span><a id="line.175"> * Sets a name/value pair for the section with the given {@code sectionName}. If the section does not yet exist,</a>
<span class="sourceLineNo">176</span><a id="line.176"> * it will be created. If the {@code sectionName} is null or empty, the name/value pair will be placed in the</a>
<span class="sourceLineNo">177</span><a id="line.177"> * default (unnamed, empty string) section.</a>
<span class="sourceLineNo">178</span><a id="line.178"> *</a>
<span class="sourceLineNo">179</span><a id="line.179"> * @param sectionName the name of the section to add the name/value pair</a>
<span class="sourceLineNo">180</span><a id="line.180"> * @param propertyName the name of the property to add</a>
<span class="sourceLineNo">181</span><a id="line.181"> * @param propertyValue the property value</a>
<span class="sourceLineNo">182</span><a id="line.182"> */</a>
<span class="sourceLineNo">183</span><a id="line.183"> public void setSectionProperty(String sectionName, String propertyName, String propertyValue) {</a>
<span class="sourceLineNo">184</span><a id="line.184"> String name = cleanName(sectionName);</a>
<span class="sourceLineNo">185</span><a id="line.185"> Section section = getSection(name);</a>
<span class="sourceLineNo">186</span><a id="line.186"> if (section == null) {</a>
<span class="sourceLineNo">187</span><a id="line.187"> section = addSection(name);</a>
<span class="sourceLineNo">188</span><a id="line.188"> }</a>
<span class="sourceLineNo">189</span><a id="line.189"> section.put(propertyName, propertyValue);</a>
<span class="sourceLineNo">190</span><a id="line.190"> }</a>
<span class="sourceLineNo">191</span><a id="line.191"></a>
<span class="sourceLineNo">192</span><a id="line.192"> /**</a>
<span class="sourceLineNo">193</span><a id="line.193"> * Returns the value of the specified section property, or {@code null} if the section or property do not exist.</a>
<span class="sourceLineNo">194</span><a id="line.194"> *</a>
<span class="sourceLineNo">195</span><a id="line.195"> * @param sectionName the name of the section to retrieve to acquire the property value</a>
<span class="sourceLineNo">196</span><a id="line.196"> * @param propertyName the name of the section property for which to return the value</a>
<span class="sourceLineNo">197</span><a id="line.197"> * @return the value of the specified section property, or {@code null} if the section or property do not exist.</a>
<span class="sourceLineNo">198</span><a id="line.198"> */</a>
<span class="sourceLineNo">199</span><a id="line.199"> public String getSectionProperty(String sectionName, String propertyName) {</a>
<span class="sourceLineNo">200</span><a id="line.200"> Section section = getSection(sectionName);</a>
<span class="sourceLineNo">201</span><a id="line.201"> return section != null ? section.get(propertyName) : null;</a>
<span class="sourceLineNo">202</span><a id="line.202"> }</a>
<span class="sourceLineNo">203</span><a id="line.203"></a>
<span class="sourceLineNo">204</span><a id="line.204"> /**</a>
<span class="sourceLineNo">205</span><a id="line.205"> * Returns the value of the specified section property, or the {@code defaultValue} if the section or</a>
<span class="sourceLineNo">206</span><a id="line.206"> * property do not exist.</a>
<span class="sourceLineNo">207</span><a id="line.207"> *</a>
<span class="sourceLineNo">208</span><a id="line.208"> * @param sectionName the name of the section to add the name/value pair</a>
<span class="sourceLineNo">209</span><a id="line.209"> * @param propertyName the name of the property to add</a>
<span class="sourceLineNo">210</span><a id="line.210"> * @param defaultValue the default value to return if the section or property do not exist.</a>
<span class="sourceLineNo">211</span><a id="line.211"> * @return the value of the specified section property, or the {@code defaultValue} if the section or</a>
<span class="sourceLineNo">212</span><a id="line.212"> * property do not exist.</a>
<span class="sourceLineNo">213</span><a id="line.213"> */</a>
<span class="sourceLineNo">214</span><a id="line.214"> public String getSectionProperty(String sectionName, String propertyName, String defaultValue) {</a>
<span class="sourceLineNo">215</span><a id="line.215"> String value = getSectionProperty(sectionName, propertyName);</a>
<span class="sourceLineNo">216</span><a id="line.216"> return value != null ? value : defaultValue;</a>
<span class="sourceLineNo">217</span><a id="line.217"> }</a>
<span class="sourceLineNo">218</span><a id="line.218"></a>
<span class="sourceLineNo">219</span><a id="line.219"> /**</a>
<span class="sourceLineNo">220</span><a id="line.220"> * Creates a new {@code Ini} instance loaded with the INI-formatted data in the resource at the given path. The</a>
<span class="sourceLineNo">221</span><a id="line.221"> * resource path may be any value interpretable by the</a>
<span class="sourceLineNo">222</span><a id="line.222"> * {@link ResourceUtils#getInputStreamForPath(String) ResourceUtils.getInputStreamForPath} method.</a>
<span class="sourceLineNo">223</span><a id="line.223"> *</a>
<span class="sourceLineNo">224</span><a id="line.224"> * @param resourcePath the resource location of the INI data to load when creating the {@code Ini} instance.</a>
<span class="sourceLineNo">225</span><a id="line.225"> * @return a new {@code Ini} instance loaded with the INI-formatted data in the resource at the given path.</a>
<span class="sourceLineNo">226</span><a id="line.226"> * @throws ConfigurationException if the path cannot be loaded into an {@code Ini} instance.</a>
<span class="sourceLineNo">227</span><a id="line.227"> */</a>
<span class="sourceLineNo">228</span><a id="line.228"> public static Ini fromResourcePath(String resourcePath) throws ConfigurationException {</a>
<span class="sourceLineNo">229</span><a id="line.229"> if (!StringUtils.hasLength(resourcePath)) {</a>
<span class="sourceLineNo">230</span><a id="line.230"> throw new IllegalArgumentException("Resource Path argument cannot be null or empty.");</a>
<span class="sourceLineNo">231</span><a id="line.231"> }</a>
<span class="sourceLineNo">232</span><a id="line.232"> Ini ini = new Ini();</a>
<span class="sourceLineNo">233</span><a id="line.233"> ini.loadFromPath(resourcePath);</a>
<span class="sourceLineNo">234</span><a id="line.234"> return ini;</a>
<span class="sourceLineNo">235</span><a id="line.235"> }</a>
<span class="sourceLineNo">236</span><a id="line.236"></a>
<span class="sourceLineNo">237</span><a id="line.237"> /**</a>
<span class="sourceLineNo">238</span><a id="line.238"> * Loads data from the specified resource path into this current {@code Ini} instance. The</a>
<span class="sourceLineNo">239</span><a id="line.239"> * resource path may be any value interpretable by the</a>
<span class="sourceLineNo">240</span><a id="line.240"> * {@link ResourceUtils#getInputStreamForPath(String) ResourceUtils.getInputStreamForPath} method.</a>
<span class="sourceLineNo">241</span><a id="line.241"> *</a>
<span class="sourceLineNo">242</span><a id="line.242"> * @param resourcePath the resource location of the INI data to load into this instance.</a>
<span class="sourceLineNo">243</span><a id="line.243"> * @throws ConfigurationException if the path cannot be loaded</a>
<span class="sourceLineNo">244</span><a id="line.244"> */</a>
<span class="sourceLineNo">245</span><a id="line.245"> public void loadFromPath(String resourcePath) throws ConfigurationException {</a>
<span class="sourceLineNo">246</span><a id="line.246"> InputStream is;</a>
<span class="sourceLineNo">247</span><a id="line.247"> try {</a>
<span class="sourceLineNo">248</span><a id="line.248"> is = ResourceUtils.getInputStreamForPath(resourcePath);</a>
<span class="sourceLineNo">249</span><a id="line.249"> } catch (IOException e) {</a>
<span class="sourceLineNo">250</span><a id="line.250"> throw new ConfigurationException(e);</a>
<span class="sourceLineNo">251</span><a id="line.251"> }</a>
<span class="sourceLineNo">252</span><a id="line.252"> load(is);</a>
<span class="sourceLineNo">253</span><a id="line.253"> }</a>
<span class="sourceLineNo">254</span><a id="line.254"></a>
<span class="sourceLineNo">255</span><a id="line.255"> /**</a>
<span class="sourceLineNo">256</span><a id="line.256"> * Loads the specified raw INI-formatted text into this instance.</a>
<span class="sourceLineNo">257</span><a id="line.257"> *</a>
<span class="sourceLineNo">258</span><a id="line.258"> * @param iniConfig the raw INI-formatted text to load into this instance.</a>
<span class="sourceLineNo">259</span><a id="line.259"> * @throws ConfigurationException if the text cannot be loaded</a>
<span class="sourceLineNo">260</span><a id="line.260"> */</a>
<span class="sourceLineNo">261</span><a id="line.261"> public void load(String iniConfig) throws ConfigurationException {</a>
<span class="sourceLineNo">262</span><a id="line.262"> load(new Scanner(iniConfig));</a>
<span class="sourceLineNo">263</span><a id="line.263"> }</a>
<span class="sourceLineNo">264</span><a id="line.264"></a>
<span class="sourceLineNo">265</span><a id="line.265"> /**</a>
<span class="sourceLineNo">266</span><a id="line.266"> * Loads the INI-formatted text backed by the given InputStream into this instance. This implementation will</a>
<span class="sourceLineNo">267</span><a id="line.267"> * close the input stream after it has finished loading. It is expected that the stream's contents are</a>
<span class="sourceLineNo">268</span><a id="line.268"> * UTF-8 encoded.</a>
<span class="sourceLineNo">269</span><a id="line.269"> *</a>
<span class="sourceLineNo">270</span><a id="line.270"> * @param is the {@code InputStream} from which to read the INI-formatted text</a>
<span class="sourceLineNo">271</span><a id="line.271"> * @throws ConfigurationException if unable</a>
<span class="sourceLineNo">272</span><a id="line.272"> */</a>
<span class="sourceLineNo">273</span><a id="line.273"> public void load(InputStream is) throws ConfigurationException {</a>
<span class="sourceLineNo">274</span><a id="line.274"> if (is == null) {</a>
<span class="sourceLineNo">275</span><a id="line.275"> throw new NullPointerException("InputStream argument cannot be null.");</a>
<span class="sourceLineNo">276</span><a id="line.276"> }</a>
<span class="sourceLineNo">277</span><a id="line.277"> InputStreamReader isr;</a>
<span class="sourceLineNo">278</span><a id="line.278"> try {</a>
<span class="sourceLineNo">279</span><a id="line.279"> isr = new InputStreamReader(is, DEFAULT_CHARSET_NAME);</a>
<span class="sourceLineNo">280</span><a id="line.280"> } catch (UnsupportedEncodingException e) {</a>
<span class="sourceLineNo">281</span><a id="line.281"> throw new ConfigurationException(e);</a>
<span class="sourceLineNo">282</span><a id="line.282"> }</a>
<span class="sourceLineNo">283</span><a id="line.283"> load(isr);</a>
<span class="sourceLineNo">284</span><a id="line.284"> }</a>
<span class="sourceLineNo">285</span><a id="line.285"></a>
<span class="sourceLineNo">286</span><a id="line.286"> /**</a>
<span class="sourceLineNo">287</span><a id="line.287"> * Loads the INI-formatted text backed by the given Reader into this instance. This implementation will close the</a>
<span class="sourceLineNo">288</span><a id="line.288"> * reader after it has finished loading.</a>
<span class="sourceLineNo">289</span><a id="line.289"> *</a>
<span class="sourceLineNo">290</span><a id="line.290"> * @param reader the {@code Reader} from which to read the INI-formatted text</a>
<span class="sourceLineNo">291</span><a id="line.291"> */</a>
<span class="sourceLineNo">292</span><a id="line.292"> public void load(Reader reader) {</a>
<span class="sourceLineNo">293</span><a id="line.293"> Scanner scanner = new Scanner(reader);</a>
<span class="sourceLineNo">294</span><a id="line.294"> try {</a>
<span class="sourceLineNo">295</span><a id="line.295"> load(scanner);</a>
<span class="sourceLineNo">296</span><a id="line.296"> } finally {</a>
<span class="sourceLineNo">297</span><a id="line.297"> try {</a>
<span class="sourceLineNo">298</span><a id="line.298"> scanner.close();</a>
<span class="sourceLineNo">299</span><a id="line.299"> } catch (Exception e) {</a>
<span class="sourceLineNo">300</span><a id="line.300"> log.debug("Unable to cleanly close the InputStream scanner. Non-critical - ignoring.", e);</a>
<span class="sourceLineNo">301</span><a id="line.301"> }</a>
<span class="sourceLineNo">302</span><a id="line.302"> }</a>
<span class="sourceLineNo">303</span><a id="line.303"> }</a>
<span class="sourceLineNo">304</span><a id="line.304"></a>
<span class="sourceLineNo">305</span><a id="line.305"> /**</a>
<span class="sourceLineNo">306</span><a id="line.306"> * Merges the contents of &lt;code&gt;m&lt;/code&gt;'s {@link Section} objects into self.</a>
<span class="sourceLineNo">307</span><a id="line.307"> * This differs from {@link Ini#putAll(Map)}, in that each section is merged with the existing one.</a>
<span class="sourceLineNo">308</span><a id="line.308"> * For example the following two ini blocks are merged and the result is the third&lt;BR/&gt;</a>
<span class="sourceLineNo">309</span><a id="line.309"> * &lt;p&gt;</a>
<span class="sourceLineNo">310</span><a id="line.310"> * Initial:</a>
<span class="sourceLineNo">311</span><a id="line.311"> * &lt;pre&gt;</a>
<span class="sourceLineNo">312</span><a id="line.312"> * &lt;code&gt;[section1]</a>
<span class="sourceLineNo">313</span><a id="line.313"> * key1 = value1</a>
<span class="sourceLineNo">314</span><a id="line.314"> *</a>
<span class="sourceLineNo">315</span><a id="line.315"> * [section2]</a>
<span class="sourceLineNo">316</span><a id="line.316"> * key2 = value2</a>
<span class="sourceLineNo">317</span><a id="line.317"> * &lt;/code&gt; &lt;/pre&gt;</a>
<span class="sourceLineNo">318</span><a id="line.318"> *</a>
<span class="sourceLineNo">319</span><a id="line.319"> * To be merged:</a>
<span class="sourceLineNo">320</span><a id="line.320"> * &lt;pre&gt;</a>
<span class="sourceLineNo">321</span><a id="line.321"> * &lt;code&gt;[section1]</a>
<span class="sourceLineNo">322</span><a id="line.322"> * foo = bar</a>
<span class="sourceLineNo">323</span><a id="line.323"> *</a>
<span class="sourceLineNo">324</span><a id="line.324"> * [section2]</a>
<span class="sourceLineNo">325</span><a id="line.325"> * key2 = new value</a>
<span class="sourceLineNo">326</span><a id="line.326"> * &lt;/code&gt; &lt;/pre&gt;</a>
<span class="sourceLineNo">327</span><a id="line.327"> *</a>
<span class="sourceLineNo">328</span><a id="line.328"> * Result:</a>
<span class="sourceLineNo">329</span><a id="line.329"> * &lt;pre&gt;</a>
<span class="sourceLineNo">330</span><a id="line.330"> * &lt;code&gt;[section1]</a>
<span class="sourceLineNo">331</span><a id="line.331"> * key1 = value1</a>
<span class="sourceLineNo">332</span><a id="line.332"> * foo = bar</a>
<span class="sourceLineNo">333</span><a id="line.333"> *</a>
<span class="sourceLineNo">334</span><a id="line.334"> * [section2]</a>
<span class="sourceLineNo">335</span><a id="line.335"> * key2 = new value</a>
<span class="sourceLineNo">336</span><a id="line.336"> * &lt;/code&gt; &lt;/pre&gt;</a>
<span class="sourceLineNo">337</span><a id="line.337"> *</a>
<span class="sourceLineNo">338</span><a id="line.338"> * &lt;/p&gt;</a>
<span class="sourceLineNo">339</span><a id="line.339"> *</a>
<span class="sourceLineNo">340</span><a id="line.340"> * @param m map to be merged</a>
<span class="sourceLineNo">341</span><a id="line.341"> * @since 1.4</a>
<span class="sourceLineNo">342</span><a id="line.342"> */</a>
<span class="sourceLineNo">343</span><a id="line.343"> public void merge(Map&lt;String, Section&gt; m) {</a>
<span class="sourceLineNo">344</span><a id="line.344"></a>
<span class="sourceLineNo">345</span><a id="line.345"> if (m != null) {</a>
<span class="sourceLineNo">346</span><a id="line.346"> for (Entry&lt;String, Section&gt; entry : m.entrySet()) {</a>
<span class="sourceLineNo">347</span><a id="line.347"> Section section = this.getSection(entry.getKey());</a>
<span class="sourceLineNo">348</span><a id="line.348"> if (section == null) {</a>
<span class="sourceLineNo">349</span><a id="line.349"> section = addSection(entry.getKey());</a>
<span class="sourceLineNo">350</span><a id="line.350"> }</a>
<span class="sourceLineNo">351</span><a id="line.351"> section.putAll(entry.getValue());</a>
<span class="sourceLineNo">352</span><a id="line.352"> }</a>
<span class="sourceLineNo">353</span><a id="line.353"> }</a>
<span class="sourceLineNo">354</span><a id="line.354"> }</a>
<span class="sourceLineNo">355</span><a id="line.355"></a>
<span class="sourceLineNo">356</span><a id="line.356"> private void addSection(String name, StringBuilder content) {</a>
<span class="sourceLineNo">357</span><a id="line.357"> if (content.length() &gt; 0) {</a>
<span class="sourceLineNo">358</span><a id="line.358"> String contentString = content.toString();</a>
<span class="sourceLineNo">359</span><a id="line.359"> String cleaned = StringUtils.clean(contentString);</a>
<span class="sourceLineNo">360</span><a id="line.360"> if (cleaned != null) {</a>
<span class="sourceLineNo">361</span><a id="line.361"> Section section = new Section(name, contentString);</a>
<span class="sourceLineNo">362</span><a id="line.362"> if (!section.isEmpty()) {</a>
<span class="sourceLineNo">363</span><a id="line.363"> sections.put(name, section);</a>
<span class="sourceLineNo">364</span><a id="line.364"> }</a>
<span class="sourceLineNo">365</span><a id="line.365"> }</a>
<span class="sourceLineNo">366</span><a id="line.366"> }</a>
<span class="sourceLineNo">367</span><a id="line.367"> }</a>
<span class="sourceLineNo">368</span><a id="line.368"></a>
<span class="sourceLineNo">369</span><a id="line.369"> /**</a>
<span class="sourceLineNo">370</span><a id="line.370"> * Loads the INI-formatted text backed by the given Scanner. This implementation will close the</a>
<span class="sourceLineNo">371</span><a id="line.371"> * scanner after it has finished loading.</a>
<span class="sourceLineNo">372</span><a id="line.372"> *</a>
<span class="sourceLineNo">373</span><a id="line.373"> * @param scanner the {@code Scanner} from which to read the INI-formatted text</a>
<span class="sourceLineNo">374</span><a id="line.374"> */</a>
<span class="sourceLineNo">375</span><a id="line.375"> public void load(Scanner scanner) {</a>
<span class="sourceLineNo">376</span><a id="line.376"></a>
<span class="sourceLineNo">377</span><a id="line.377"> String sectionName = DEFAULT_SECTION_NAME;</a>
<span class="sourceLineNo">378</span><a id="line.378"> StringBuilder sectionContent = new StringBuilder();</a>
<span class="sourceLineNo">379</span><a id="line.379"></a>
<span class="sourceLineNo">380</span><a id="line.380"> while (scanner.hasNextLine()) {</a>
<span class="sourceLineNo">381</span><a id="line.381"></a>
<span class="sourceLineNo">382</span><a id="line.382"> String rawLine = scanner.nextLine();</a>
<span class="sourceLineNo">383</span><a id="line.383"> String line = StringUtils.clean(rawLine);</a>
<span class="sourceLineNo">384</span><a id="line.384"></a>
<span class="sourceLineNo">385</span><a id="line.385"> if (line == null || line.startsWith(COMMENT_POUND) || line.startsWith(COMMENT_SEMICOLON)) {</a>
<span class="sourceLineNo">386</span><a id="line.386"> //skip empty lines and comments:</a>
<span class="sourceLineNo">387</span><a id="line.387"> continue;</a>
<span class="sourceLineNo">388</span><a id="line.388"> }</a>
<span class="sourceLineNo">389</span><a id="line.389"></a>
<span class="sourceLineNo">390</span><a id="line.390"> String newSectionName = getSectionName(line);</a>
<span class="sourceLineNo">391</span><a id="line.391"> if (newSectionName != null) {</a>
<span class="sourceLineNo">392</span><a id="line.392"> //found a new section - convert the currently buffered one into a Section object</a>
<span class="sourceLineNo">393</span><a id="line.393"> addSection(sectionName, sectionContent);</a>
<span class="sourceLineNo">394</span><a id="line.394"></a>
<span class="sourceLineNo">395</span><a id="line.395"> //reset the buffer for the new section:</a>
<span class="sourceLineNo">396</span><a id="line.396"> sectionContent = new StringBuilder();</a>
<span class="sourceLineNo">397</span><a id="line.397"></a>
<span class="sourceLineNo">398</span><a id="line.398"> sectionName = newSectionName;</a>
<span class="sourceLineNo">399</span><a id="line.399"></a>
<span class="sourceLineNo">400</span><a id="line.400"> if (log.isDebugEnabled()) {</a>
<span class="sourceLineNo">401</span><a id="line.401"> log.debug("Parsing " + SECTION_PREFIX + sectionName + SECTION_SUFFIX);</a>
<span class="sourceLineNo">402</span><a id="line.402"> }</a>
<span class="sourceLineNo">403</span><a id="line.403"> } else {</a>
<span class="sourceLineNo">404</span><a id="line.404"> //normal line - add it to the existing content buffer:</a>
<span class="sourceLineNo">405</span><a id="line.405"> sectionContent.append(rawLine).append("\n");</a>
<span class="sourceLineNo">406</span><a id="line.406"> }</a>
<span class="sourceLineNo">407</span><a id="line.407"> }</a>
<span class="sourceLineNo">408</span><a id="line.408"></a>
<span class="sourceLineNo">409</span><a id="line.409"> //finish any remaining buffered content:</a>
<span class="sourceLineNo">410</span><a id="line.410"> addSection(sectionName, sectionContent);</a>
<span class="sourceLineNo">411</span><a id="line.411"> }</a>
<span class="sourceLineNo">412</span><a id="line.412"></a>
<span class="sourceLineNo">413</span><a id="line.413"> protected static boolean isSectionHeader(String line) {</a>
<span class="sourceLineNo">414</span><a id="line.414"> String s = StringUtils.clean(line);</a>
<span class="sourceLineNo">415</span><a id="line.415"> return s != null &amp;&amp; s.startsWith(SECTION_PREFIX) &amp;&amp; s.endsWith(SECTION_SUFFIX);</a>
<span class="sourceLineNo">416</span><a id="line.416"> }</a>
<span class="sourceLineNo">417</span><a id="line.417"></a>
<span class="sourceLineNo">418</span><a id="line.418"> protected static String getSectionName(String line) {</a>
<span class="sourceLineNo">419</span><a id="line.419"> String s = StringUtils.clean(line);</a>
<span class="sourceLineNo">420</span><a id="line.420"> if (isSectionHeader(s)) {</a>
<span class="sourceLineNo">421</span><a id="line.421"> return cleanName(s.substring(1, s.length() - 1));</a>
<span class="sourceLineNo">422</span><a id="line.422"> }</a>
<span class="sourceLineNo">423</span><a id="line.423"> return null;</a>
<span class="sourceLineNo">424</span><a id="line.424"> }</a>
<span class="sourceLineNo">425</span><a id="line.425"></a>
<span class="sourceLineNo">426</span><a id="line.426"> public boolean equals(Object obj) {</a>
<span class="sourceLineNo">427</span><a id="line.427"> if (obj instanceof Ini) {</a>
<span class="sourceLineNo">428</span><a id="line.428"> Ini ini = (Ini) obj;</a>
<span class="sourceLineNo">429</span><a id="line.429"> return this.sections.equals(ini.sections);</a>
<span class="sourceLineNo">430</span><a id="line.430"> }</a>
<span class="sourceLineNo">431</span><a id="line.431"> return false;</a>
<span class="sourceLineNo">432</span><a id="line.432"> }</a>
<span class="sourceLineNo">433</span><a id="line.433"></a>
<span class="sourceLineNo">434</span><a id="line.434"> @Override</a>
<span class="sourceLineNo">435</span><a id="line.435"> public int hashCode() {</a>
<span class="sourceLineNo">436</span><a id="line.436"> return this.sections.hashCode();</a>
<span class="sourceLineNo">437</span><a id="line.437"> }</a>
<span class="sourceLineNo">438</span><a id="line.438"></a>
<span class="sourceLineNo">439</span><a id="line.439"> public String toString() {</a>
<span class="sourceLineNo">440</span><a id="line.440"> if (this.sections == null || this.sections.isEmpty()) {</a>
<span class="sourceLineNo">441</span><a id="line.441"> return "&lt;empty INI&gt;";</a>
<span class="sourceLineNo">442</span><a id="line.442"> } else {</a>
<span class="sourceLineNo">443</span><a id="line.443"> StringBuilder sb = new StringBuilder("sections=");</a>
<span class="sourceLineNo">444</span><a id="line.444"> int i = 0;</a>
<span class="sourceLineNo">445</span><a id="line.445"> for (Ini.Section section : this.sections.values()) {</a>
<span class="sourceLineNo">446</span><a id="line.446"> if (i &gt; 0) {</a>
<span class="sourceLineNo">447</span><a id="line.447"> sb.append(",");</a>
<span class="sourceLineNo">448</span><a id="line.448"> }</a>
<span class="sourceLineNo">449</span><a id="line.449"> sb.append(section.toString());</a>
<span class="sourceLineNo">450</span><a id="line.450"> i++;</a>
<span class="sourceLineNo">451</span><a id="line.451"> }</a>
<span class="sourceLineNo">452</span><a id="line.452"> return sb.toString();</a>
<span class="sourceLineNo">453</span><a id="line.453"> }</a>
<span class="sourceLineNo">454</span><a id="line.454"> }</a>
<span class="sourceLineNo">455</span><a id="line.455"></a>
<span class="sourceLineNo">456</span><a id="line.456"> public int size() {</a>
<span class="sourceLineNo">457</span><a id="line.457"> return this.sections.size();</a>
<span class="sourceLineNo">458</span><a id="line.458"> }</a>
<span class="sourceLineNo">459</span><a id="line.459"></a>
<span class="sourceLineNo">460</span><a id="line.460"> public boolean containsKey(Object key) {</a>
<span class="sourceLineNo">461</span><a id="line.461"> return this.sections.containsKey(key);</a>
<span class="sourceLineNo">462</span><a id="line.462"> }</a>
<span class="sourceLineNo">463</span><a id="line.463"></a>
<span class="sourceLineNo">464</span><a id="line.464"> public boolean containsValue(Object value) {</a>
<span class="sourceLineNo">465</span><a id="line.465"> return this.sections.containsValue(value);</a>
<span class="sourceLineNo">466</span><a id="line.466"> }</a>
<span class="sourceLineNo">467</span><a id="line.467"></a>
<span class="sourceLineNo">468</span><a id="line.468"> public Section get(Object key) {</a>
<span class="sourceLineNo">469</span><a id="line.469"> return this.sections.get(key);</a>
<span class="sourceLineNo">470</span><a id="line.470"> }</a>
<span class="sourceLineNo">471</span><a id="line.471"></a>
<span class="sourceLineNo">472</span><a id="line.472"> public Section put(String key, Section value) {</a>
<span class="sourceLineNo">473</span><a id="line.473"> return this.sections.put(key, value);</a>
<span class="sourceLineNo">474</span><a id="line.474"> }</a>
<span class="sourceLineNo">475</span><a id="line.475"></a>
<span class="sourceLineNo">476</span><a id="line.476"> public Section remove(Object key) {</a>
<span class="sourceLineNo">477</span><a id="line.477"> return this.sections.remove(key);</a>
<span class="sourceLineNo">478</span><a id="line.478"> }</a>
<span class="sourceLineNo">479</span><a id="line.479"></a>
<span class="sourceLineNo">480</span><a id="line.480"> public void putAll(Map&lt;? extends String, ? extends Section&gt; m) {</a>
<span class="sourceLineNo">481</span><a id="line.481"> this.sections.putAll(m);</a>
<span class="sourceLineNo">482</span><a id="line.482"> }</a>
<span class="sourceLineNo">483</span><a id="line.483"></a>
<span class="sourceLineNo">484</span><a id="line.484"> public void clear() {</a>
<span class="sourceLineNo">485</span><a id="line.485"> this.sections.clear();</a>
<span class="sourceLineNo">486</span><a id="line.486"> }</a>
<span class="sourceLineNo">487</span><a id="line.487"></a>
<span class="sourceLineNo">488</span><a id="line.488"> public Set&lt;String&gt; keySet() {</a>
<span class="sourceLineNo">489</span><a id="line.489"> return Collections.unmodifiableSet(this.sections.keySet());</a>
<span class="sourceLineNo">490</span><a id="line.490"> }</a>
<span class="sourceLineNo">491</span><a id="line.491"></a>
<span class="sourceLineNo">492</span><a id="line.492"> public Collection&lt;Section&gt; values() {</a>
<span class="sourceLineNo">493</span><a id="line.493"> return Collections.unmodifiableCollection(this.sections.values());</a>
<span class="sourceLineNo">494</span><a id="line.494"> }</a>
<span class="sourceLineNo">495</span><a id="line.495"></a>
<span class="sourceLineNo">496</span><a id="line.496"> public Set&lt;Entry&lt;String, Section&gt;&gt; entrySet() {</a>
<span class="sourceLineNo">497</span><a id="line.497"> return Collections.unmodifiableSet(this.sections.entrySet());</a>
<span class="sourceLineNo">498</span><a id="line.498"> }</a>
<span class="sourceLineNo">499</span><a id="line.499"></a>
<span class="sourceLineNo">500</span><a id="line.500"> /**</a>
<span class="sourceLineNo">501</span><a id="line.501"> * An {@code Ini.Section} is String-key-to-String-value Map, identifiable by a</a>
<span class="sourceLineNo">502</span><a id="line.502"> * {@link #getName() name} unique within an {@link Ini} instance.</a>
<span class="sourceLineNo">503</span><a id="line.503"> */</a>
<span class="sourceLineNo">504</span><a id="line.504"> public static class Section implements Map&lt;String, String&gt; {</a>
<span class="sourceLineNo">505</span><a id="line.505"> private final String name;</a>
<span class="sourceLineNo">506</span><a id="line.506"> private final Map&lt;String, String&gt; props;</a>
<span class="sourceLineNo">507</span><a id="line.507"></a>
<span class="sourceLineNo">508</span><a id="line.508"> private Section(String name) {</a>
<span class="sourceLineNo">509</span><a id="line.509"> if (name == null) {</a>
<span class="sourceLineNo">510</span><a id="line.510"> throw new NullPointerException("name");</a>
<span class="sourceLineNo">511</span><a id="line.511"> }</a>
<span class="sourceLineNo">512</span><a id="line.512"> this.name = name;</a>
<span class="sourceLineNo">513</span><a id="line.513"> this.props = new LinkedHashMap&lt;String, String&gt;();</a>
<span class="sourceLineNo">514</span><a id="line.514"> }</a>
<span class="sourceLineNo">515</span><a id="line.515"></a>
<span class="sourceLineNo">516</span><a id="line.516"> private Section(String name, String sectionContent) {</a>
<span class="sourceLineNo">517</span><a id="line.517"> if (name == null) {</a>
<span class="sourceLineNo">518</span><a id="line.518"> throw new NullPointerException("name");</a>
<span class="sourceLineNo">519</span><a id="line.519"> }</a>
<span class="sourceLineNo">520</span><a id="line.520"> this.name = name;</a>
<span class="sourceLineNo">521</span><a id="line.521"> Map&lt;String,String&gt; props;</a>
<span class="sourceLineNo">522</span><a id="line.522"> if (StringUtils.hasText(sectionContent) ) {</a>
<span class="sourceLineNo">523</span><a id="line.523"> props = toMapProps(sectionContent);</a>
<span class="sourceLineNo">524</span><a id="line.524"> } else {</a>
<span class="sourceLineNo">525</span><a id="line.525"> props = new LinkedHashMap&lt;String,String&gt;();</a>
<span class="sourceLineNo">526</span><a id="line.526"> }</a>
<span class="sourceLineNo">527</span><a id="line.527"> if ( props != null ) {</a>
<span class="sourceLineNo">528</span><a id="line.528"> this.props = props;</a>
<span class="sourceLineNo">529</span><a id="line.529"> } else {</a>
<span class="sourceLineNo">530</span><a id="line.530"> this.props = new LinkedHashMap&lt;String,String&gt;();</a>
<span class="sourceLineNo">531</span><a id="line.531"> }</a>
<span class="sourceLineNo">532</span><a id="line.532"> }</a>
<span class="sourceLineNo">533</span><a id="line.533"></a>
<span class="sourceLineNo">534</span><a id="line.534"> private Section(Section defaults) {</a>
<span class="sourceLineNo">535</span><a id="line.535"> this(defaults.getName());</a>
<span class="sourceLineNo">536</span><a id="line.536"> putAll(defaults.props);</a>
<span class="sourceLineNo">537</span><a id="line.537"> }</a>
<span class="sourceLineNo">538</span><a id="line.538"></a>
<span class="sourceLineNo">539</span><a id="line.539"> //Protected to access in a test case - NOT considered part of Shiro's public API</a>
<span class="sourceLineNo">540</span><a id="line.540"></a>
<span class="sourceLineNo">541</span><a id="line.541"> protected static boolean isContinued(String line) {</a>
<span class="sourceLineNo">542</span><a id="line.542"> if (!StringUtils.hasText(line)) {</a>
<span class="sourceLineNo">543</span><a id="line.543"> return false;</a>
<span class="sourceLineNo">544</span><a id="line.544"> }</a>
<span class="sourceLineNo">545</span><a id="line.545"> int length = line.length();</a>
<span class="sourceLineNo">546</span><a id="line.546"> //find the number of backslashes at the end of the line. If an even number, the</a>
<span class="sourceLineNo">547</span><a id="line.547"> //backslashes are considered escaped. If an odd number, the line is considered continued on the next line</a>
<span class="sourceLineNo">548</span><a id="line.548"> int backslashCount = 0;</a>
<span class="sourceLineNo">549</span><a id="line.549"> for (int i = length - 1; i &gt; 0; i--) {</a>
<span class="sourceLineNo">550</span><a id="line.550"> if (line.charAt(i) == ESCAPE_TOKEN) {</a>
<span class="sourceLineNo">551</span><a id="line.551"> backslashCount++;</a>
<span class="sourceLineNo">552</span><a id="line.552"> } else {</a>
<span class="sourceLineNo">553</span><a id="line.553"> break;</a>
<span class="sourceLineNo">554</span><a id="line.554"> }</a>
<span class="sourceLineNo">555</span><a id="line.555"> }</a>
<span class="sourceLineNo">556</span><a id="line.556"> return backslashCount % 2 != 0;</a>
<span class="sourceLineNo">557</span><a id="line.557"> }</a>
<span class="sourceLineNo">558</span><a id="line.558"></a>
<span class="sourceLineNo">559</span><a id="line.559"> private static boolean isKeyValueSeparatorChar(char c) {</a>
<span class="sourceLineNo">560</span><a id="line.560"> return Character.isWhitespace(c) || c == ':' || c == '=';</a>
<span class="sourceLineNo">561</span><a id="line.561"> }</a>
<span class="sourceLineNo">562</span><a id="line.562"></a>
<span class="sourceLineNo">563</span><a id="line.563"> private static boolean isCharEscaped(CharSequence s, int index) {</a>
<span class="sourceLineNo">564</span><a id="line.564"> return index &gt; 0 &amp;&amp; s.charAt(index) == ESCAPE_TOKEN;</a>
<span class="sourceLineNo">565</span><a id="line.565"> }</a>
<span class="sourceLineNo">566</span><a id="line.566"></a>
<span class="sourceLineNo">567</span><a id="line.567"> //Protected to access in a test case - NOT considered part of Shiro's public API</a>
<span class="sourceLineNo">568</span><a id="line.568"> protected static String[] splitKeyValue(String keyValueLine) {</a>
<span class="sourceLineNo">569</span><a id="line.569"> String line = StringUtils.clean(keyValueLine);</a>
<span class="sourceLineNo">570</span><a id="line.570"> if (line == null) {</a>
<span class="sourceLineNo">571</span><a id="line.571"> return null;</a>
<span class="sourceLineNo">572</span><a id="line.572"> }</a>
<span class="sourceLineNo">573</span><a id="line.573"> StringBuilder keyBuffer = new StringBuilder();</a>
<span class="sourceLineNo">574</span><a id="line.574"> StringBuilder valueBuffer = new StringBuilder();</a>
<span class="sourceLineNo">575</span><a id="line.575"></a>
<span class="sourceLineNo">576</span><a id="line.576"> boolean buildingKey = true; //we'll build the value next:</a>
<span class="sourceLineNo">577</span><a id="line.577"></a>
<span class="sourceLineNo">578</span><a id="line.578"> for (int i = 0; i &lt; line.length(); i++) {</a>
<span class="sourceLineNo">579</span><a id="line.579"> char c = line.charAt(i);</a>
<span class="sourceLineNo">580</span><a id="line.580"></a>
<span class="sourceLineNo">581</span><a id="line.581"> if (buildingKey) {</a>
<span class="sourceLineNo">582</span><a id="line.582"> if (isKeyValueSeparatorChar(c) &amp;&amp; !isCharEscaped(line, i)) {</a>
<span class="sourceLineNo">583</span><a id="line.583"> buildingKey = false;//now start building the value</a>
<span class="sourceLineNo">584</span><a id="line.584"> } else if (!isCharEscaped(line, i)){</a>
<span class="sourceLineNo">585</span><a id="line.585"> keyBuffer.append(c);</a>
<span class="sourceLineNo">586</span><a id="line.586"> }</a>
<span class="sourceLineNo">587</span><a id="line.587"> } else {</a>
<span class="sourceLineNo">588</span><a id="line.588"> if (valueBuffer.length() == 0 &amp;&amp; isKeyValueSeparatorChar(c) &amp;&amp; !isCharEscaped(line, i)) {</a>
<span class="sourceLineNo">589</span><a id="line.589"> //swallow the separator chars before we start building the value</a>
<span class="sourceLineNo">590</span><a id="line.590"> } else if (!isCharEscaped(line, i)){</a>
<span class="sourceLineNo">591</span><a id="line.591"> valueBuffer.append(c);</a>
<span class="sourceLineNo">592</span><a id="line.592"> }</a>
<span class="sourceLineNo">593</span><a id="line.593"> }</a>
<span class="sourceLineNo">594</span><a id="line.594"> }</a>
<span class="sourceLineNo">595</span><a id="line.595"></a>
<span class="sourceLineNo">596</span><a id="line.596"> String key = StringUtils.clean(keyBuffer.toString());</a>
<span class="sourceLineNo">597</span><a id="line.597"> String value = StringUtils.clean(valueBuffer.toString());</a>
<span class="sourceLineNo">598</span><a id="line.598"></a>
<span class="sourceLineNo">599</span><a id="line.599"> if (key == null || value == null) {</a>
<span class="sourceLineNo">600</span><a id="line.600"> String msg = "Line argument must contain a key and a value. Only one string token was found.";</a>
<span class="sourceLineNo">601</span><a id="line.601"> throw new IllegalArgumentException(msg);</a>
<span class="sourceLineNo">602</span><a id="line.602"> }</a>
<span class="sourceLineNo">603</span><a id="line.603"></a>
<span class="sourceLineNo">604</span><a id="line.604"> log.trace("Discovered key/value pair: {} = {}", key, value);</a>
<span class="sourceLineNo">605</span><a id="line.605"></a>
<span class="sourceLineNo">606</span><a id="line.606"> return new String[]{key, value};</a>
<span class="sourceLineNo">607</span><a id="line.607"> }</a>
<span class="sourceLineNo">608</span><a id="line.608"></a>
<span class="sourceLineNo">609</span><a id="line.609"> private static Map&lt;String, String&gt; toMapProps(String content) {</a>
<span class="sourceLineNo">610</span><a id="line.610"> Map&lt;String, String&gt; props = new LinkedHashMap&lt;String, String&gt;();</a>
<span class="sourceLineNo">611</span><a id="line.611"> String line;</a>
<span class="sourceLineNo">612</span><a id="line.612"> StringBuilder lineBuffer = new StringBuilder();</a>
<span class="sourceLineNo">613</span><a id="line.613"> Scanner scanner = new Scanner(content);</a>
<span class="sourceLineNo">614</span><a id="line.614"> while (scanner.hasNextLine()) {</a>
<span class="sourceLineNo">615</span><a id="line.615"> line = StringUtils.clean(scanner.nextLine());</a>
<span class="sourceLineNo">616</span><a id="line.616"> if (isContinued(line)) {</a>
<span class="sourceLineNo">617</span><a id="line.617"> //strip off the last continuation backslash:</a>
<span class="sourceLineNo">618</span><a id="line.618"> line = line.substring(0, line.length() - 1);</a>
<span class="sourceLineNo">619</span><a id="line.619"> lineBuffer.append(line);</a>
<span class="sourceLineNo">620</span><a id="line.620"> continue;</a>
<span class="sourceLineNo">621</span><a id="line.621"> } else {</a>
<span class="sourceLineNo">622</span><a id="line.622"> lineBuffer.append(line);</a>
<span class="sourceLineNo">623</span><a id="line.623"> }</a>
<span class="sourceLineNo">624</span><a id="line.624"> line = lineBuffer.toString();</a>
<span class="sourceLineNo">625</span><a id="line.625"> lineBuffer = new StringBuilder();</a>
<span class="sourceLineNo">626</span><a id="line.626"> String[] kvPair = splitKeyValue(line);</a>
<span class="sourceLineNo">627</span><a id="line.627"> props.put(kvPair[0], kvPair[1]);</a>
<span class="sourceLineNo">628</span><a id="line.628"> }</a>
<span class="sourceLineNo">629</span><a id="line.629"></a>
<span class="sourceLineNo">630</span><a id="line.630"> return props;</a>
<span class="sourceLineNo">631</span><a id="line.631"> }</a>
<span class="sourceLineNo">632</span><a id="line.632"></a>
<span class="sourceLineNo">633</span><a id="line.633"> public String getName() {</a>
<span class="sourceLineNo">634</span><a id="line.634"> return this.name;</a>
<span class="sourceLineNo">635</span><a id="line.635"> }</a>
<span class="sourceLineNo">636</span><a id="line.636"></a>
<span class="sourceLineNo">637</span><a id="line.637"> public void clear() {</a>
<span class="sourceLineNo">638</span><a id="line.638"> this.props.clear();</a>
<span class="sourceLineNo">639</span><a id="line.639"> }</a>
<span class="sourceLineNo">640</span><a id="line.640"></a>
<span class="sourceLineNo">641</span><a id="line.641"> public boolean containsKey(Object key) {</a>
<span class="sourceLineNo">642</span><a id="line.642"> return this.props.containsKey(key);</a>
<span class="sourceLineNo">643</span><a id="line.643"> }</a>
<span class="sourceLineNo">644</span><a id="line.644"></a>
<span class="sourceLineNo">645</span><a id="line.645"> public boolean containsValue(Object value) {</a>
<span class="sourceLineNo">646</span><a id="line.646"> return this.props.containsValue(value);</a>
<span class="sourceLineNo">647</span><a id="line.647"> }</a>
<span class="sourceLineNo">648</span><a id="line.648"></a>
<span class="sourceLineNo">649</span><a id="line.649"> public Set&lt;Entry&lt;String, String&gt;&gt; entrySet() {</a>
<span class="sourceLineNo">650</span><a id="line.650"> return this.props.entrySet();</a>
<span class="sourceLineNo">651</span><a id="line.651"> }</a>
<span class="sourceLineNo">652</span><a id="line.652"></a>
<span class="sourceLineNo">653</span><a id="line.653"> public String get(Object key) {</a>
<span class="sourceLineNo">654</span><a id="line.654"> return this.props.get(key);</a>
<span class="sourceLineNo">655</span><a id="line.655"> }</a>
<span class="sourceLineNo">656</span><a id="line.656"></a>
<span class="sourceLineNo">657</span><a id="line.657"> public boolean isEmpty() {</a>
<span class="sourceLineNo">658</span><a id="line.658"> return this.props.isEmpty();</a>
<span class="sourceLineNo">659</span><a id="line.659"> }</a>
<span class="sourceLineNo">660</span><a id="line.660"></a>
<span class="sourceLineNo">661</span><a id="line.661"> public Set&lt;String&gt; keySet() {</a>
<span class="sourceLineNo">662</span><a id="line.662"> return this.props.keySet();</a>
<span class="sourceLineNo">663</span><a id="line.663"> }</a>
<span class="sourceLineNo">664</span><a id="line.664"></a>
<span class="sourceLineNo">665</span><a id="line.665"> public String put(String key, String value) {</a>
<span class="sourceLineNo">666</span><a id="line.666"> return this.props.put(key, value);</a>
<span class="sourceLineNo">667</span><a id="line.667"> }</a>
<span class="sourceLineNo">668</span><a id="line.668"></a>
<span class="sourceLineNo">669</span><a id="line.669"> public void putAll(Map&lt;? extends String, ? extends String&gt; m) {</a>
<span class="sourceLineNo">670</span><a id="line.670"> this.props.putAll(m);</a>
<span class="sourceLineNo">671</span><a id="line.671"> }</a>
<span class="sourceLineNo">672</span><a id="line.672"></a>
<span class="sourceLineNo">673</span><a id="line.673"> public String remove(Object key) {</a>
<span class="sourceLineNo">674</span><a id="line.674"> return this.props.remove(key);</a>
<span class="sourceLineNo">675</span><a id="line.675"> }</a>
<span class="sourceLineNo">676</span><a id="line.676"></a>
<span class="sourceLineNo">677</span><a id="line.677"> public int size() {</a>
<span class="sourceLineNo">678</span><a id="line.678"> return this.props.size();</a>
<span class="sourceLineNo">679</span><a id="line.679"> }</a>
<span class="sourceLineNo">680</span><a id="line.680"></a>
<span class="sourceLineNo">681</span><a id="line.681"> public Collection&lt;String&gt; values() {</a>
<span class="sourceLineNo">682</span><a id="line.682"> return this.props.values();</a>
<span class="sourceLineNo">683</span><a id="line.683"> }</a>
<span class="sourceLineNo">684</span><a id="line.684"></a>
<span class="sourceLineNo">685</span><a id="line.685"> public String toString() {</a>
<span class="sourceLineNo">686</span><a id="line.686"> String name = getName();</a>
<span class="sourceLineNo">687</span><a id="line.687"> if (DEFAULT_SECTION_NAME.equals(name)) {</a>
<span class="sourceLineNo">688</span><a id="line.688"> return "&lt;default&gt;";</a>
<span class="sourceLineNo">689</span><a id="line.689"> }</a>
<span class="sourceLineNo">690</span><a id="line.690"> return name;</a>
<span class="sourceLineNo">691</span><a id="line.691"> }</a>
<span class="sourceLineNo">692</span><a id="line.692"></a>
<span class="sourceLineNo">693</span><a id="line.693"> @Override</a>
<span class="sourceLineNo">694</span><a id="line.694"> public boolean equals(Object obj) {</a>
<span class="sourceLineNo">695</span><a id="line.695"> if (obj instanceof Section) {</a>
<span class="sourceLineNo">696</span><a id="line.696"> Section other = (Section) obj;</a>
<span class="sourceLineNo">697</span><a id="line.697"> return getName().equals(other.getName()) &amp;&amp; this.props.equals(other.props);</a>
<span class="sourceLineNo">698</span><a id="line.698"> }</a>
<span class="sourceLineNo">699</span><a id="line.699"> return false;</a>
<span class="sourceLineNo">700</span><a id="line.700"> }</a>
<span class="sourceLineNo">701</span><a id="line.701"></a>
<span class="sourceLineNo">702</span><a id="line.702"> @Override</a>
<span class="sourceLineNo">703</span><a id="line.703"> public int hashCode() {</a>
<span class="sourceLineNo">704</span><a id="line.704"> return this.name.hashCode() * 31 + this.props.hashCode();</a>
<span class="sourceLineNo">705</span><a id="line.705"> }</a>
<span class="sourceLineNo">706</span><a id="line.706"> }</a>
<span class="sourceLineNo">707</span><a id="line.707"></a>
<span class="sourceLineNo">708</span><a id="line.708">}</a>
</pre>
</div>
</main>
</body>
</html>