##### Coverage Report - org.apache.commons.configuration.ConfigurationUtils

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

ConfigurationUtils

92% | 136/148

100% | 37/37

4.722222222222222;4,722

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;

19

20

     import java.io.File;

21

     import java.io.IOException;

22

     import java.io.InputStream;

23

     import java.io.PrintStream;

24

     import java.io.PrintWriter;

25

     import java.io.StringWriter;

26

     import java.lang.reflect.InvocationTargetException;

27

     import java.lang.reflect.Method;

28

     import java.net.MalformedURLException;

29

     import java.net.URL;

30

     import java.net.URLDecoder;

31

     import java.util.Iterator;

32

33

     import org.apache.commons.lang.StringUtils;

34

     import org.apache.commons.logging.Log;

35

     import org.apache.commons.logging.LogFactory;

36

37

     /**

38

      * Miscellaneous utility methods for configurations.

39

      *

40

      * @see ConfigurationConverter Utility methods to convert configurations.

41

      *

42

      * @author <a href="mailto:herve.quiroz@esil.univ-mrs.fr">Herve Quiroz</a>

43

      * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>

44

      * @author Emmanuel Bourg

45

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

46

      */

47

28

     public final class ConfigurationUtils

48

     {

49

         /** Constant for the file URL protocol.*/

50

         static final String PROTOCOL_FILE = "file";

51

52

         /** Constant for the resource path separator.*/

53

         static final String RESOURCE_PATH_SEPARATOR = "/";

54

55

         /** Constant for the name of the clone() method.*/

56

         private static final String METHOD_CLONE = "clone";

57

58

         /** The logger.*/

59

28

         private static Log log = LogFactory.getLog(ConfigurationUtils.class);

60

61

         /**

62

          * Private constructor. Prevents instances from being created.

63

          */

64

         private ConfigurationUtils()

65

0

         {

66

             // to prevent instanciation...

67

0

         }

68

69

         /**

70

          * Dump the configuration key/value mappings to some ouput stream.

71

          *

72

          * @param configuration the configuration

73

          * @param out the output stream to dump the configuration to

74

          */

75

         public static void dump(Configuration configuration, PrintStream out)

76

         {

77

0

             dump(configuration, new PrintWriter(out));

78

0

         }

79

80

         /**

81

          * Dump the configuration key/value mappings to some writer.

82

          *

83

          * @param configuration the configuration

84

          * @param out the writer to dump the configuration to

85

          */

86

         public static void dump(Configuration configuration, PrintWriter out)

87

         {

88

5

             Iterator keys = configuration.getKeys();

89

16

             while (keys.hasNext())

90

             {

91

6

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

92

6

                 Object value = configuration.getProperty(key);

93

6

                 out.print(key);

94

6

                 out.print("=");

95

6

                 out.print(value);

96

97

6

                 if (keys.hasNext())

98

                 {

99

2

                     out.println();

100

                 }

101

             }

102

103

5

             out.flush();

104

5

         }

105

106

         /**

107

          * Get a string representation of the key/value mappings of a

108

          * configuration.

109

          *

110

          * @param configuration the configuration

111

          * @return a string representation of the configuration

112

          */

113

         public static String toString(Configuration configuration)

114

         {

115

5

             StringWriter writer = new StringWriter();

116

5

             dump(configuration, new PrintWriter(writer));

117

5

             return writer.toString();

118

         }

119

120

         /**

121

          * Copy all properties from the source configuration to the target

122

          * configuration. Properties in the target configuration are replaced with

123

          * the properties with the same key in the source configuration.

124

          * <em>Note:</em> This method won't work well on hierarchical configurations

125

          * because it is not able to copy information about the properties'

126

          * structure. So when dealing with hierarchical configuration objects their

127

          * <code>{@link HierarchicalConfiguration#clone() clone()}</code> methods

128

          * should be used.

129

          *

130

          * @param source the source configuration

131

          * @param target the target configuration

132

          * @since 1.1

133

          */

134

         public static void copy(Configuration source, Configuration target)

135

         {

136

43

             Iterator keys = source.getKeys();

137

1182

             while (keys.hasNext())

138

             {

139

1096

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

140

1096

                 target.setProperty(key, source.getProperty(key));

141

             }

142

43

         }

143

144

         /**

145

          * Append all properties from the source configuration to the target

146

          * configuration. Properties in the source configuration are appended to

147

          * the properties with the same key in the target configuration.

148

          *

149

          * @param source the source configuration

150

          * @param target the target configuration

151

          * @since 1.1

152

          */

153

         public static void append(Configuration source, Configuration target)

154

         {

155

1

             Iterator keys = source.getKeys();

156

4

             while (keys.hasNext())

157

             {

158

2

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

159

2

                 target.addProperty(key, source.getProperty(key));

160

             }

161

1

         }

162

163

         /**

164

          * Converts the passed in configuration to a hierarchical one. If the

165

          * configuration is already hierarchical, it is directly returned. Otherwise

166

          * all properties are copied into a new hierarchical configuration.

167

          *

168

          * @param conf the configuration to convert

169

          * @return the new hierarchical configuration (the result is <b>null</b> if

170

          * and only if the passed in configuration is <b>null</b>)

171

          * @since 1.3

172

          */

173

         public static HierarchicalConfiguration convertToHierarchical(

174

                 Configuration conf)

175

         {

176

73

             if (conf == null)

177

             {

178

1

                 return null;

179

             }

180

181

72

             if (conf instanceof HierarchicalConfiguration)

182

             {

183

38

                 return (HierarchicalConfiguration) conf;

184

             }

185

             else

186

             {

187

34

                 HierarchicalConfiguration hc = new HierarchicalConfiguration();

188

34

                 ConfigurationUtils.copy(conf, hc);

189

34

                 return hc;

190

             }

191

         }

192

193

         /**

194

          * Clones the given configuration object if this is possible. If the passed

195

          * in configuration object implements the <code>Cloneable</code>

196

          * interface, its <code>clone()</code> method will be invoked. Otherwise

197

          * an exception will be thrown.

198

          *

199

          * @param config the configuration object to be cloned (can be <b>null</b>)

200

          * @return the cloned configuration (<b>null</b> if the argument was

201

          * <b>null</b>, too)

202

          * @throws ConfigurationRuntimeException if cloning is not supported for

203

          * this object

204

          * @since 1.3

205

          */

206

         public static Configuration cloneConfiguration(Configuration config)

207

                 throws ConfigurationRuntimeException

208

         {

209

11

             if (config == null)

210

             {

211

1

                 return null;

212

             }

213

             else

214

             {

215

                 try

216

                 {

217

10

                     return (Configuration) clone(config);

218

                 }

219

                 catch (CloneNotSupportedException cnex)

220

                 {

221

2

                     throw new ConfigurationRuntimeException(cnex);

222

                 }

223

             }

224

         }

225

226

         /**

227

          * An internally used helper method for cloning objects. This implementation

228

          * is not very sophisticated nor efficient. Maybe it can be replaced by an

229

          * implementation from Commons Lang later. The method checks whether the

230

          * passed in object implements the <code>Cloneable</code> interface. If

231

          * this is the case, the <code>clone()</code> method is invoked by

232

          * reflection. Errors that occur during the cloning process are re-thrown as

233

          * runtime exceptions.

234

          *

235

          * @param obj the object to be cloned

236

          * @return the cloned object

237

          * @throws CloneNotSupportedException if the object cannot be cloned

238

          */

239

         static Object clone(Object obj) throws CloneNotSupportedException

240

         {

241

21

             if (obj instanceof Cloneable)

242

             {

243

                 try

244

                 {

245

19

                     Method m = obj.getClass().getMethod(METHOD_CLONE, null);

246

19

                     return m.invoke(obj, null);

247

                 }

248

                 catch (NoSuchMethodException nmex)

249

                 {

250

0

                     throw new CloneNotSupportedException(

251

                             "No clone() method found for class"

252

                                     + obj.getClass().getName());

253

                 }

254

                 catch (IllegalAccessException iaex)

255

                 {

256

0

                     throw new ConfigurationRuntimeException(iaex);

257

                 }

258

                 catch (InvocationTargetException itex)

259

                 {

260

0

                     throw new ConfigurationRuntimeException(itex);

261

                 }

262

             }

263

             else

264

             {

265

2

                 throw new CloneNotSupportedException(obj.getClass().getName()

266

                         + " does not implement Cloneable");

267

             }

268

         }

269

270

         /**

271

          * Constructs a URL from a base path and a file name. The file name can

272

          * be absolute, relative or a full URL. If necessary the base path URL is

273

          * applied.

274

          *

275

          * @param basePath the base path URL (can be <b>null</b>)

276

          * @param file the file name

277

          * @return the resulting URL

278

          * @throws MalformedURLException if URLs are invalid

279

          */

280

         public static URL getURL(String basePath, String file) throws MalformedURLException

281

         {

282

8

             File f = new File(file);

283

8

             if (f.isAbsolute()) // already absolute?

284

             {

285

2

                 return f.toURL();

286

             }

287

288

             try

289

             {

290

6

                 if (basePath == null)

291

                 {

292

2

                     return new URL(file);

293

                 }

294

                 else

295

                 {

296

4

                     URL base = new URL(basePath);

297

3

                     return new URL(base, file);

298

                 }

299

             }

300

             catch (MalformedURLException uex)

301

             {

302

2

                 return constructFile(basePath, file).toURL();

303

             }

304

         }

305

306

         /**

307

          * Helper method for constructing a file object from a base path and a

308

          * file name. This method is called if the base path passed to

309

          * <code>getURL()</code> does not seem to be a valid URL.

310

          *

311

          * @param basePath the base path

312

          * @param fileName the file name

313

          * @return the resulting file

314

          */

315

         static File constructFile(String basePath, String fileName)

316

         {

317

404

             File file = null;

318

319

404

             File absolute = null;

320

404

             if (fileName != null)

321

             {

322

404

                 absolute = new File(fileName);

323

             }

324

325

404

             if (StringUtils.isEmpty(basePath) || (absolute != null && absolute.isAbsolute()))

326

             {

327

49

                 file = new File(fileName);

328

             }

329

             else

330

             {

331

355

                 StringBuffer fName = new StringBuffer();

332

355

                 fName.append(basePath);

333

334

                 // My best friend. Paranoia.

335

355

                 if (!basePath.endsWith(File.separator))

336

                 {

337

355

                     fName.append(File.separator);

338

                 }

339

340

                 //

341

                 // We have a relative path, and we have

342

                 // two possible forms here. If we have the

343

                 // "./" form then just strip that off first

344

                 // before continuing.

345

                 //

346

355

                 if (fileName.startsWith("." + File.separator))

347

                 {

348

0

                     fName.append(fileName.substring(2));

349

                 }

350

                 else

351

                 {

352

355

                     fName.append(fileName);

353

                 }

354

355

355

                 file = new File(fName.toString());

356

             }

357

358

404

             return file;

359

         }

360

361

         /**

362

          * Return the location of the specified resource by searching the user home

363

          * directory, the current classpath and the system classpath.

364

          *

365

          * @param name the name of the resource

366

          *

367

          * @return the location of the resource

368

          */

369

         public static URL locate(String name)

370

         {

371

1

             return locate(null, name);

372

         }

373

374

         /**

375

          * Return the location of the specified resource by searching the user home

376

          * directory, the current classpath and the system classpath.

377

          *

378

          * @param base the base path of the resource

379

          * @param name the name of the resource

380

          *

381

          * @return the location of the resource

382

          */

383

         public static URL locate(String base, String name)

384

         {

385

933

             if (name == null)

386

             {

387

                 // undefined, always return null

388

4

                 return null;

389

             }

390

391

929

             URL url = null;

392

393

             // attempt to create an URL directly

394

             try

395

             {

396

929

                 if (base == null)

397

                 {

398

270

                     url = new URL(name);

399

                 }

400

                 else

401

                 {

402

659

                     URL baseURL = new URL(base);

403

381

                     url = new URL(baseURL, name);

404

405

                     // check if the file exists

406

380

                     InputStream in = null;

407

                     try

408

                     {

409

380

                         in = url.openStream();

410

364

                     }

411

                     finally

412

                     {

413

16

                         if (in != null)

414

                         {

415

364

                             in.close();

416

                         }

417

                     }

418

                 }

419

420

364

                 log.debug("Configuration loaded from the URL " + url);

421

364

             }

422

             catch (IOException e)

423

             {

424

565

                 url = null;

425

             }

426

427

             // attempt to load from an absolute path

428

929

             if (url == null)

429

             {

430

565

                 File file = new File(name);

431

565

                 if (file.isAbsolute() && file.exists()) // already absolute?

432

                 {

433

                     try

434

                     {

435

231

                         url = file.toURL();

436

231

                         log.debug("Configuration loaded from the absolute path " + name);

437

231

                     }

438

                     catch (MalformedURLException e)

439

                     {

440

0

                         e.printStackTrace();

441

                     }

442

                 }

443

             }

444

445

             // attempt to load from the base directory

446

929

             if (url == null)

447

             {

448

                 try

449

                 {

450

334

                     File file = constructFile(base, name);

451

334

                     if (file != null && file.exists())

452

                     {

453

290

                         url = file.toURL();

454

                     }

455

456

334

                     if (url != null)

457

                     {

458

290

                         log.debug("Configuration loaded from the base path " + name);

459

                     }

460

334

                 }

461

                 catch (IOException e)

462

                 {

463

0

                     e.printStackTrace();

464

                 }

465

             }

466

467

             // attempt to load from the user home directory

468

929

             if (url == null)

469

             {

470

                 try

471

                 {

472

44

                     File file = constructFile(System.getProperty("user.home"), name);

473

44

                     if (file != null && file.exists())

474

                     {

475

1

                         url = file.toURL();

476

                     }

477

478

44

                     if (url != null)

479

                     {

480

1

                         log.debug("Configuration loaded from the home path " + name);

481

                     }

482

483

44

                 }

484

                 catch (IOException e)

485

                 {

486

0

                     e.printStackTrace();

487

                 }

488

             }

489

490

             // attempt to load from classpath

491

929

             if (url == null)

492

             {

493

43

                 url = locateFromClasspath(name);

494

             }

495

929

             return url;

496

         }

497

498

         /**

499

          * Tries to find a resource with the given name in the classpath.

500

          * @param resourceName the name of the resource

501

          * @return the URL to the found resource or <b>null</b> if the resource

502

          * cannot be found

503

          */

504

         static URL locateFromClasspath(String resourceName)

505

         {

506

43

             URL url = null;

507

             // attempt to load from the context classpath

508

43

             ClassLoader loader = Thread.currentThread().getContextClassLoader();

509

43

             if (loader != null)

510

             {

511

41

                 url = loader.getResource(resourceName);

512

513

41

                 if (url != null)

514

                 {

515

18

                     log.debug("Configuration loaded from the context classpath (" + resourceName + ")");

516

                 }

517

             }

518

519

             // attempt to load from the system classpath

520

43

             if (url == null)

521

             {

522

25

                 url = ClassLoader.getSystemResource(resourceName);

523

524

25

                 if (url != null)

525

                 {

526

1

                     log.debug("Configuration loaded from the system classpath (" + resourceName + ")");

527

                 }

528

             }

529

43

             return url;

530

         }

531

532

         /**

533

          * Return the path without the file name, for example http://xyz.net/foo/bar.xml

534

          * results in http://xyz.net/foo/

535

          *

536

          * @param url the URL from which to extract the path

537

          * @return the path component of the passed in URL

538

          */

539

         static String getBasePath(URL url)

540

         {

541

19

             if (url == null)

542

             {

543

0

                 return null;

544

             }

545

546

19

             String s = url.toString();

547

548

19

             if (s.endsWith("/") || StringUtils.isEmpty(url.getPath()))

549

             {

550

3

                 return s;

551

             }

552

             else

553

             {

554

16

                 return s.substring(0, s.lastIndexOf("/") + 1);

555

             }

556

         }

557

558

         /**

559

          * Extract the file name from the specified URL.

560

          *

561

          * @param url the URL from which to extract the file name

562

          * @return the extracted file name

563

          */

564

         static String getFileName(URL url)

565

         {

566

17

             if (url == null)

567

             {

568

1

                 return null;

569

             }

570

571

16

             String path = url.getPath();

572

573

16

             if (path.endsWith("/") || StringUtils.isEmpty(path))

574

             {

575

1

                 return null;

576

             }

577

             else

578

             {

579

15

                 return path.substring(path.lastIndexOf("/") + 1);

580

             }

581

         }

582

583

         /**

584

          * Tries to convert the specified base path and file name into a file object.

585

          * This method is called e.g. by the save() methods of file based

586

          * configurations. The parameter strings can be relative files, absolute

587

          * files and URLs as well.

588

          *

589

          * @param basePath the base path

590

          * @param fileName the file name

591

          * @return the file object (<b>null</b> if no file can be obtained)

592

          */

593

         public static File getFile(String basePath, String fileName)

594

         {

595

             // Check if URLs are involved

596

             URL url;

597

             try

598

             {

599

29

                 url = new URL(new URL(basePath), fileName);

600

3

             }

601

             catch (MalformedURLException mex1)

602

             {

603

26

                 try

604

                 {

605

26

                     url = new URL(fileName);

606

2

                 }

607

                 catch (MalformedURLException mex2)

608

                 {

609

24

                     url = null;

610

                 }

611

             }

612

613

29

             if (url != null)

614

             {

615

5

                 return fileFromURL(url);

616

             }

617

618

24

             return constructFile(basePath, fileName);

619

         }

620

621

         /**

622

          * Tries to convert the specified URL to a file object. If this fails,

623

          * <b>null</b> is returned.

624

          *

625

          * @param url the URL

626

          * @return the resulting file object

627

          */

628

         public static File fileFromURL(URL url)

629

         {

630

1128

             if (PROTOCOL_FILE.equals(url.getProtocol()))

631

             {

632

1126

                 return new File(URLDecoder.decode(url.getPath()));

633

             }

634

             else

635

             {

636

2

                 return null;

637

             }

638

         }

639

     }