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

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

ConfigurationFactory

97% | 85/88

100% | 12/12

1.575;1,575

ConfigurationFactory$AdditionalConfigurationData

100% | 7/7

N/A | N/A

1.575;1,575

ConfigurationFactory$ConfigurationBuilder

100% | 24/24

100% | 5/5

1.575;1,575

ConfigurationFactory$DigesterConfigurationFactory

100% | 4/4

N/A | N/A

1.575;1,575

ConfigurationFactory$FileConfigurationFactory

100% | 14/14

100% | 1/1

1.575;1,575

ConfigurationFactory$JNDIConfigurationFactory

100% | 4/4

100% | 1/1

1.575;1,575

ConfigurationFactory$PropertiesConfigurationFactory

100% | 7/7

100% | 1/1

1.575;1,575

ConfigurationFactory$PropertyListConfigurationFactory

43% | 3/7

0% | 0/1

1.575;1,575

ConfigurationFactory$SystemConfigurationFactory

100% | 4/4

100% | 1/1

1.575;1,575

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.net.URL;

24

     import java.util.Collection;

25

     import java.util.Iterator;

26

     import java.util.LinkedList;

27

     import java.util.Map;

28

29

     import org.apache.commons.configuration.plist.PropertyListConfiguration;

30

     import org.apache.commons.configuration.plist.XMLPropertyListConfiguration;

31

     import org.apache.commons.digester.AbstractObjectCreationFactory;

32

     import org.apache.commons.digester.Digester;

33

     import org.apache.commons.digester.ObjectCreationFactory;

34

     import org.apache.commons.digester.Substitutor;

35

     import org.apache.commons.digester.substitution.MultiVariableExpander;

36

     import org.apache.commons.digester.substitution.VariableSubstitutor;

37

     import org.apache.commons.digester.xmlrules.DigesterLoader;

38

     import org.apache.commons.lang.StringUtils;

39

     import org.apache.commons.logging.Log;

40

     import org.apache.commons.logging.LogFactory;

41

     import org.xml.sax.Attributes;

42

     import org.xml.sax.SAXException;

43

44

     /**

45

      * Factory class to create a CompositeConfiguration from a .xml file using

46

      * Digester.  By default it can handle the Configurations from commons-

47

      * configuration.  If you need to add your own, then you can pass in your own

48

      * digester rules to use.  It is also namespace aware, by providing a

49

      * digesterRuleNamespaceURI.

50

      *

51

      * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>

52

      * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>

53

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

54

      * @version $Id: ConfigurationFactory.java 439648 2006-09-02 20:42:10Z oheger $

55

      */

56

86

     public class ConfigurationFactory

57

     {

58

         /** Constant for the root element in the info file.*/

59

         private static final String SEC_ROOT = "configuration/";

60

61

         /** Constant for the override section.*/

62

         private static final String SEC_OVERRIDE = SEC_ROOT + "override/";

63

64

         /** Constant for the additional section.*/

65

         private static final String SEC_ADDITIONAL = SEC_ROOT + "additional/";

66

67

         /** Constant for the optional attribute.*/

68

         private static final String ATTR_OPTIONAL = "optional";

69

70

         /** Constant for the fileName attribute.*/

71

         private static final String ATTR_FILENAME = "fileName";

72

73

         /** Constant for the default base path (points to actual directory).*/

74

         private static final String DEF_BASE_PATH = ".";

75

76

         /** static logger */

77

6

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

78

79

         /** The XML file with the details about the configuration to load */

80

         private String configurationFileName;

81

82

         /** The URL to the XML file with the details about the configuration to load. */

83

         private URL configurationURL;

84

85

         /**

86

          * The implicit base path for included files. This path is determined by

87

          * the configuration to load and used unless no other base path was

88

          * explicitely specified.

89

          */

90

         private String implicitBasePath;

91

92

         /** The basePath to prefix file paths for file based property files. */

93

         private String basePath;

94

95

         /** URL for xml digester rules file */

96

         private URL digesterRules;

97

98

         /** The digester namespace to parse */

99

         private String digesterRuleNamespaceURI;

100

101

         /**

102

          * Constructor

103

          */

104

         public ConfigurationFactory()

105

29

         {

106

29

             setBasePath(DEF_BASE_PATH);

107

29

         }

108

         /**

109

          * Constructor with ConfigurationFile Name passed

110

          *

111

          * @param configurationFileName The path to the configuration file

112

          */

113

         public ConfigurationFactory(String configurationFileName)

114

2

         {

115

2

             setConfigurationFileName(configurationFileName);

116

2

         }

117

118

         /**

119

          * Return the configuration provided by this factory. It loads the

120

          * configuration file which is a XML description of the actual

121

          * configurations to load. It can contain various different types of

122

          * configuration, e.g. Properties, XML and JNDI.

123

          *

124

          * @return A Configuration object

125

          * @throws ConfigurationException A generic exception that we had trouble during the

126

          * loading of the configuration data.

127

          */

128

         public Configuration getConfiguration() throws ConfigurationException

129

         {

130

             Digester digester;

131

28

             InputStream input = null;

132

28

             ConfigurationBuilder builder = new ConfigurationBuilder();

133

28

             URL url = getConfigurationURL();

134

             try

135

             {

136

28

                 if (url == null)

137

                 {

138

21

                     url = ConfigurationUtils.locate(implicitBasePath, getConfigurationFileName());

139

                 }

140

28

                 input = url.openStream();

141

27

             }

142

             catch (Exception e)

143

             {

144

1

                 log.error("Exception caught opening stream to URL", e);

145

1

                 throw new ConfigurationException("Exception caught opening stream to URL", e);

146

             }

147

148

27

             if (getDigesterRules() == null)

149

             {

150

26

                 digester = new Digester();

151

26

                 configureNamespace(digester);

152

26

                 initDefaultDigesterRules(digester);

153

             }

154

             else

155

             {

156

1

                 digester = DigesterLoader.createDigester(getDigesterRules());

157

                 // This might already be too late. As far as I can see, the namespace

158

                 // awareness must be configured before the digester rules are loaded.

159

1

                 configureNamespace(digester);

160

             }

161

162

             // Configure digester to always enable the context class loader

163

27

             digester.setUseContextClassLoader(true);

164

             // Add a substitutor to resolve system properties

165

27

             enableDigesterSubstitutor(digester);

166

             // Put the composite builder object below all of the other objects.

167

27

             digester.push(builder);

168

             // Parse the input stream to configure our mappings

169

             try

170

             {

171

27

                 digester.parse(input);

172

25

                 input.close();

173

25

             }

174

             catch (SAXException saxe)

175

             {

176

2

                 log.error("SAX Exception caught", saxe);

177

2

                 throw new ConfigurationException("SAX Exception caught", saxe);

178

             }

179

             catch (IOException ioe)

180

             {

181

0

                 log.error("IO Exception caught", ioe);

182

0

                 throw new ConfigurationException("IO Exception caught", ioe);

183

             }

184

25

             return builder.getConfiguration();

185

         }

186

187

         /**

188

          * Returns the configurationFile.

189

          *

190

          * @return The name of the configuration file. Can be null.

191

          */

192

         public String getConfigurationFileName()

193

         {

194

21

             return configurationFileName;

195

         }

196

197

         /**

198

          * Sets the configurationFile.

199

          *

200

          * @param configurationFileName  The name of the configurationFile to use.

201

          */

202

         public void setConfigurationFileName(String configurationFileName)

203

         {

204

24

             File file = new File(configurationFileName).getAbsoluteFile();

205

24

             this.configurationFileName = file.getName();

206

24

             implicitBasePath = file.getParent();

207

24

         }

208

209

         /**

210

          * Returns the URL of the configuration file to be loaded.

211

          *

212

          * @return the URL of the configuration to load

213

          */

214

         public URL getConfigurationURL()

215

         {

216

28

             return configurationURL;

217

         }

218

219

         /**

220

          * Sets the URL of the configuration to load. This configuration can be

221

          * either specified by a file name or by a URL.

222

          *

223

          * @param url the URL of the configuration to load

224

          */

225

         public void setConfigurationURL(URL url)

226

         {

227

8

             configurationURL = url;

228

8

             implicitBasePath = url.toString();

229

8

         }

230

231

         /**

232

          * Returns the digesterRules.

233

          *

234

          * @return URL

235

          */

236

         public URL getDigesterRules()

237

         {

238

28

             return digesterRules;

239

         }

240

241

         /**

242

          * Sets the digesterRules.

243

          *

244

          * @param digesterRules The digesterRules to set

245

          */

246

         public void setDigesterRules(URL digesterRules)

247

         {

248

1

             this.digesterRules = digesterRules;

249

1

         }

250

251

         /**

252

          * Adds a substitutor to interpolate system properties

253

          *

254

          * @param digester The digester to which we add the substitutor

255

          */

256

         protected void enableDigesterSubstitutor(Digester digester)

257

         {

258

27

             Map systemProperties = System.getProperties();

259

27

             MultiVariableExpander expander = new MultiVariableExpander();

260

27

             expander.addSource("$", systemProperties);

261

262

             // allow expansion in both xml attributes and element text

263

27

             Substitutor substitutor = new VariableSubstitutor(expander);

264

27

             digester.setSubstitutor(substitutor);

265

27

         }

266

267

         /**

268

          * Initializes the parsing rules for the default digester

269

          *

270

          * This allows the Configuration Factory to understand the default types:

271

          * Properties, XML and JNDI. Two special sections are introduced:

272

          * <code>&lt;override&gt;</code> and <code>&lt;additional&gt;</code>.

273

          *

274

          * @param digester The digester to configure

275

          */

276

         protected void initDefaultDigesterRules(Digester digester)

277

         {

278

26

             initDigesterSectionRules(digester, SEC_ROOT, false);

279

26

             initDigesterSectionRules(digester, SEC_OVERRIDE, false);

280

26

             initDigesterSectionRules(digester, SEC_ADDITIONAL, true);

281

26

         }

282

283

         /**

284

          * Sets up digester rules for a specified section of the configuration

285

          * info file.

286

          *

287

          * @param digester the current digester instance

288

          * @param matchString specifies the section

289

          * @param additional a flag if rules for the additional section are to be

290

          * added

291

          */

292

         protected void initDigesterSectionRules(Digester digester, String matchString, boolean additional)

293

         {

294

78

             setupDigesterInstance(

295

                 digester,

296

                 matchString + "properties",

297

                 new PropertiesConfigurationFactory(),

298

                 null,

299

                 additional);

300

301

78

             setupDigesterInstance(

302

                 digester,

303

                 matchString + "plist",

304

                 new PropertyListConfigurationFactory(),

305

                 null,

306

                 additional);

307

308

78

             setupDigesterInstance(

309

                 digester,

310

                 matchString + "xml",

311

                 new FileConfigurationFactory(XMLConfiguration.class),

312

                 null,

313

                 additional);

314

315

78

             setupDigesterInstance(

316

                 digester,

317

                 matchString + "hierarchicalXml",

318

                 new FileConfigurationFactory(XMLConfiguration.class),

319

                 null,

320

                 additional);

321

322

78

             setupDigesterInstance(

323

                 digester,

324

                 matchString + "jndi",

325

                 new JNDIConfigurationFactory(),

326

                 null,

327

                 additional);

328

329

78

             setupDigesterInstance(

330

                 digester,

331

                 matchString + "system",

332

                 new SystemConfigurationFactory(),

333

                 null,

334

                 additional);

335

78

         }

336

337

         /**

338

          * Sets up digester rules for a configuration to be loaded.

339

          *

340

          * @param digester the current digester

341

          * @param matchString the pattern to match with this rule

342

          * @param factory an ObjectCreationFactory instance to use for creating new

343

          * objects

344

          * @param method the name of a method to be called or <b>null</b> for none

345

          * @param additional a flag if rules for the additional section are to be

346

          * added

347

          */

348

         protected void setupDigesterInstance(

349

                 Digester digester,

350

                 String matchString,

351

                 ObjectCreationFactory factory,

352

                 String method,

353

                 boolean additional)

354

         {

355

468

             if (additional)

356

             {

357

156

                 setupUnionRules(digester, matchString);

358

             }

359

360

468

             digester.addFactoryCreate(matchString, factory);

361

468

             digester.addSetProperties(matchString);

362

363

468

             if (method != null)

364

             {

365

0

                 digester.addCallMethod(matchString, method);

366

             }

367

368

468

             digester.addSetNext(matchString, "addConfiguration", Configuration.class.getName());

369

468

         }

370

371

         /**

372

          * Sets up rules for configurations in the additional section.

373

          *

374

          * @param digester the current digester

375

          * @param matchString the pattern to match with this rule

376

          */

377

         protected void setupUnionRules(Digester digester, String matchString)

378

         {

379

156

             digester.addObjectCreate(matchString,

380

             AdditionalConfigurationData.class);

381

156

             digester.addSetProperties(matchString);

382

156

             digester.addSetNext(matchString, "addAdditionalConfig",

383

             AdditionalConfigurationData.class.getName());

384

156

         }

385

386

         /**

387

          * Returns the digesterRuleNamespaceURI.

388

          *

389

          * @return A String with the digesterRuleNamespaceURI.

390

          */

391

         public String getDigesterRuleNamespaceURI()

392

         {

393

28

             return digesterRuleNamespaceURI;

394

         }

395

396

         /**

397

          * Sets the digesterRuleNamespaceURI.

398

          *

399

          * @param digesterRuleNamespaceURI The new digesterRuleNamespaceURI to use

400

          */

401

         public void setDigesterRuleNamespaceURI(String digesterRuleNamespaceURI)

402

         {

403

1

             this.digesterRuleNamespaceURI = digesterRuleNamespaceURI;

404

1

         }

405

406

         /**

407

          * Configure the current digester to be namespace aware and to have

408

          * a Configuration object to which all of the other configurations

409

          * should be added

410

          *

411

          * @param digester The Digester to configure

412

          */

413

         private void configureNamespace(Digester digester)

414

         {

415

27

             if (getDigesterRuleNamespaceURI() != null)

416

             {

417

1

                 digester.setNamespaceAware(true);

418

1

                 digester.setRuleNamespaceURI(getDigesterRuleNamespaceURI());

419

             }

420

             else

421

             {

422

26

                 digester.setNamespaceAware(false);

423

             }

424

27

             digester.setValidating(false);

425

27

         }

426

427

         /**

428

          * Returns the Base path from which this Configuration Factory operates.

429

          * This is never null. If you set the BasePath to null, then a base path

430

          * according to the configuration to load is returned.

431

          *

432

          * @return The base Path of this configuration factory.

433

          */

434

         public String getBasePath()

435

         {

436

60

             String path = StringUtils.isEmpty(basePath)

437

                     || DEF_BASE_PATH.equals(basePath) ? implicitBasePath : basePath;

438

60

             return StringUtils.isEmpty(path) ? DEF_BASE_PATH : path;

439

         }

440

441

         /**

442

          * Sets the basePath for all file references from this Configuration Factory.

443

          * Normally a base path need not to be set because it is determined by

444

          * the location of the configuration file to load. All relative pathes in

445

          * this file are resolved relative to this file. Setting a base path makes

446

          * sense if such relative pathes should be otherwise resolved, e.g. if

447

          * the configuration file is loaded from the class path and all sub

448

          * configurations it refers to are stored in a special config directory.

449

          *

450

          * @param basePath The new basePath to set.

451

          */

452

         public void setBasePath(String basePath)

453

         {

454

33

             this.basePath = basePath;

455

33

         }

456

457

         /**

458

          * A base class for digester factory classes. This base class maintains

459

          * a default class for the objects to be created.

460

          * There will be sub classes for specific configuration implementations.

461

          */

462

         public class DigesterConfigurationFactory extends AbstractObjectCreationFactory

463

         {

464

             /** Actual class to use. */

465

             private Class clazz;

466

467

             /**

468

              * Creates a new instance of <code>DigesterConfigurationFactory</code>.

469

              *

470

              * @param clazz the class which we should instantiate

471

              */

472

             public DigesterConfigurationFactory(Class clazz)

473

468

             {

474

468

                 this.clazz = clazz;

475

468

             }

476

477

             /**

478

              * Creates an instance of the specified class.

479

              *

480

              * @param attribs the attributes (ignored)

481

              * @return the new object

482

              * @throws Exception if object creation fails

483

              */

484

             public Object createObject(Attributes attribs) throws Exception

485

             {

486

21

                 return clazz.newInstance();

487

             }

488

         }

489

490

         /**

491

          * A tiny inner class that allows the Configuration Factory to

492

          * let the digester construct FileConfiguration objects

493

          * that already have the correct base Path set.

494

          *

495

          */

496

         public class FileConfigurationFactory extends DigesterConfigurationFactory

497

         {

498

             /**

499

              * C'tor

500

              *

501

              * @param clazz The class which we should instantiate.

502

              */

503

             public FileConfigurationFactory(Class clazz)

504

312

             {

505

312

                 super(clazz);

506

312

             }

507

508

             /**

509

              * Gets called by the digester.

510

              *

511

              * @param attributes the actual attributes

512

              * @return the new object

513

              * @throws Exception Couldn't instantiate the requested object.

514

              */

515

             public Object createObject(Attributes attributes) throws Exception

516

             {

517

54

                 FileConfiguration conf = createConfiguration(attributes);

518

54

                 conf.setBasePath(getBasePath());

519

54

                 conf.setFileName(attributes.getValue(ATTR_FILENAME));

520

                 try

521

                 {

522

54

                     log.info("Trying to load configuration " + conf.getFileName());

523

54

                     conf.load();

524

45

                 }

525

                 catch (ConfigurationException cex)

526

                 {

527

9

                     if (attributes.getValue(ATTR_OPTIONAL) != null

528

                             && PropertyConverter.toBoolean(attributes.getValue(ATTR_OPTIONAL)).booleanValue())

529

                     {

530

8

                         log.warn("Could not load optional configuration " + conf.getFileName());

531

                     }

532

                     else

533

                     {

534

1

                         throw cex;

535

                     }

536

                 }

537

53

                 return conf;

538

             }

539

540

             /**

541

              * Creates the object, a <code>FileConfiguration</code>.

542

              *

543

              * @param attributes the actual attributes

544

              * @return the file configuration

545

              * @throws Exception if the object could not be created

546

              */

547

             protected FileConfiguration createConfiguration(Attributes attributes) throws Exception

548

             {

549

19

                 return (FileConfiguration) super.createObject(attributes);

550

             }

551

         }

552

553

         /**

554

          * A factory that returns an XMLPropertiesConfiguration for .xml files

555

          * and a PropertiesConfiguration for the others.

556

          *

557

          * @since 1.2

558

          */

559

         public class PropertiesConfigurationFactory extends FileConfigurationFactory

560

         {

561

             /**

562

              * Creates a new instance of <code>PropertiesConfigurationFactory</code>.

563

              */

564

             public PropertiesConfigurationFactory()

565

78

             {

566

78

                 super(null);

567

78

             }

568

569

             /**

570

              * Creates the new configuration object. Based on the file name

571

              * provided in the attributes either a <code>PropertiesConfiguration</code>

572

              * or a <code>XMLPropertiesConfiguration</code> object will be

573

              * returned.

574

              *

575

              * @param attributes the attributes

576

              * @return the new configuration object

577

              * @throws Exception if an error occurs

578

              */

579

             protected FileConfiguration createConfiguration(Attributes attributes) throws Exception

580

             {

581

35

                 String filename = attributes.getValue(ATTR_FILENAME);

582

583

35

                 if (filename != null && filename.toLowerCase().trim().endsWith(".xml"))

584

                 {

585

2

                     return new XMLPropertiesConfiguration();

586

                 }

587

                 else

588

                 {

589

33

                     return new PropertiesConfiguration();

590

                 }

591

             }

592

         }

593

594

         /**

595

          * A factory that returns an XMLPropertyListConfiguration for .xml files

596

          * and a PropertyListConfiguration for the others.

597

          *

598

          * @since 1.2

599

          */

600

         public class PropertyListConfigurationFactory extends FileConfigurationFactory

601

         {

602

             /**

603

              * Creates a new instance of <code>PropertyListConfigurationFactory</code>.

604

              */

605

             public PropertyListConfigurationFactory()

606

78

             {

607

78

                 super(null);

608

78

             }

609

610

             /**

611

              * Creates the new configuration object. Based on the file name

612

              * provided in the attributes either a <code>XMLPropertyListConfiguration</code>

613

              * or a <code>PropertyListConfiguration</code> object will be

614

              * returned.

615

              *

616

              * @param attributes the attributes

617

              * @return the new configuration object

618

              * @throws Exception if an error occurs

619

              */

620

             protected FileConfiguration createConfiguration(Attributes attributes) throws Exception

621

             {

622

0

                 String filename = attributes.getValue(ATTR_FILENAME);

623

624

0

                 if (filename != null && filename.toLowerCase().trim().endsWith(".xml"))

625

                 {

626

0

                     return new XMLPropertyListConfiguration();

627

                 }

628

                 else

629

                 {

630

0

                     return new PropertyListConfiguration();

631

                 }

632

             }

633

         }

634

635

         /**

636

          * A tiny inner class that allows the Configuration Factory to

637

          * let the digester construct JNDIConfiguration objects.

638

          */

639

         private class JNDIConfigurationFactory extends DigesterConfigurationFactory

640

         {

641

             /**

642

              * Creates a new instance of <code>JNDIConfigurationFactory</code>.

643

              */

644

6

             public JNDIConfigurationFactory()

645

78

             {

646

78

                 super(JNDIConfiguration.class);

647

78

             }

648

         }

649

650

         /**

651

          * A tiny inner class that allows the Configuration Factory to

652

          * let the digester construct SystemConfiguration objects.

653

          */

654

         private class SystemConfigurationFactory extends DigesterConfigurationFactory

655

         {

656

             /**

657

              * Creates a new instance of <code>SystemConfigurationFactory</code>.

658

              */

659

6

             public SystemConfigurationFactory()

660

78

             {

661

78

                 super(SystemConfiguration.class);

662

78

             }

663

         }

664

665

         /**

666

          * A simple data class that holds all information about a configuration

667

          * from the <code>&lt;additional&gt;</code> section.

668

          */

669

21

         public static class AdditionalConfigurationData

670

         {

671

             /** Stores the configuration object.*/

672

             private Configuration configuration;

673

674

             /** Stores the location of this configuration in the global tree.*/

675

             private String at;

676

677

             /**

678

              * Returns the value of the <code>at</code> attribute.

679

              *

680

              * @return the at attribute

681

              */

682

             public String getAt()

683

             {

684

20

                 return at;

685

             }

686

687

             /**

688

              * Sets the value of the <code>at</code> attribute.

689

              *

690

              * @param string the attribute value

691

              */

692

             public void setAt(String string)

693

             {

694

10

                 at = string;

695

10

             }

696

697

             /**

698

              * Returns the configuration object.

699

              *

700

              * @return the configuration

701

              */

702

             public Configuration getConfiguration()

703

             {

704

40

                 return configuration;

705

             }

706

707

             /**

708

              * Sets the configuration object. Note: Normally this method should be

709

              * named <code>setConfiguration()</code>, but the name

710

              * <code>addConfiguration()</code> is required by some of the digester

711

              * rules.

712

              *

713

              * @param config the configuration to set

714

              */

715

             public void addConfiguration(Configuration config)

716

             {

717

21

                 configuration = config;

718

21

             }

719

         }

720

721

         /**

722

          * An internally used helper class for constructing the composite

723

          * configuration object.

724

          */

725

         public static class ConfigurationBuilder

726

         {

727

             /** Stores the composite configuration.*/

728

             private CompositeConfiguration config;

729

730

             /** Stores a collection with the configs from the additional section.*/

731

             private Collection additionalConfigs;

732

733

             /**

734

              * Creates a new instance of <code>ConfigurationBuilder</code>.

735

              */

736

             public ConfigurationBuilder()

737

28

             {

738

28

                 config = new CompositeConfiguration();

739

28

                 additionalConfigs = new LinkedList();

740

28

             }

741

742

             /**

743

              * Adds a new configuration to this object. This method is called by

744

              * Digester.

745

              *

746

              * @param conf the configuration to be added

747

              */

748

             public void addConfiguration(Configuration conf)

749

             {

750

42

                 config.addConfiguration(conf);

751

42

             }

752

753

             /**

754

              * Adds information about an additional configuration. This method is

755

              * called by Digester.

756

              *

757

              * @param data the data about the additional configuration

758

              */

759

             public void addAdditionalConfig(AdditionalConfigurationData data)

760

             {

761

21

                 additionalConfigs.add(data);

762

21

             }

763

764

             /**

765

              * Returns the final composite configuration.

766

              *

767

              * @return the final configuration object

768

              */

769

             public CompositeConfiguration getConfiguration()

770

             {

771

25

                 if (!additionalConfigs.isEmpty())

772

                 {

773

6

                     Configuration unionConfig = createAdditionalConfiguration(additionalConfigs);

774

6

                     if (unionConfig != null)

775

                     {

776

5

                         addConfiguration(unionConfig);

777

                     }

778

6

                     additionalConfigs.clear();

779

                 }

780

781

25

                 return config;

782

             }

783

784

             /**

785

              * Creates a configuration object with the union of all properties

786

              * defined in the <code>&lt;additional&gt;</code> section. This

787

              * implementation returns a <code>HierarchicalConfiguration</code>

788

              * object.

789

              *

790

              * @param configs a collection with

791

              * <code>AdditionalConfigurationData</code> objects

792

              * @return the union configuration (can be <b>null</b>)

793

              */

794

             protected Configuration createAdditionalConfiguration(Collection configs)

795

             {

796

6

                 HierarchicalConfiguration result = new HierarchicalConfiguration();

797

798

32

                 for (Iterator it = configs.iterator(); it.hasNext();)

799

                 {

800

20

                     AdditionalConfigurationData cdata =

801

                     (AdditionalConfigurationData) it.next();

802

20

                     result.addNodes(cdata.getAt(),

803

                     createRootNode(cdata).getChildren());

804

                 }

805

806

6

                 return result.isEmpty() ? null : result;

807

             }

808

809

             /**

810

              * Creates a configuration root node for the specified configuration.

811

              *

812

              * @param cdata the configuration data object

813

              * @return a root node for this configuration

814

              */

815

             private HierarchicalConfiguration.Node createRootNode(AdditionalConfigurationData cdata)

816

             {

817

20

                 if (cdata.getConfiguration() instanceof HierarchicalConfiguration)

818

                 {

819

                     // we can directly use this configuration's root node

820

12

                     return ((HierarchicalConfiguration) cdata.getConfiguration()).getRoot();

821

                 }

822

                 else

823

                 {

824

                     // transform configuration to a hierarchical root node

825

8

                     HierarchicalConfiguration hc = new HierarchicalConfiguration();

826

8

                     ConfigurationUtils.copy(cdata.getConfiguration(), hc);

827

8

                     return hc.getRoot();

828

                 }

829

             }

830

         }

831

     }