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

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

AbstractFileConfiguration

91% | 202/221

88% | 36/41

2.3404255319148937;2,34

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.FileOutputStream;

22

     import java.io.IOException;

23

     import java.io.InputStream;

24

     import java.io.InputStreamReader;

25

     import java.io.OutputStream;

26

     import java.io.OutputStreamWriter;

27

     import java.io.Reader;

28

     import java.io.UnsupportedEncodingException;

29

     import java.io.Writer;

30

     import java.net.MalformedURLException;

31

     import java.net.URL;

32

     import java.util.Iterator;

33

34

     import org.apache.commons.configuration.reloading.InvariantReloadingStrategy;

35

     import org.apache.commons.configuration.reloading.ReloadingStrategy;

36

     import org.apache.commons.lang.StringUtils;

37

38

     /**

39

      * <p>Partial implementation of the <code>FileConfiguration</code> interface.

40

      * Developpers of file based configuration may want to extend this class,

41

      * the two methods left to implement are <code>{@link FileConfiguration#load(Reader)}</code>

42

      * and <code>{@link FileConfiguration#save(Writer)}.</p>

43

      * <p>This base class already implements a couple of ways to specify the location

44

      * of the file this configuration is based on. The following possibilities

45

      * exist:

46

      * <ul><li>URLs: With the method <code>setURL()</code> a full URL to the

47

      * configuration source can be specified. This is the most flexible way. Note

48

      * that the <code>save()</code> methods support only <em>file:</em> URLs.</li>

49

      * <li>Files: The <code>setFile()</code> method allows to specify the

50

      * configuration source as a file. This can be either a relative or an

51

      * absolute file. In the former case the file is resolved based on the current

52

      * directory.</li>

53

      * <li>As file paths in string form: With the <code>setPath()</code> method a

54

      * full path to a configuration file can be provided as a string.</li>

55

      * <li>Separated as base path and file name: This is the native form in which

56

      * the location is stored. The base path is a string defining either a local

57

      * directory or a URL. It can be set using the <code>setBasePath()</code>

58

      * method. The file name, non surprisingly, defines the name of the configuration

59

      * file.</li></ul></p>

60

      * <p>Note that the <code>load()</code> methods do not wipe out the configuration's

61

      * content before the new configuration file is loaded. Thus it is very easy to

62

      * construct a union configuration by simply loading multiple configuration

63

      * files, e.g.</p>

64

      * <p><pre>

65

      * config.load(configFile1);

66

      * config.load(configFile2);

67

      * </pre></p>

68

      * <p>After executing this code fragment, the resulting configuration will

69

      * contain both the properties of configFile1 and configFile2. On the other

70

      * hand, if the current configuration file is to be reloaded, <code>clear()</code>

71

      * should be called first. Otherwise the properties are doubled. This behavior

72

      * is analogous to the behavior of the <code>load(InputStream)</code> method

73

      * in <code>java.util.Properties</code>.</p>

74

      *

75

      * @author Emmanuel Bourg

76

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

77

      * @since 1.0-rc2

78

      */

79

     public abstract class AbstractFileConfiguration extends BaseConfiguration implements FileConfiguration

80

     {

81

         /** Constant for the configuration reload event.*/

82

         public static final int EVENT_RELOAD = 20;

83

84

         /** Stores the file name.*/

85

         protected String fileName;

86

87

         /** Stores the base path.*/

88

         protected String basePath;

89

90

         /** The auto save flag.*/

91

         protected boolean autoSave;

92

93

         /** Holds a reference to the reloading strategy.*/

94

         protected ReloadingStrategy strategy;

95

96

         /** A lock object for protecting reload operations.*/

97

794

         private Object reloadLock = new Object();

98

99

         /** Stores the encoding of the configuration file.*/

100

         private String encoding;

101

102

         /** Stores the URL from which the configuration file was loaded.*/

103

         private URL sourceURL;

104

105

         /** A counter that prohibits reloading.*/

106

         private int noReload;

107

108

         /**

109

          * Default constructor

110

          *

111

          * @since 1.1

112

          */

113

         public AbstractFileConfiguration()

114

794

         {

115

794

             initReloadingStrategy();

116

794

         }

117

118

         /**

119

          * Creates and loads the configuration from the specified file. The passed

120

          * in string must be a valid file name, either absolute or relativ.

121

          *

122

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

123

          *

124

          * @throws ConfigurationException Error while loading the file

125

          * @since 1.1

126

          */

127

         public AbstractFileConfiguration(String fileName) throws ConfigurationException

128

         {

129

220

             this();

130

131

             // store the file name

132

220

             setFileName(fileName);

133

134

             // load the file

135

220

             load();

136

218

         }

137

138

         /**

139

          * Creates and loads the configuration from the specified file.

140

          *

141

          * @param file The file to load.

142

          * @throws ConfigurationException Error while loading the file

143

          * @since 1.1

144

          */

145

         public AbstractFileConfiguration(File file) throws ConfigurationException

146

         {

147

9

             this();

148

149

             // set the file and update the url, the base path and the file name

150

9

             setFile(file);

151

152

             // load the file

153

9

             if (file.exists())

154

             {

155

8

                 load();

156

             }

157

8

         }

158

159

         /**

160

          * Creates and loads the configuration from the specified URL.

161

          *

162

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

163

          * @throws ConfigurationException Error while loading the file

164

          * @since 1.1

165

          */

166

         public AbstractFileConfiguration(URL url) throws ConfigurationException

167

         {

168

1

             this();

169

170

             // set the URL and update the base path and the file name

171

1

             setURL(url);

172

173

             // load the file

174

1

             load();

175

1

         }

176

177

         /**

178

          * Load the configuration from the underlying location.

179

          *

180

          * @throws ConfigurationException if loading of the configuration fails

181

          */

182

         public void load() throws ConfigurationException

183

         {

184

724

             if (sourceURL != null)

185

             {

186

192

                 load(sourceURL);

187

             }

188

             else

189

             {

190

532

                 load(getFileName());

191

             }

192

703

         }

193

194

         /**

195

          * Locate the specified file and load the configuration. This does not

196

          * change the source of the configuration (i.e. the internally maintained file name).

197

          * Use one of the setter methods for this purpose.

198

          *

199

          * @param fileName the name of the file to be loaded

200

          * @throws ConfigurationException if an error occurs

201

          */

202

         public void load(String fileName) throws ConfigurationException

203

         {

204

             try

205

             {

206

537

                 URL url = ConfigurationUtils.locate(basePath, fileName);

207

208

537

                 if (url == null)

209

                 {

210

18

                     throw new ConfigurationException("Cannot locate configuration source " + fileName);

211

                 }

212

519

                 load(url);

213

515

             }

214

             catch (ConfigurationException e)

215

             {

216

22

                 throw e;

217

             }

218

             catch (Exception e)

219

             {

220

0

                 throw new ConfigurationException(e.getMessage(), e);

221

             }

222

515

         }

223

224

         /**

225

          * Load the configuration from the specified file. This does not change

226

          * the source of the configuration (i.e. the internally maintained file

227

          * name). Use one of the setter methods for this purpose.

228

          *

229

          * @param file the file to load

230

          * @throws ConfigurationException if an error occurs

231

          */

232

         public void load(File file) throws ConfigurationException

233

         {

234

             try

235

             {

236

12

                 load(file.toURL());

237

9

             }

238

             catch (ConfigurationException e)

239

             {

240

3

                 throw e;

241

             }

242

             catch (Exception e)

243

             {

244

0

                 throw new ConfigurationException(e.getMessage(), e);

245

             }

246

9

         }

247

248

         /**

249

          * Load the configuration from the specified URL. This does not change the

250

          * source of the configuration (i.e. the internally maintained file name).

251

          * Use on of the setter methods for this purpose.

252

          *

253

          * @param url the URL of the file to be loaded

254

          * @throws ConfigurationException if an error occurs

255

          */

256

         public void load(URL url) throws ConfigurationException

257

         {

258

1079

             if (sourceURL == null)

259

             {

260

531

                 if (StringUtils.isEmpty(getBasePath()))

261

                 {

262

                     // ensure that we have a valid base path

263

280

                     setBasePath(url.toString());

264

                 }

265

531

                 sourceURL = url;

266

             }

267

268

             // throw an exception if the target URL is a directory

269

1079

             File file = ConfigurationUtils.fileFromURL(url);

270

1079

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

271

             {

272

4

                 throw new ConfigurationException("Cannot load a configuration from a directory");

273

             }

274

275

1075

             InputStream in = null;

276

277

             try

278

             {

279

1075

                 in = url.openStream();

280

1075

                 load(in);

281

1072

             }

282

             catch (ConfigurationException e)

283

             {

284

3

                 throw e;

285

             }

286

             catch (Exception e)

287

             {

288

0

                 throw new ConfigurationException(e.getMessage(), e);

289

             }

290

             finally

291

             {

292

                 // close the input stream

293

3

                 try

294

                 {

295

1075

                     if (in != null)

296

                     {

297

1075

                         in.close();

298

                     }

299

1075

                 }

300

                 catch (IOException e)

301

                 {

302

0

                     e.printStackTrace();

303

1075

                 }

304

             }

305

1072

         }

306

307

         /**

308

          * Load the configuration from the specified stream, using the encoding

309

          * returned by {@link #getEncoding()}.

310

          *

311

          * @param in the input stream

312

          *

313

          * @throws ConfigurationException if an error occurs during the load operation

314

          */

315

         public void load(InputStream in) throws ConfigurationException

316

         {

317

852

             load(in, getEncoding());

318

851

         }

319

320

         /**

321

          * Load the configuration from the specified stream, using the specified

322

          * encoding. If the encoding is null the default encoding is used.

323

          *

324

          * @param in the input stream

325

          * @param encoding the encoding used. <code>null</code> to use the default encoding

326

          *

327

          * @throws ConfigurationException if an error occurs during the load operation

328

          */

329

         public void load(InputStream in, String encoding) throws ConfigurationException

330

         {

331

853

             Reader reader = null;

332

333

853

             if (encoding != null)

334

             {

335

                 try

336

                 {

337

451

                     reader = new InputStreamReader(in, encoding);

338

451

                 }

339

                 catch (UnsupportedEncodingException e)

340

                 {

341

0

                     throw new ConfigurationException(

342

                             "The requested encoding is not supported, try the default encoding.", e);

343

                 }

344

             }

345

346

853

             if (reader == null)

347

             {

348

402

                 reader = new InputStreamReader(in);

349

             }

350

351

853

             load(reader);

352

852

         }

353

354

         /**

355

          * Save the configuration. Before this method can be called a valid file

356

          * name must have been set.

357

          *

358

          * @throws ConfigurationException if an error occurs or no file name has

359

          * been set yet

360

          */

361

         public void save() throws ConfigurationException

362

         {

363

27

             if (getFileName() == null)

364

             {

365

4

                 throw new ConfigurationException("No file name has been set!");

366

             }

367

368

23

             if (sourceURL != null)

369

             {

370

15

                 save(sourceURL);

371

             }

372

             else

373

             {

374

8

                 save(fileName);

375

             }

376

23

             strategy.init();

377

23

         }

378

379

         /**

380

          * Save the configuration to the specified file. This doesn't change the

381

          * source of the configuration, use setFileName() if you need it.

382

          *

383

          * @param fileName the file name

384

          *

385

          * @throws ConfigurationException if an error occurs during the save operation

386

          */

387

         public void save(String fileName) throws ConfigurationException

388

         {

389

             try

390

             {

391

15

                 File file = ConfigurationUtils.getFile(basePath, fileName);

392

15

                 if (file == null)

393

                 {

394

1

                     throw new ConfigurationException("Invalid file name for save: " + fileName);

395

                 }

396

14

                 save(file);

397

14

             }

398

             catch (ConfigurationException e)

399

             {

400

1

                 throw e;

401

             }

402

             catch (Exception e)

403

             {

404

0

                 throw new ConfigurationException(e.getMessage(), e);

405

             }

406

14

         }

407

408

         /**

409

          * Save the configuration to the specified URL if it's a file URL.

410

          * This doesn't change the source of the configuration, use setURL()

411

          * if you need it.

412

          *

413

          * @param url the URL

414

          *

415

          * @throws ConfigurationException if an error occurs during the save operation

416

          */

417

         public void save(URL url) throws ConfigurationException

418

         {

419

17

             File file = ConfigurationUtils.fileFromURL(url);

420

17

             if (file != null)

421

             {

422

16

                 save(file);

423

             }

424

             else

425

             {

426

1

                 throw new ConfigurationException("Could not save to URL " + url);

427

             }

428

16

         }

429

430

         /**

431

          * Save the configuration to the specified file. The file is created

432

          * automatically if it doesn't exist. This doesn't change the source

433

          * of the configuration, use {@link #setFile} if you need it.

434

          *

435

          * @param file the target file

436

          *

437

          * @throws ConfigurationException if an error occurs during the save operation

438

          */

439

         public void save(File file) throws ConfigurationException

440

         {

441

39

             OutputStream out = null;

442

443

             try

444

             {

445

                 // create the file if necessary

446

39

                 createPath(file);

447

39

                 out = new FileOutputStream(file);

448

39

                 save(out);

449

38

             }

450

             catch (IOException e)

451

             {

452

0

                 throw new ConfigurationException(e.getMessage(), e);

453

             }

454

             finally

455

             {

456

                 // close the output stream

457

1

                 try

458

                 {

459

39

                     if (out != null)

460

                     {

461

39

                         out.close();

462

                     }

463

39

                 }

464

                 catch (IOException e)

465

                 {

466

0

                     e.printStackTrace();

467

39

                 }

468

             }

469

38

         }

470

471

         /**

472

          * Save the configuration to the specified stream, using the encoding

473

          * returned by {@link #getEncoding()}.

474

          *

475

          * @param out the output stream

476

          *

477

          * @throws ConfigurationException if an error occurs during the save operation

478

          */

479

         public void save(OutputStream out) throws ConfigurationException

480

         {

481

40

             save(out, getEncoding());

482

39

         }

483

484

         /**

485

          * Save the configuration to the specified stream, using the specified

486

          * encoding. If the encoding is null the default encoding is used.

487

          *

488

          * @param out the output stream

489

          * @param encoding the encoding to use

490

          * @throws ConfigurationException if an error occurs during the save operation

491

          */

492

         public void save(OutputStream out, String encoding) throws ConfigurationException

493

         {

494

41

             Writer writer = null;

495

496

41

             if (encoding != null)

497

             {

498

                 try

499

                 {

500

25

                     writer = new OutputStreamWriter(out, encoding);

501

25

                 }

502

                 catch (UnsupportedEncodingException e)

503

                 {

504

0

                     throw new ConfigurationException(

505

                             "The requested encoding is not supported, try the default encoding.", e);

506

                 }

507

             }

508

509

41

             if (writer == null)

510

             {

511

16

                 writer = new OutputStreamWriter(out);

512

             }

513

514

41

             save(writer);

515

40

         }

516

517

         /**

518

          * Return the name of the file.

519

          *

520

          * @return the file name

521

          */

522

         public String getFileName()

523

         {

524

687

             return fileName;

525

         }

526

527

         /**

528

          * Set the name of the file. The passed in file name can contain a

529

          * relative path.

530

          * It must be used when referring files with relative paths from classpath.

531

          * Use <code>{@link AbstractFileConfiguration#setPath(String)

532

          * setPath()}</code> to set a full qualified file name.

533

          *

534

          * @param fileName the name of the file

535

          */

536

         public void setFileName(String fileName)

537

         {

538

615

             sourceURL = null;

539

615

             this.fileName = fileName;

540

615

         }

541

542

         /**

543

          * Return the base path.

544

          *

545

          * @return the base path

546

          */

547

         public String getBasePath()

548

         {

549

969

             return basePath;

550

         }

551

552

         /**

553

          * Set the base path. Relative configurations are loaded from this path. The

554

          * base path can be either a path to a directory or a URL.

555

          *

556

          * @param basePath the base path.

557

          */

558

         public void setBasePath(String basePath)

559

         {

560

577

             sourceURL = null;

561

577

             this.basePath = basePath;

562

577

         }

563

564

         /**

565

          * Return the file where the configuration is stored. If the base path is a

566

          * URL with a protocol different than &quot;file&quot;, or the configuration

567

          * file is within a compressed archive, the return value

568

          * will not point to a valid file object.

569

          *

570

          * @return the file where the configuration is stored; this can be <b>null</b>

571

          */

572

         public File getFile()

573

         {

574

11

             if (getFileName() == null)

575

             {

576

1

                 return null;

577

             }

578

             else

579

             {

580

10

                 if (sourceURL != null)

581

                 {

582

1

                     return ConfigurationUtils.fileFromURL(sourceURL);

583

                 }

584

                 else

585

                 {

586

9

                     return ConfigurationUtils.getFile(getBasePath(), getFileName());

587

                 }

588

             }

589

         }

590

591

         /**

592

          * Set the file where the configuration is stored. The passed in file is

593

          * made absolute if it is not yet. Then the file's path component becomes

594

          * the base path and its name component becomes the file name.

595

          *

596

          * @param file the file where the configuration is stored

597

          */

598

         public void setFile(File file)

599

         {

600

165

             sourceURL = null;

601

165

             setFileName(file.getName());

602

165

             setBasePath((file.getParentFile() != null) ? file.getParentFile()

603

                     .getAbsolutePath() : null);

604

165

         }

605

606

         /**

607

          * Returns the full path to the file this configuration is based on. The

608

          * return value is a valid File path only if this configuration is based on

609

          * a file on the local disk.

610

          * If the configuration was loaded from a packed archive the returned value

611

          * is the string form of the URL from which the configuration was loaded.

612

          *

613

          * @return the full path to the configuration file

614

          */

615

         public String getPath()

616

         {

617

2

             String path = null;

618

2

             File file = getFile();

619

             // if resource was loaded from jar file may be null

620

2

             if (file != null)

621

             {

622

2

                 path = file.getAbsolutePath();

623

             }

624

625

             // try to see if file was loaded from a jar

626

2

             if (path == null)

627

             {

628

0

                 if (sourceURL != null)

629

                 {

630

0

                     path = sourceURL.getPath();

631

                 }

632

                 else

633

                 {

634

                     try {

635

0

                         path = ConfigurationUtils.getURL(getBasePath(),

636

                                 getFileName()).getPath();

637

0

                     } catch (MalformedURLException e) {

638

                         // simply ignore it and return null

639

                     }

640

                 }

641

             }

642

643

2

             return path;

644

         }

645

646

         /**

647

          * Sets the location of this configuration as a full or relative path name.

648

          * The passed in path should represent a valid file name on the file system.

649

          * It must not be used to specify relative paths for files that exist

650

          * in classpath, either plain file system or compressed archive,

651

          * because this method expands any relative path to an absolute one which

652

          * may end in an invalid absolute path for classpath references.

653

          *

654

          * @param path the full path name of the configuration file

655

          */

656

         public void setPath(String path)

657

         {

658

1

             setFile(new File(path));

659

1

         }

660

661

         /**

662

          * Return the URL where the configuration is stored.

663

          *

664

          * @return the configuration's location as URL

665

          */

666

         public URL getURL()

667

         {

668

630

             return (sourceURL != null) ? sourceURL

669

                     : ConfigurationUtils.locate(getBasePath(), getFileName());

670

         }

671

672

         /**

673

          * Set the location of this configuration as a URL. For loading this can be

674

          * an arbitrary URL with a supported protocol. If the configuration is to

675

          * be saved, too, a URL with the &quot;file&quot; protocol should be

676

          * provided.

677

          *

678

          * @param url the location of this configuration as URL

679

          */

680

         public void setURL(URL url)

681

         {

682

14

             setBasePath(ConfigurationUtils.getBasePath(url));

683

14

             setFileName(ConfigurationUtils.getFileName(url));

684

14

             sourceURL = url;

685

14

         }

686

687

         public void setAutoSave(boolean autoSave)

688

         {

689

1639

             this.autoSave = autoSave;

690

1639

         }

691

692

         public boolean isAutoSave()

693

         {

694

818

             return autoSave;

695

         }

696

697

         /**

698

          * Save the configuration if the automatic persistence is enabled

699

          * and if a file is specified.

700

          */

701

         protected void possiblySave()

702

         {

703

19801

             if (autoSave && fileName != null)

704

             {

705

                 try

706

                 {

707

14

                     save();

708

14

                 }

709

                 catch (ConfigurationException e)

710

                 {

711

0

                     throw new ConfigurationRuntimeException("Failed to auto-save", e);

712

                 }

713

             }

714

19801

         }

715

716

         /**

717

          * Adds a new property to this configuration. This implementation checks if

718

          * the auto save mode is enabled and saves the configuration if necessary.

719

          *

720

          * @param key the key of the new property

721

          * @param value the value

722

          */

723

         public void addProperty(String key, Object value)

724

         {

725

19462

             super.addProperty(key, value);

726

19462

             possiblySave();

727

19462

         }

728

729

         /**

730

          * Sets a new value for the specified property. This implementation checks

731

          * if the auto save mode is enabled and saves the configuration if

732

          * necessary.

733

          *

734

          * @param key the key of the affected property

735

          * @param value the value

736

          */

737

         public void setProperty(String key, Object value)

738

         {

739

17

             super.setProperty(key, value);

740

17

             possiblySave();

741

17

         }

742

743

         public void clearProperty(String key)

744

         {

745

37

             super.clearProperty(key);

746

37

             possiblySave();

747

37

         }

748

749

         public ReloadingStrategy getReloadingStrategy()

750

         {

751

7

             return strategy;

752

         }

753

754

         public void setReloadingStrategy(ReloadingStrategy strategy)

755

         {

756

814

             this.strategy = strategy;

757

814

             strategy.setConfiguration(this);

758

814

             strategy.init();

759

814

         }

760

761

         public void reload()

762

         {

763

23655

             synchronized (reloadLock)

764

             {

765

23655

                 if (noReload == 0)

766

                 {

767

                     try

768

                     {

769

14027

                         enterNoReload(); // avoid reentrant calls

770

771

14027

                         if (strategy.reloadingRequired())

772

                         {

773

171

                             fireEvent(EVENT_RELOAD, null, getURL(), true);

774

171

                             setDetailEvents(false);

775

                             try

776

                             {

777

171

                                 clear();

778

171

                                 load();

779

171

                             }

780

                             finally

781

                             {

782

0

                                 setDetailEvents(true);

783

                             }

784

171

                             fireEvent(EVENT_RELOAD, null, getURL(), false);

785

786

                             // notify the strategy

787

171

                             strategy.reloadingPerformed();

788

                         }

789

14027

                     }

790

                     catch (Exception e)

791

                     {

792

0

                         e.printStackTrace();

793

                         // todo rollback the changes if the file can't be reloaded

794

0

                     }

795

                     finally

796

                     {

797

0

                         exitNoReload();

798

                     }

799

                 }

800

23655

             }

801

23655

         }

802

803

         /**

804

          * Enters the &quot;No reloading mode&quot;. As long as this mode is active

805

          * no reloading will be performed. This is necessary for some

806

          * implementations of <code>save()</code> in derived classes, which may

807

          * cause a reload while accessing the properties to save. This may cause the

808

          * whole configuration to be erased. To avoid this, this method can be

809

          * called first. After a call to this method there always must be a

810

          * corresponding call of <code>{@link #exitNoReload()}</code> later! (If

811

          * necessary, <code>finally</code> blocks must be used to ensure this.

812

          */

813

         protected void enterNoReload()

814

         {

815

53764

             synchronized (reloadLock)

816

             {

817

53764

                 noReload++;

818

53764

             }

819

53764

         }

820

821

         /**

822

          * Leaves the &quot;No reloading mode&quot;.

823

          *

824

          * @see #enterNoReload()

825

          */

826

         protected void exitNoReload()

827

         {

828

53764

             synchronized (reloadLock)

829

             {

830

53764

                 if (noReload > 0) // paranoia check

831

                 {

832

53764

                     noReload--;

833

                 }

834

53764

             }

835

53764

         }

836

837

         /**

838

          * Sends an event to all registered listeners. This implementation ensures

839

          * that no reloads are performed while the listeners are invoked. So

840

          * infinite loops can be avoided that can be caused by event listeners

841

          * accessing the configuration's properties when they are invoked.

842

          *

843

          * @param type the event type

844

          * @param propName the name of the property

845

          * @param propValue the value of the property

846

          * @param before the before update flag

847

          */

848

         protected void fireEvent(int type, String propName, Object propValue,

849

                 boolean before)

850

         {

851

39712

             enterNoReload();

852

             try

853

             {

854

39712

                 super.fireEvent(type, propName, propValue, before);

855

39712

             }

856

             finally

857

             {

858

0

                 exitNoReload();

859

             }

860

39712

         }

861

862

         public Object getProperty(String key)

863

         {

864

21707

             reload();

865

21707

             return super.getProperty(key);

866

         }

867

868

         public boolean isEmpty()

869

         {

870

9

             reload();

871

9

             return super.isEmpty();

872

         }

873

874

         public boolean containsKey(String key)

875

         {

876

599

             reload();

877

599

             return super.containsKey(key);

878

         }

879

880

         public Iterator getKeys()

881

         {

882

81

             reload();

883

81

             return super.getKeys();

884

         }

885

886

         /**

887

          * Create the path to the specified file.

888

          *

889

          * @param file the target file

890

          */

891

         private void createPath(File file)

892

         {

893

39

             if (file != null)

894

             {

895

                 // create the path to the file if the file doesn't exist

896

39

                 if (!file.exists())

897

                 {

898

22

                     File parent = file.getParentFile();

899

22

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

900

                     {

901

3

                         parent.mkdirs();

902

                     }

903

                 }

904

             }

905

39

         }

906

907

         public String getEncoding()

908

         {

909

918

             return encoding;

910

         }

911

912

         public void setEncoding(String encoding)

913

         {

914

392

             this.encoding = encoding;

915

392

         }

916

917

         /**

918

          * Creates a copy of this configuration. The new configuration object will

919

          * contain the same properties as the original, but it will lose any

920

          * connection to a source file (if one exists); this includes setting the

921

          * source URL, base path, and file name to <b>null</b>. This is done to

922

          * avoid race conditions if both the original and the copy are modified and

923

          * then saved.

924

          *

925

          * @return the copy

926

          * @since 1.3

927

          */

928

         public Object clone()

929

         {

930

4

             AbstractFileConfiguration copy = (AbstractFileConfiguration) super

931

                     .clone();

932

4

             copy.setBasePath(null);

933

4

             copy.setFileName(null);

934

4

             copy.initReloadingStrategy();

935

4

             return copy;

936

         }

937

938

         /**

939

          * Helper method for initializing the reloading strategy.

940

          */

941

         private void initReloadingStrategy()

942

         {

943

798

             setReloadingStrategy(new InvariantReloadingStrategy());

944

798

         }

945

     }