##### Coverage Report - org.apache.commons.configuration.plist.PropertyListConfiguration

Classes in this File | Line Coverage | Branch Coverage | Complexity

PropertyListConfiguration

80% | 66/83

95% | 19/20

3.5555555555555554;3,556

1

     /*

2

      * Licensed to the Apache Software Foundation (ASF) under one or more

3

      * contributor license agreements.  See the NOTICE file distributed with

4

      * this work for additional information regarding copyright ownership.

5

      * The ASF licenses this file to You under the Apache License, Version 2.0

6

      * (the "License"); you may not use this file except in compliance with

7

      * the License.  You may obtain a copy of the License at

8

      *

9

      *     http://www.apache.org/licenses/LICENSE-2.0

10

      *

11

      * Unless required by applicable law or agreed to in writing, software

12

      * distributed under the License is distributed on an "AS IS" BASIS,

13

      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

14

      * See the License for the specific language governing permissions and

15

      * limitations under the License.

16

      */

17

18

     package org.apache.commons.configuration.plist;

19

20

     import java.io.File;

21

     import java.io.PrintWriter;

22

     import java.io.Reader;

23

     import java.io.Writer;

24

     import java.net.URL;

25

     import java.util.ArrayList;

26

     import java.util.Iterator;

27

     import java.util.List;

28

     import java.util.Map;

29

30

     import org.apache.commons.codec.binary.Hex;

31

     import org.apache.commons.configuration.AbstractHierarchicalFileConfiguration;

32

     import org.apache.commons.configuration.Configuration;

33

     import org.apache.commons.configuration.ConfigurationException;

34

     import org.apache.commons.configuration.HierarchicalConfiguration;

35

     import org.apache.commons.configuration.MapConfiguration;

36

     import org.apache.commons.lang.StringUtils;

37

38

     /**

39

      * NeXT / OpenStep style configuration.

40

      * (http://developer.apple.com/documentation/Cocoa/Conceptual/PropertyLists/Concepts/OldStylePListsConcept.html)

41

      *

42

      * <p>Example:</p>

43

      * <pre>

44

      * {

45

      *     foo = "bar";

46

      *

47

      *     array = ( value1, value2, value3 );

48

      *

49

      *     data = &lt;4f3e0145ab>;

50

      *

51

      *     nested =

52

      *     {

53

      *         key1 = value1;

54

      *         key2 = value;

55

      *         nested =

56

      *         {

57

      *             foo = bar

58

      *         }

59

      *     }

60

      * }

61

      * </pre>

62

      *

63

      * @since 1.2

64

      *

65

      * @author Emmanuel Bourg

66

      * @version $Revision: 439648 $, $Date: 2006-09-02 22:42:10 +0200 (Sa, 02 Sep 2006) $

67

      */

68

     public class PropertyListConfiguration extends AbstractHierarchicalFileConfiguration

69

     {

70

         /**

71

          * The serial version UID.

72

          */

73

         private static final long serialVersionUID = 3227248503779092127L;

74

75

         /** Size of the indentation for the generated file. */

76

         private static final int INDENT_SIZE = 4;

77

78

         /**

79

          * Creates an empty PropertyListConfiguration object which can be

80

          * used to synthesize a new plist file by adding values and

81

          * then saving().

82

          */

83

         public PropertyListConfiguration()

84

126

         {

85

126

         }

86

87

         /**

88

          * Creates and loads the property list from the specified file.

89

          *

90

          * @param fileName The name of the plist file to load.

91

          * @throws ConfigurationException Error while loading the plist file

92

          */

93

         public PropertyListConfiguration(String fileName) throws ConfigurationException

94

         {

95

0

             super(fileName);

96

0

         }

97

98

         /**

99

          * Creates and loads the property list from the specified file.

100

          *

101

          * @param file The plist file to load.

102

          * @throws ConfigurationException Error while loading the plist file

103

          */

104

         public PropertyListConfiguration(File file) throws ConfigurationException

105

         {

106

1

             super(file);

107

1

         }

108

109

         /**

110

          * Creates and loads the property list from the specified URL.

111

          *

112

          * @param url The location of the plist file to load.

113

          * @throws ConfigurationException Error while loading the plist file

114

          */

115

         public PropertyListConfiguration(URL url) throws ConfigurationException

116

         {

117

0

             super(url);

118

0

         }

119

120

         public void load(Reader in) throws ConfigurationException

121

         {

122

15

             PropertyListParser parser = new PropertyListParser(in);

123

             try

124

             {

125

126

15

                 HierarchicalConfiguration config = parser.parse();

127

14

                 setRoot(config.getRoot());

128

14

             }

129

             catch (ParseException e)

130

             {

131

1

                 throw new ConfigurationException(e);

132

             }

133

14

         }

134

135

         public void save(Writer out) throws ConfigurationException

136

         {

137

1

             PrintWriter writer = new PrintWriter(out);

138

1

             printNode(writer, 0, getRoot());

139

1

             writer.flush();

140

1

         }

141

142

         /**

143

          * Append a node to the writer, indented according to a specific level.

144

          */

145

         private void printNode(PrintWriter out, int indentLevel, Node node)

146

         {

147

22

             String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE);

148

149

22

             if (node.getName() != null)

150

             {

151

19

                 out.print(padding + quoteString(node.getName()) + " = ");

152

             }

153

154

             // get all non trivial nodes

155

22

             List children = new ArrayList(node.getChildren());

156

22

             Iterator it = children.iterator();

157

64

             while (it.hasNext())

158

             {

159

20

                 Node child = (Node) it.next();

160

20

                 if (child.getValue() == null && (child.getChildren() == null || child.getChildren().isEmpty()))

161

                 {

162

1

                     it.remove();

163

                 }

164

             }

165

166

22

             if (!children.isEmpty())

167

             {

168

                 // skip a line, except for the root dictionary

169

7

                 if (indentLevel > 0)

170

                 {

171

6

                     out.println();

172

                 }

173

174

7

                 out.println(padding + "{");

175

176

                 // display the children

177

7

                 it = children.iterator();

178

33

                 while (it.hasNext())

179

                 {

180

19

                     Node child = (Node) it.next();

181

182

19

                     printNode(out, indentLevel + 1, child);

183

184

                     // add a semi colon for elements that are not dictionaries

185

19

                     Object value = child.getValue();

186

19

                     if (value != null && !(value instanceof Map) && !(value instanceof Configuration))

187

                     {

188

15

                         out.println(";");

189

                     }

190

191

                     // skip a line after arrays and dictionaries

192

19

                     if (it.hasNext() && (value == null || value instanceof List))

193

                     {

194

6

                         out.println();

195

                     }

196

                 }

197

198

7

                 out.print(padding + "}");

199

200

                 // line feed if the dictionary is not in an array

201

7

                 if (node.getParent() != null)

202

                 {

203

4

                     out.println();

204

                 }

205

             }

206

             else

207

             {

208

                 // display the leaf value

209

15

                 Object value = node.getValue();

210

15

                 printValue(out, indentLevel, value);

211

             }

212

22

         }

213

214

         /**

215

          * Append a value to the writer, indented according to a specific level.

216

          */

217

         private void printValue(PrintWriter out, int indentLevel, Object value)

218

         {

219

26

             String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE);

220

221

26

             if (value instanceof List)

222

             {

223

6

                 out.print("( ");

224

6

                 Iterator it = ((List) value).iterator();

225

23

                 while (it.hasNext())

226

                 {

227

11

                     printValue(out, indentLevel + 1, it.next());

228

11

                     if (it.hasNext())

229

                     {

230

6

                         out.print(", ");

231

                     }

232

                 }

233

6

                 out.print(" )");

234

             }

235

20

             else if (value instanceof HierarchicalConfiguration)

236

             {

237

2

                 printNode(out, indentLevel, ((HierarchicalConfiguration) value).getRoot());

238

             }

239

18

             else if (value instanceof Configuration)

240

             {

241

                 // display a flat Configuration as a dictionary

242

0

                 out.println();

243

0

                 out.println(padding + "{");

244

245

0

                 Configuration config = (Configuration) value;

246

0

                 Iterator it = config.getKeys();

247

0

                 while (it.hasNext())

248

                 {

249

0

                     String key = (String) it.next();

250

0

                     Node node = new Node(key);

251

0

                     node.setValue(config.getProperty(key));

252

253

0

                     printNode(out, indentLevel + 1, node);

254

0

                     out.println(";");

255

                 }

256

0

                 out.println(padding + "}");

257

             }

258

18

             else if (value instanceof Map)

259

             {

260

                 // display a Map as a dictionary

261

0

                 Map map = (Map) value;

262

0

                 printValue(out, indentLevel, new MapConfiguration(map));

263

             }

264

18

             else if (value instanceof byte[])

265

             {

266

2

                 out.print("<" + new String(Hex.encodeHex((byte[]) value)) + ">");

267

             }

268

16

             else if (value != null)

269

             {

270

16

                 out.print(quoteString(String.valueOf(value)));

271

             }

272

26

         }

273

274

         /**

275

          * Quote the specified string if necessary, that's if the string contains:

276

          * <ul>

277

          *   <li>a space character (' ', '\t', '\r', '\n')</li>

278

          *   <li>a quote '"'</li>

279

          *   <li>special characters in plist files ('(', ')', '{', '}', '=', ';', ',')</li>

280

          * </ul>

281

          * Quotes within the string are escaped.

282

          *

283

          * <p>Examples:</p>

284

          * <ul>

285

          *   <li>abcd -> abcd</li>

286

          *   <li>ab cd -> "ab cd"</li>

287

          *   <li>foo"bar -> "foo\"bar"</li>

288

          *   <li>foo;bar -> "foo;bar"</li>

289

          * </ul>

290

          */

291

         String quoteString(String s)

292

         {

293

40

             if (s == null)

294

             {

295

1

                 return null;

296

             }

297

298

39

             if (s.indexOf(' ') != -1

299

                     || s.indexOf('\t') != -1

300

                     || s.indexOf('\r') != -1

301

                     || s.indexOf('\n') != -1

302

                     || s.indexOf('"') != -1

303

                     || s.indexOf('(') != -1

304

                     || s.indexOf(')') != -1

305

                     || s.indexOf('{') != -1

306

                     || s.indexOf('}') != -1

307

                     || s.indexOf('=') != -1

308

                     || s.indexOf(',') != -1

309

                     || s.indexOf(';') != -1)

310

             {

311

5

                 s = StringUtils.replace(s, "\"", "\\\"");

312

5

                 s = "\"" + s + "\"";

313

             }

314

315

39

             return s;

316

         }

317

     }