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

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

PropertyConverter

98% | 180/184

100% | 59/59

6.0476190476190474;6,048

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.awt.Color;

21

     import java.lang.reflect.Constructor;

22

     import java.lang.reflect.InvocationTargetException;

23

     import java.math.BigDecimal;

24

     import java.math.BigInteger;

25

     import java.net.MalformedURLException;

26

     import java.net.URL;

27

     import java.text.ParseException;

28

     import java.text.SimpleDateFormat;

29

     import java.util.ArrayList;

30

     import java.util.Calendar;

31

     import java.util.Collection;

32

     import java.util.Date;

33

     import java.util.Iterator;

34

     import java.util.List;

35

     import java.util.Locale;

36

37

     import org.apache.commons.collections.IteratorUtils;

38

     import org.apache.commons.collections.iterators.IteratorChain;

39

     import org.apache.commons.collections.iterators.SingletonIterator;

40

     import org.apache.commons.lang.BooleanUtils;

41

     import org.apache.commons.lang.StringUtils;

42

43

     /**

44

      * A utility class to convert the configuration properties into any type.

45

      *

46

      * @author Emmanuel Bourg

47

      * @version $Revision: 442690 $, $Date: 2006-09-12 22:03:18 +0200 (Di, 12 Sep 2006) $

48

      * @since 1.1

49

      */

50

108

     public final class PropertyConverter

51

     {

52

         /** Constant for the list delimiter escaping character.*/

53

         static final String LIST_ESCAPE = "\\";

54

55

         /** Constant for the prefix of hex numbers.*/

56

         private static final String HEX_PREFIX = "0x";

57

58

         /** Constant for the radix of hex numbers.*/

59

         private static final int HEX_RADIX = 16;

60

61

         /** Constant for the argument classes of the Number constructor that takes

62

          * a String.

63

          */

64

53

         private static final Class[] CONSTR_ARGS = {String.class};

65

66

         /**

67

          * Private constructor prevents instances from being created.

68

          */

69

         private PropertyConverter()

70

0

         {

71

             // to prevent instanciation...

72

0

         }

73

74

         /**

75

          * Convert the specified object into a Boolean. Internally the

76

          * <code>org.apache.commons.lang.BooleanUtils</code> class from the

77

          * <a href="http://jakarta.apache.org/commons/lang/">Commons Lang</a>

78

          * project is used to perform this conversion. This class accepts some more

79

          * tokens for the boolean value of <b>true</b>, e.g. <code>yes</code> and

80

          * <code>on</code>. Please refer to the documentation of this class for more

81

          * details.

82

          *

83

          * @param value the value to convert

84

          * @return the converted value

85

          * @throws ConversionException thrown if the value cannot be converted to a boolean

86

          */

87

         public static Boolean toBoolean(Object value) throws ConversionException

88

         {

89

117

             if (value instanceof Boolean)

90

             {

91

42

                 return (Boolean) value;

92

             }

93

75

             else if (value instanceof String)

94

             {

95

73

                 Boolean b = BooleanUtils.toBooleanObject((String) value);

96

73

                 if (b == null)

97

                 {

98

5

                     throw new ConversionException("The value " + value + " can't be converted to a Boolean object");

99

                 }

100

68

                 return b;

101

             }

102

             else

103

             {

104

2

                 throw new ConversionException("The value " + value + " can't be converted to a Boolean object");

105

             }

106

         }

107

108

         /**

109

          * Convert the specified object into a Byte.

110

          *

111

          * @param value the value to convert

112

          * @return the converted value

113

          * @throws ConversionException thrown if the value cannot be converted to a byte

114

          */

115

         public static Byte toByte(Object value) throws ConversionException

116

         {

117

54

             Number n = toNumber(value, Byte.class);

118

48

             if (n instanceof Byte)

119

             {

120

46

                 return (Byte) n;

121

             }

122

             else

123

             {

124

2

                 return new Byte(n.byteValue());

125

             }

126

         }

127

128

         /**

129

          * Convert the specified object into a Short.

130

          *

131

          * @param value the value to convert

132

          * @return the converted value

133

          * @throws ConversionException thrown if the value cannot be converted to a short

134

          */

135

         public static Short toShort(Object value) throws ConversionException

136

         {

137

58

             Number n = toNumber(value, Short.class);

138

52

             if (n instanceof Short)

139

             {

140

51

                 return (Short) n;

141

             }

142

             else

143

             {

144

1

                 return new Short(n.shortValue());

145

             }

146

         }

147

148

         /**

149

          * Convert the specified object into an Integer.

150

          *

151

          * @param value the value to convert

152

          * @return the converted value

153

          * @throws ConversionException thrown if the value cannot be converted to an integer

154

          */

155

         public static Integer toInteger(Object value) throws ConversionException

156

         {

157

76

             Number n = toNumber(value, Integer.class);

158

72

             if (n instanceof Integer)

159

             {

160

71

                 return (Integer) n;

161

             }

162

             else

163

             {

164

1

                 return new Integer(n.intValue());

165

             }

166

         }

167

168

         /**

169

          * Convert the specified object into a Long.

170

          *

171

          * @param value the value to convert

172

          * @return the converted value

173

          * @throws ConversionException thrown if the value cannot be converted to a Long

174

          */

175

         public static Long toLong(Object value) throws ConversionException

176

         {

177

55

             Number n = toNumber(value, Long.class);

178

49

             if (n instanceof Long)

179

             {

180

46

                 return (Long) n;

181

             }

182

             else

183

             {

184

3

                 return new Long(n.longValue());

185

             }

186

         }

187

188

         /**

189

          * Convert the specified object into a Float.

190

          *

191

          * @param value the value to convert

192

          * @return the converted value

193

          * @throws ConversionException thrown if the value cannot be converted to a Float

194

          */

195

         public static Float toFloat(Object value) throws ConversionException

196

         {

197

53

             Number n = toNumber(value, Float.class);

198

47

             if (n instanceof Float)

199

             {

200

46

                 return (Float) n;

201

             }

202

             else

203

             {

204

1

                 return new Float(n.floatValue());

205

             }

206

         }

207

208

         /**

209

          * Convert the specified object into a Double.

210

          *

211

          * @param value the value to convert

212

          * @return the converted value

213

          * @throws ConversionException thrown if the value cannot be converted to a Double

214

          */

215

         public static Double toDouble(Object value) throws ConversionException

216

         {

217

54

             Number n = toNumber(value, Double.class);

218

48

             if (n instanceof Double)

219

             {

220

47

                 return (Double) n;

221

             }

222

             else

223

             {

224

1

                 return new Double(n.doubleValue());

225

             }

226

         }

227

228

         /**

229

          * Convert the specified object into a BigInteger.

230

          *

231

          * @param value the value to convert

232

          * @return the converted value

233

          * @throws ConversionException thrown if the value cannot be converted to a BigInteger

234

          */

235

         public static BigInteger toBigInteger(Object value) throws ConversionException

236

         {

237

41

             Number n = toNumber(value, BigInteger.class);

238

35

             if (n instanceof BigInteger)

239

             {

240

34

                 return (BigInteger) n;

241

             }

242

             else

243

             {

244

1

                 return BigInteger.valueOf(n.longValue());

245

             }

246

         }

247

248

         /**

249

          * Convert the specified object into a BigDecimal.

250

          *

251

          * @param value the value to convert

252

          * @return the converted value

253

          * @throws ConversionException thrown if the value cannot be converted to a BigDecimal

254

          */

255

         public static BigDecimal toBigDecimal(Object value) throws ConversionException

256

         {

257

40

             Number n = toNumber(value, BigDecimal.class);

258

34

             if (n instanceof BigDecimal)

259

             {

260

33

                 return (BigDecimal) n;

261

             }

262

             else

263

             {

264

1

                 return new BigDecimal(n.doubleValue());

265

             }

266

         }

267

268

         /**

269

          * Tries to convert the specified object into a number object. This method

270

          * is used by the conversion methods for number types. Note that the return

271

          * value is not in always of the specified target class, but only if a new

272

          * object has to be created.

273

          *

274

          * @param value the value to be converted (must not be <b>null</b>)

275

          * @param targetClass the target class of the conversion (must be derived

276

          * from <code>java.lang.Number</code>)

277

          * @return the converted number

278

          * @throws ConversionException if the object cannot be converted

279

          */

280

         static Number toNumber(Object value, Class targetClass)

281

                 throws ConversionException

282

         {

283

439

             if (value instanceof Number)

284

             {

285

157

                 return (Number) value;

286

             }

287

             else

288

             {

289

282

                 String str = value.toString();

290

282

                 if (str.startsWith(HEX_PREFIX))

291

                 {

292

                     try

293

                     {

294

7

                         return new BigInteger(str.substring(HEX_PREFIX.length()),

295

                                 HEX_RADIX);

296

                     }

297

                     catch (NumberFormatException nex)

298

                     {

299

1

                         throw new ConversionException("Could not convert " + str

300

                                 + " to " + targetClass.getName()

301

                                 + "! Invalid hex number.", nex);

302

                     }

303

                 }

304

305

                 try

306

                 {

307

275

                     Constructor constr = targetClass.getConstructor(CONSTR_ARGS);

308

274

                     return (Number) constr.newInstance(new Object[]{str});

309

                 }

310

                 catch (InvocationTargetException itex)

311

                 {

312

47

                     throw new ConversionException("Could not convert " + str

313

                             + " to " + targetClass.getName(), itex

314

                             .getTargetException());

315

                 }

316

                 catch (Exception ex)

317

                 {

318

                     // Treat all possible exceptions the same way

319

1

                     throw new ConversionException(

320

                             "Conversion error when trying to convert " + str

321

                                     + " to " + targetClass.getName(), ex);

322

                 }

323

             }

324

         }

325

326

         /**

327

          * Convert the specified object into an URL.

328

          *

329

          * @param value the value to convert

330

          * @return the converted value

331

          * @throws ConversionException thrown if the value cannot be converted to an URL

332

          */

333

         public static URL toURL(Object value) throws ConversionException

334

         {

335

35

             if (value instanceof URL)

336

             {

337

15

                 return (URL) value;

338

             }

339

20

             else if (value instanceof String)

340

             {

341

                 try

342

                 {

343

18

                     return new URL((String) value);

344

                 }

345

                 catch (MalformedURLException e)

346

                 {

347

2

                     throw new ConversionException("The value " + value + " can't be converted to an URL", e);

348

                 }

349

             }

350

             else

351

             {

352

2

                 throw new ConversionException("The value " + value + " can't be converted to an URL");

353

             }

354

         }

355

356

         /**

357

          * Convert the specified object into a Locale.

358

          *

359

          * @param value the value to convert

360

          * @return the converted value

361

          * @throws ConversionException thrown if the value cannot be converted to a Locale

362

          */

363

         public static Locale toLocale(Object value) throws ConversionException

364

         {

365

40

             if (value instanceof Locale)

366

             {

367

14

                 return (Locale) value;

368

             }

369

26

             else if (value instanceof String)

370

             {

371

24

                 List elements = split((String) value, '_');

372

24

                 int size = elements.size();

373

374

24

                 if (size >= 1 && (((String) elements.get(0)).length() == 2 || ((String) elements.get(0)).length() == 0))

375

                 {

376

22

                     String language = (String) elements.get(0);

377

22

                     String country = (String) ((size >= 2) ? elements.get(1) : "");

378

22

                     String variant = (String) ((size >= 3) ? elements.get(2) : "");

379

380

22

                     return new Locale(language, country, variant);

381

                 }

382

                 else

383

                 {

384

2

                     throw new ConversionException("The value " + value + " can't be converted to a Locale");

385

                 }

386

             }

387

             else

388

             {

389

2

                 throw new ConversionException("The value " + value + " can't be converted to a Locale");

390

             }

391

         }

392

393

         /**

394

          * Split a string on the specified delimiter. To be removed when

395

          * commons-lang has a better replacement available (Tokenizer?).

396

          *

397

          * todo: replace with a commons-lang equivalent

398

          *

399

          * @param s          the string to split

400

          * @param delimiter  the delimiter

401

          * @return a list with the single tokens

402

          */

403

         public static List split(String s, char delimiter)

404

         {

405

10079

             if (s == null)

406

             {

407

9

                 return new ArrayList();

408

             }

409

410

10070

             List list = new ArrayList();

411

412

10070

             StringBuffer token = new StringBuffer();

413

10070

             int begin = 0;

414

10070

             int end = 0;

415

33813

             while (begin <= s.length())

416

             {

417

                 // find the next delimiter

418

13673

                 int index = s.indexOf(delimiter, end);

419

420

                 // move the end index at the end of the string if the delimiter is not found

421

13673

                 end = (index != -1) ? index : s.length();

422

423

                 // extract the chunk

424

13673

                 String chunk = s.substring(begin , end);

425

426

13673

                 if (chunk.endsWith(LIST_ESCAPE) && end != s.length())

427

                 {

428

936

                     token.append(chunk.substring(0, chunk.length() - 1));

429

936

                     token.append(delimiter);

430

                 }

431

                 else

432

                 {

433

                     // append the chunk to the token

434

12737

                     token.append(chunk);

435

436

                     // add the token to the list

437

12737

                     list.add(token.toString().trim());

438

439

                     // reset the token

440

12737

                     token = new StringBuffer();

441

                 }

442

443

                 // move to the next chunk

444

13673

                 end = end + 1;

445

13673

                 begin = end;

446

             }

447

448

10070

             return list;

449

         }

450

451

         /**

452

          * Escapes the delimiters that might be contained in the given string. This

453

          * method ensures that list delimiter characters that are part of a

454

          * property's value are correctly escaped when a configuration is saved to a

455

          * file. Otherwise when loaded again the property will be treated as a list

456

          * property.

457

          *

458

          * @param s the string with the value

459

          * @param delimiter the list delimiter to use

460

          * @return the correctly esaped string

461

          */

462

         public static String escapeDelimiters(String s, char delimiter)

463

         {

464

105

             return StringUtils.replace(s, String.valueOf(delimiter), LIST_ESCAPE

465

                     + delimiter);

466

         }

467

468

         /**

469

          * Convert the specified object into a Color. If the value is a String,

470

          * the format allowed is (#)?[0-9A-F]{6}([0-9A-F]{2})?. Examples:

471

          * <ul>

472

          *   <li>FF0000 (red)</li>

473

          *   <li>0000FFA0 (semi transparent blue)</li>

474

          *   <li>#CCCCCC (gray)</li>

475

          *   <li>#00FF00A0 (semi transparent green)</li>

476

          * </ul>

477

          *

478

          * @param value the value to convert

479

          * @return the converted value

480

          * @throws ConversionException thrown if the value cannot be converted to a Color

481

          */

482

         public static Color toColor(Object value) throws ConversionException

483

         {

484

36

             if (value instanceof Color)

485

             {

486

14

                 return (Color) value;

487

             }

488

22

             else if (value instanceof String && !StringUtils.isBlank((String) value))

489

             {

490

20

                 String color = ((String) value).trim();

491

492

20

                 int[] components = new int[3];

493

494

                 // check the size of the string

495

20

                 int minlength = components.length * 2;

496

20

                 if (color.length() < minlength)

497

                 {

498

0

                     throw new ConversionException("The value " + value + " can't be converted to a Color");

499

                 }

500

501

                 // remove the leading #

502

20

                 if (color.startsWith("#"))

503

                 {

504

2

                     color = color.substring(1);

505

                 }

506

507

                 try

508

                 {

509

                     // parse the components

510

74

                     for (int i = 0; i < components.length; i++)

511

                     {

512

56

                         components[i] = Integer.parseInt(color.substring(2 * i, 2 * i + 2), HEX_RADIX);

513

                     }

514

515

                     // parse the transparency

516

                     int alpha;

517

18

                     if (color.length() >= minlength + 2)

518

                     {

519

1

                         alpha = Integer.parseInt(color.substring(minlength, minlength + 2), HEX_RADIX);

520

                     }

521

                     else

522

                     {

523

17

                         alpha = Color.black.getAlpha();

524

                     }

525

526

18

                     return new Color(components[0], components[1], components[2], alpha);

527

                 }

528

                 catch (Exception e)

529

                 {

530

2

                     throw new ConversionException("The value " + value + " can't be converted to a Color", e);

531

                 }

532

             }

533

             else

534

             {

535

2

                 throw new ConversionException("The value " + value + " can't be converted to a Color");

536

             }

537

         }

538

539

         /**

540

          * Convert the specified object into a Date.

541

          *

542

          * @param value  the value to convert

543

          * @param format the DateFormat pattern to parse String values

544

          * @return the converted value

545

          * @throws ConversionException thrown if the value cannot be converted to a Calendar

546

          */

547

         public static Date toDate(Object value, String format) throws ConversionException

548

         {

549

42

             if (value instanceof Date)

550

             {

551

15

                 return (Date) value;

552

             }

553

27

             else if (value instanceof Calendar)

554

             {

555

5

                 return ((Calendar) value).getTime();

556

             }

557

22

             else if (value instanceof String)

558

             {

559

                 try

560

                 {

561

20

                     return new SimpleDateFormat(format).parse((String) value);

562

                 }

563

                 catch (ParseException e)

564

                 {

565

2

                     throw new ConversionException("The value " + value + " can't be converted to a Date", e);

566

                 }

567

             }

568

             else

569

             {

570

2

                 throw new ConversionException("The value " + value + " can't be converted to a Date");

571

             }

572

         }

573

574

         /**

575

          * Convert the specified object into a Calendar.

576

          *

577

          * @param value  the value to convert

578

          * @param format the DateFormat pattern to parse String values

579

          * @return the converted value

580

          * @throws ConversionException thrown if the value cannot be converted to a Calendar

581

          */

582

         public static Calendar toCalendar(Object value, String format) throws ConversionException

583

         {

584

40

             if (value instanceof Calendar)

585

             {

586

10

                 return (Calendar) value;

587

             }

588

30

             else if (value instanceof Date)

589

             {

590

10

                 Calendar calendar = Calendar.getInstance();

591

10

                 calendar.setTime((Date) value);

592

10

                 return calendar;

593

             }

594

20

             else if (value instanceof String)

595

             {

596

                 try

597

                 {

598

18

                     Calendar calendar = Calendar.getInstance();

599

18

                     calendar.setTime(new SimpleDateFormat(format).parse((String) value));

600

16

                     return calendar;

601

                 }

602

                 catch (ParseException e)

603

                 {

604

2

                     throw new ConversionException("The value " + value + " can't be converted to a Calendar", e);

605

                 }

606

             }

607

             else

608

             {

609

2

                 throw new ConversionException("The value " + value + " can't be converted to a Calendar");

610

             }

611

         }

612

613

         /**

614

          * Return an iterator over the simple values of a composite value. The value

615

          * specified is handled depending on its type:

616

          * <ul>

617

          *   <li>Strings are checked for delimiter characters and splitted if necessary.</li>

618

          *   <li>For collections the single elements are checked.</li>

619

          *   <li>Arrays are treated like collections.</li>

620

          *   <li>All other types are directly inserted.</li>

621

          *   <li>Recursive combinations are supported, e.g. a collection containing array that contain strings.</li>

622

          * </ul>

623

          *

624

          * @param value     the value to "split"

625

          * @param delimiter the delimiter for String values

626

          * @return an iterator for accessing the single values

627

          */

628

         public static Iterator toIterator(Object value, char delimiter)

629

         {

630

42069

             if (value == null)

631

             {

632

3

                 return IteratorUtils.emptyIterator();

633

             }

634

42066

             if (value instanceof String)

635

             {

636

28736

                 String s = (String) value;

637

28736

                 if (s.indexOf(delimiter) > 0)

638

                 {

639

2057

                     return split((String) value, delimiter).iterator();

640

                 }

641

                 else

642

                 {

643

26679

                     return new SingletonIterator(value);

644

                 }

645

             }

646

13330

             else if (value instanceof Collection)

647

             {

648

698

                 return toIterator(((Collection) value).iterator(), delimiter);

649

             }

650

12632

             else if (value.getClass().isArray())

651

             {

652

810

                 return toIterator(IteratorUtils.arrayIterator(value), delimiter);

653

             }

654

11822

             else if (value instanceof Iterator)

655

             {

656

1508

                 Iterator iterator = (Iterator) value;

657

1508

                 IteratorChain chain = new IteratorChain();

658

6234

                 while (iterator.hasNext())

659

                 {

660

3218

                     chain.addIterator(toIterator(iterator.next(), delimiter));

661

                 }

662

1508

                 return chain;

663

             }

664

             else

665

             {

666

10314

                 return new SingletonIterator(value);

667

             }

668

         }

669

670

         /**

671

          * Performs interpolation of the specified value. This method checks if the

672

          * given value contains variables of the form <code>${...}</code>. If

673

          * this is the case, all occurrances will be substituted by their current

674

          * values.

675

          *

676

          * @param value the value to be interpolated

677

          * @param config the current configuration object

678

          * @return the interpolated value

679

          */

680

         public static Object interpolate(Object value, AbstractConfiguration config)

681

         {

682

2139

             if (value instanceof String)

683

             {

684

1424

                 return interpolateHelper((String) value, null, config);

685

             }

686

             else

687

             {

688

715

                 return value;

689

             }

690

         }

691

692

         /**

693

          * Recursive handler for multple levels of interpolation. This will be

694

          * replaced when Commons Lang provides an interpolation feature. When called

695

          * the first time, priorVariables should be null.

696

          *

697

          * @param base string with the ${key} variables

698

          * @param priorVariables serves two purposes: to allow checking for loops,

699

          * and creating a meaningful exception message should a loop occur. It's

700

          * 0'th element will be set to the value of base from the first call. All

701

          * subsequent interpolated variables are added afterward.

702

          * @param config the current configuration

703

          * @return the string with the interpolation taken care of

704

          */

705

         private static String interpolateHelper(String base, List priorVariables,

706

                 AbstractConfiguration config)

707

         {

708

1529

             if (base == null)

709

             {

710

0

                 return null;

711

             }

712

713

             // on the first call initialize priorVariables

714

             // and add base as the first element

715

1529

             if (priorVariables == null)

716

             {

717

1424

                 priorVariables = new ArrayList();

718

1424

                 priorVariables.add(base);

719

             }

720

721

1529

             int begin = -1;

722

1529

             int end = -1;

723

1529

             int prec = 0 - AbstractConfiguration.END_TOKEN.length();

724

1529

             StringBuffer result = new StringBuffer();

725

726

             // FIXME: we should probably allow the escaping of the start token

727

1529

             while (((begin = base.indexOf(AbstractConfiguration.START_TOKEN, prec

728

                     + AbstractConfiguration.END_TOKEN.length())) > -1)

729

1637

                     && ((end = base.indexOf(AbstractConfiguration.END_TOKEN, begin)) > -1))

730

             {

731

117

                 result.append(base.substring(prec

732

                         + AbstractConfiguration.END_TOKEN.length(), begin));

733

117

                 String variable = base.substring(begin

734

                         + AbstractConfiguration.START_TOKEN.length(), end);

735

736

                 // if we've got a loop, create a useful exception message and throw

737

117

                 if (priorVariables.contains(variable))

738

                 {

739

3

                     String initialBase = priorVariables.remove(0).toString();

740

3

                     priorVariables.add(variable);

741

3

                     StringBuffer priorVariableSb = new StringBuffer();

742

743

                     // create a nice trace of interpolated variables like so:

744

                     // var1->var2->var3

745

15

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

746

                     {

747

9

                         priorVariableSb.append(it.next());

748

9

                         if (it.hasNext())

749

                         {

750

6

                             priorVariableSb.append("->");

751

                         }

752

                     }

753

754

3

                     throw new IllegalStateException(

755

                             "infinite loop in property interpolation of "

756

                                     + initialBase + ": "

757

                                     + priorVariableSb.toString());

758

                 }

759

                 // otherwise, add this variable to the interpolation list.

760

                 else

761

                 {

762

114

                     priorVariables.add(variable);

763

                 }

764

765

114

                 Object value = config.resolveContainerStore(variable);

766

114

                 if (value != null)

767

                 {

768

105

                     result.append(interpolateHelper(value.toString(),

769

                             priorVariables, config));

770

771

                     // pop the interpolated variable off the stack

772

                     // this maintains priorVariables correctness for

773

                     // properties with multiple interpolations, e.g.

774

                     // prop.name=${some.other.prop1}/blahblah/${some.other.prop2}

775

99

                     priorVariables.remove(priorVariables.size() - 1);

776

                 }

777

                 else

778

                 {

779

                     // variable not defined - so put it back in the value

780

9

                     result.append(AbstractConfiguration.START_TOKEN);

781

9

                     result.append(variable);

782

9

                     result.append(AbstractConfiguration.END_TOKEN);

783

                 }

784

785

108

                 prec = end;

786

             }

787

1520

             result.append(base.substring(prec

788

                     + AbstractConfiguration.END_TOKEN.length(), base.length()));

789

1520

             return result.toString();

790

         }

791

     }