##### Coverage Report - org.apache.commons.configuration.tree.DefaultConfigurationKey

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

DefaultConfigurationKey

99% | 68/69

100% | 19/19

1.9555555555555555;1,956

DefaultConfigurationKey$KeyIterator

95% | 70/74

100% | 19/19

1.9555555555555555;1,956

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

     package org.apache.commons.configuration.tree;

18

19

     import java.util.Iterator;

20

     import java.util.NoSuchElementException;

21

22

     import org.apache.commons.lang.StringUtils;

23

24

     /**

25

      * <p>

26

      * A simple class that supports creation of and iteration on configuration keys

27

      * supported by a <code>{@link DefaultExpressionEngine}</code> object.

28

      * </p>

29

      * <p>

30

      * For key creation the class works similar to a StringBuffer: There are several

31

      * <code>appendXXXX()</code> methods with which single parts of a key can be

32

      * constructed. All these methods return a reference to the actual object so

33

      * they can be written in a chain. When using this methods the exact syntax for

34

      * keys need not be known.

35

      * </p>

36

      * <p>

37

      * This class also defines a specialized iterator for configuration keys. With

38

      * such an iterator a key can be tokenized into its single parts. For each part

39

      * it can be checked whether it has an associated index.

40

      * </p>

41

      * <p>

42

      * Instances of this class are always associated with an instance of

43

      * <code>{@link DefaultExpressionEngine}</code>, from which the current

44

      * delimiters are obtained. So key creation and parsing is specific to this

45

      * associated expression engine.

46

      * </p>

47

      *

48

      * @since 1.3

49

      * @author Oliver Heger

50

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

51

      */

52

115002

     public class DefaultConfigurationKey

53

     {

54

         /** Constant for the initial StringBuffer size. */

55

         private static final int INITIAL_SIZE = 32;

56

57

         /** Stores a reference to the associated expression engine. */

58

         private DefaultExpressionEngine expressionEngine;

59

60

         /** Holds a buffer with the so far created key. */

61

         private StringBuffer keyBuffer;

62

63

         /**

64

          * Creates a new instance of <code>DefaultConfigurationKey</code> and sets

65

          * the associated expression engine.

66

          *

67

          * @param engine the expression engine

68

          */

69

         public DefaultConfigurationKey(DefaultExpressionEngine engine)

70

28

         {

71

28

             keyBuffer = new StringBuffer(INITIAL_SIZE);

72

28

             setExpressionEngine(engine);

73

28

         }

74

75

         /**

76

          * Creates a new instance of <code>DefaultConfigurationKey</code> and sets

77

          * the associated expression engine and an initial key.

78

          *

79

          * @param engine the expression engine

80

          * @param key the key to be wrapped

81

          */

82

         public DefaultConfigurationKey(DefaultExpressionEngine engine, String key)

83

5534

         {

84

5534

             setExpressionEngine(engine);

85

5534

             keyBuffer = new StringBuffer(trim(key));

86

5534

         }

87

88

         /**

89

          * Returns the associated default expression engine.

90

          *

91

          * @return the associated expression engine

92

          */

93

         public DefaultExpressionEngine getExpressionEngine()

94

         {

95

174131

             return expressionEngine;

96

         }

97

98

         /**

99

          * Sets the associated expression engine.

100

          *

101

          * @param expressionEngine the expression engine (must not be <b>null</b>)

102

          */

103

         public void setExpressionEngine(DefaultExpressionEngine expressionEngine)

104

         {

105

5563

             if (expressionEngine == null)

106

             {

107

1

                 throw new IllegalArgumentException(

108

                         "Expression engine must not be null!");

109

             }

110

5562

             this.expressionEngine = expressionEngine;

111

5562

         }

112

113

         /**

114

          * Appends the name of a property to this key. If necessary, a property

115

          * delimiter will be added. If the boolean argument is set to <b>true</b>,

116

          * property delimiters contained in the property name will be escaped.

117

          *

118

          * @param property the name of the property to be added

119

          * @param escape a flag if property delimiters in the passed in property name

120

          * should be escaped

121

          * @return a reference to this object

122

          */

123

         public DefaultConfigurationKey append(String property, boolean escape)

124

         {

125

             String key;

126

785

             if (escape && property != null)

127

             {

128

749

                 key = escapeDelimiters(property);

129

             }

130

             else

131

             {

132

36

                 key = property;

133

             }

134

785

             key = trim(key);

135

136

785

             if (keyBuffer.length() > 0 && !isAttributeKey(property)

137

                     && key.length() > 0)

138

             {

139

578

                 keyBuffer.append(getExpressionEngine().getPropertyDelimiter());

140

             }

141

142

785

             keyBuffer.append(key);

143

785

             return this;

144

         }

145

146

         /**

147

          * Appends the name of a property to this key. If necessary, a property

148

          * delimiter will be added. Property delimiters in the given string will not

149

          * be escaped.

150

          *

151

          * @param property the name of the property to be added

152

          * @return a reference to this object

153

          */

154

         public DefaultConfigurationKey append(String property)

155

         {

156

35

             return append(property, false);

157

         }

158

159

         /**

160

          * Appends an index to this configuration key.

161

          *

162

          * @param index the index to be appended

163

          * @return a reference to this object

164

          */

165

         public DefaultConfigurationKey appendIndex(int index)

166

         {

167

4

             keyBuffer.append(getExpressionEngine().getIndexStart());

168

4

             keyBuffer.append(index);

169

4

             keyBuffer.append(getExpressionEngine().getIndexEnd());

170

4

             return this;

171

         }

172

173

         /**

174

          * Appends an attribute to this configuration key.

175

          *

176

          * @param attr the name of the attribute to be appended

177

          * @return a reference to this object

178

          */

179

         public DefaultConfigurationKey appendAttribute(String attr)

180

         {

181

151

             keyBuffer.append(constructAttributeKey(attr));

182

151

             return this;

183

         }

184

185

         /**

186

          * Returns the actual length of this configuration key.

187

          *

188

          * @return the length of this key

189

          */

190

         public int length()

191

         {

192

41381

             return keyBuffer.length();

193

         }

194

195

         /**

196

          * Sets the new length of this configuration key. With this method it is

197

          * possible to truncate the key, e.g. to return to a state prior calling

198

          * some <code>append()</code> methods. The semantic is the same as the

199

          * <code>setLength()</code> method of <code>StringBuffer</code>.

200

          *

201

          * @param len the new length of the key

202

          */

203

         public void setLength(int len)

204

         {

205

1

             keyBuffer.setLength(len);

206

1

         }

207

208

         /**

209

          * Checks if two <code>ConfigurationKey</code> objects are equal. The

210

          * method can be called with strings or other objects, too.

211

          *

212

          * @param c the object to compare

213

          * @return a flag if both objects are equal

214

          */

215

         public boolean equals(Object c)

216

         {

217

6

             if (c == null)

218

             {

219

1

                 return false;

220

             }

221

222

5

             return keyBuffer.toString().equals(c.toString());

223

         }

224

225

         /**

226

          * Returns the hash code for this object.

227

          *

228

          * @return the hash code

229

          */

230

         public int hashCode()

231

         {

232

2

             return String.valueOf(keyBuffer).hashCode();

233

         }

234

235

         /**

236

          * Returns a string representation of this object. This is the configuration

237

          * key as a plain string.

238

          *

239

          * @return a string for this object

240

          */

241

         public String toString()

242

         {

243

912

             return keyBuffer.toString();

244

         }

245

246

         /**

247

          * Tests if the specified key represents an attribute according to the

248

          * current expression engine.

249

          *

250

          * @param key the key to be checked

251

          * @return <b>true</b> if this is an attribute key, <b>false</b> otherwise

252

          */

253

         public boolean isAttributeKey(String key)

254

         {

255

12586

             if (key == null)

256

             {

257

4

                 return false;

258

             }

259

260

12582

             return key.startsWith(getExpressionEngine().getAttributeStart())

261

                     && (getExpressionEngine().getAttributeEnd() == null || key

262

                             .endsWith(getExpressionEngine().getAttributeEnd()));

263

         }

264

265

         /**

266

          * Decorates the given key so that it represents an attribute. Adds special

267

          * start and end markers. The passed in string will be modified only if does

268

          * not already represent an attribute.

269

          *

270

          * @param key the key to be decorated

271

          * @return the decorated attribute key

272

          */

273

         public String constructAttributeKey(String key)

274

         {

275

158

             if (key == null)

276

             {

277

2

                 return StringUtils.EMPTY;

278

             }

279

156

             if (isAttributeKey(key))

280

             {

281

3

                 return key;

282

             }

283

             else

284

             {

285

153

                 StringBuffer buf = new StringBuffer();

286

153

                 buf.append(getExpressionEngine().getAttributeStart()).append(key);

287

153

                 if (getExpressionEngine().getAttributeEnd() != null)

288

                 {

289

150

                     buf.append(getExpressionEngine().getAttributeEnd());

290

                 }

291

153

                 return buf.toString();

292

             }

293

         }

294

295

         /**

296

          * Extracts the name of the attribute from the given attribute key. This

297

          * method removes the attribute markers - if any - from the specified key.

298

          *

299

          * @param key the attribute key

300

          * @return the name of the corresponding attribute

301

          */

302

         public String attributeName(String key)

303

         {

304

3

             return isAttributeKey(key) ? removeAttributeMarkers(key) : key;

305

         }

306

307

         /**

308

          * Removes leading property delimiters from the specified key.

309

          *

310

          * @param key the key

311

          * @return the key with removed leading property delimiters

312

          */

313

         public String trimLeft(String key)

314

         {

315

6324

             if (key == null)

316

             {

317

19

                 return StringUtils.EMPTY;

318

             }

319

             else

320

             {

321

6305

                 String result = key;

322

12626

                 while (hasLeadingDelimiter(result))

323

                 {

324

16

                     result = result.substring(getExpressionEngine()

325

                             .getPropertyDelimiter().length());

326

                 }

327

6305

                 return result;

328

             }

329

         }

330

331

         /**

332

          * Removes trailing property delimiters from the specified key.

333

          *

334

          * @param key the key

335

          * @return the key with removed trailing property delimiters

336

          */

337

         public String trimRight(String key)

338

         {

339

6324

             if (key == null)

340

             {

341

0

                 return StringUtils.EMPTY;

342

             }

343

             else

344

             {

345

6324

                 String result = key;

346

12662

                 while (hasTrailingDelimiter(result))

347

                 {

348

14

                     result = result

349

                             .substring(0, result.length()

350

                                     - getExpressionEngine().getPropertyDelimiter()

351

                                             .length());

352

                 }

353

6324

                 return result;

354

             }

355

         }

356

357

         /**

358

          * Removes delimiters at the beginning and the end of the specified key.

359

          *

360

          * @param key the key

361

          * @return the key with removed property delimiters

362

          */

363

         public String trim(String key)

364

         {

365

6322

             return trimRight(trimLeft(key));

366

         }

367

368

         /**

369

          * Returns an iterator for iterating over the single components of this

370

          * configuration key.

371

          *

372

          * @return an iterator for this key

373

          */

374

         public KeyIterator iterator()

375

         {

376

4646

             return new KeyIterator();

377

         }

378

379

         /**

380

          * Helper method that checks if the specified key ends with a property

381

          * delimiter.

382

          *

383

          * @param key the key to check

384

          * @return a flag if there is a trailing delimiter

385

          */

386

         private boolean hasTrailingDelimiter(String key)

387

         {

388

6338

             return key.endsWith(getExpressionEngine().getPropertyDelimiter())

389

                     && (getExpressionEngine().getEscapedDelimiter() == null || !key

390

                             .endsWith(getExpressionEngine().getEscapedDelimiter()));

391

         }

392

393

         /**

394

          * Helper method that checks if the specified key starts with a property

395

          * delimiter.

396

          *

397

          * @param key the key to check

398

          * @return a flag if there is a leading delimiter

399

          */

400

         private boolean hasLeadingDelimiter(String key)

401

         {

402

24769

             return key.startsWith(getExpressionEngine().getPropertyDelimiter())

403

                     && (getExpressionEngine().getEscapedDelimiter() == null || !key

404

                             .startsWith(getExpressionEngine().getEscapedDelimiter()));

405

         }

406

407

         /**

408

          * Helper method for removing attribute markers from a key.

409

          *

410

          * @param key the key

411

          * @return the key with removed attribute markers

412

          */

413

         private String removeAttributeMarkers(String key)

414

         {

415

889

             return key

416

                     .substring(

417

                             getExpressionEngine().getAttributeStart().length(),

418

                             key.length()

419

                                     - ((getExpressionEngine().getAttributeEnd() != null) ? getExpressionEngine()

420

                                             .getAttributeEnd().length()

421

                                             : 0));

422

         }

423

424

         /**

425

          * Unescapes the delimiters in the specified string.

426

          *

427

          * @param key the key to be unescaped

428

          * @return the unescaped key

429

          */

430

         private String unescapeDelimiters(String key)

431

         {

432

11839

             return (getExpressionEngine().getEscapedDelimiter() == null) ? key

433

                     : StringUtils.replace(key, getExpressionEngine()

434

                             .getEscapedDelimiter(), getExpressionEngine()

435

                             .getPropertyDelimiter());

436

         }

437

438

         /**

439

          * Escapes the delimiters in the specified string.

440

          *

441

          * @param key the key to be escaped

442

          * @return the escaped key

443

          */

444

         private String escapeDelimiters(String key)

445

         {

446

749

             return (getExpressionEngine().getEscapedDelimiter() == null || key

447

                     .indexOf(getExpressionEngine().getPropertyDelimiter()) < 0) ? key

448

                     : StringUtils.replace(key, getExpressionEngine()

449

                             .getPropertyDelimiter(), getExpressionEngine()

450

                             .getEscapedDelimiter());

451

         }

452

453

         /**

454

          * A specialized iterator class for tokenizing a configuration key. This

455

          * class implements the normal iterator interface. In addition it provides

456

          * some specific methods for configuration keys.

457

          */

458

4646

         public class KeyIterator implements Iterator, Cloneable

459

         {

460

             /** Stores the current key name. */

461

             private String current;

462

463

             /** Stores the start index of the actual token. */

464

             private int startIndex;

465

466

             /** Stores the end index of the actual token. */

467

             private int endIndex;

468

469

             /** Stores the index of the actual property if there is one. */

470

             private int indexValue;

471

472

             /** Stores a flag if the actual property has an index. */

473

             private boolean hasIndex;

474

475

             /** Stores a flag if the actual property is an attribute. */

476

             private boolean attribute;

477

478

             /**

479

              * Returns the next key part of this configuration key. This is a short

480

              * form of <code>nextKey(false)</code>.

481

              *

482

              * @return the next key part

483

              */

484

             public String nextKey()

485

             {

486

824

                 return nextKey(false);

487

             }

488

489

             /**

490

              * Returns the next key part of this configuration key. The boolean

491

              * parameter indicates wheter a decorated key should be returned. This

492

              * affects only attribute keys: if the parameter is <b>false</b>, the

493

              * attribute markers are stripped from the key; if it is <b>true</b>,

494

              * they remain.

495

              *

496

              * @param decorated a flag if the decorated key is to be returned

497

              * @return the next key part

498

              */

499

             public String nextKey(boolean decorated)

500

             {

501

11840

                 if (!hasNext())

502

                 {

503

1

                     throw new NoSuchElementException("No more key parts!");

504

                 }

505

506

11839

                 hasIndex = false;

507

11839

                 indexValue = -1;

508

11839

                 String key = findNextIndices();

509

510

11839

                 current = key;

511

11839

                 hasIndex = checkIndex(key);

512

11839

                 attribute = checkAttribute(current);

513

514

11839

                 return currentKey(decorated);

515

             }

516

517

             /**

518

              * Checks if there is a next element.

519

              *

520

              * @return a flag if there is a next element

521

              */

522

             public boolean hasNext()

523

             {

524

29862

                 return endIndex < keyBuffer.length();

525

             }

526

527

             /**

528

              * Returns the next object in the iteration.

529

              *

530

              * @return the next object

531

              */

532

             public Object next()

533

             {

534

801

                 return nextKey();

535

             }

536

537

             /**

538

              * Removes the current object in the iteration. This method is not

539

              * supported by this iterator type, so an exception is thrown.

540

              */

541

             public void remove()

542

             {

543

1

                 throw new UnsupportedOperationException("Remove not supported!");

544

             }

545

546

             /**

547

              * Returns the current key of the iteration (without skipping to the

548

              * next element). This is the same key the previous <code>next()</code>

549

              * call had returned. (Short form of <code>currentKey(false)</code>.

550

              *

551

              * @return the current key

552

              */

553

             public String currentKey()

554

             {

555

2481

                 return currentKey(false);

556

             }

557

558

             /**

559

              * Returns the current key of the iteration (without skipping to the

560

              * next element). The boolean parameter indicates wheter a decorated key

561

              * should be returned. This affects only attribute keys: if the

562

              * parameter is <b>false</b>, the attribute markers are stripped from

563

              * the key; if it is <b>true</b>, they remain.

564

              *

565

              * @param decorated a flag if the decorated key is to be returned

566

              * @return the current key

567

              */

568

             public String currentKey(boolean decorated)

569

             {

570

14325

                 return (decorated && !isPropertyKey()) ? constructAttributeKey(current)

571

                         : current;

572

             }

573

574

             /**

575

              * Returns a flag if the current key is an attribute. This method can be

576

              * called after <code>next()</code>.

577

              *

578

              * @return a flag if the current key is an attribute

579

              */

580

             public boolean isAttribute()

581

             {

582

                 // if attribute emulation mode is active, the last part of a key is

583

                 // always an attribute key, too

584

7193

                 return attribute || (isAttributeEmulatingMode() && !hasNext());

585

             }

586

587

             /**

588

              * Returns a flag whether the current key refers to a property (i.e. is

589

              * no special attribute key). Usually this method will return the

590

              * opposite of <code>isAttribute()</code>, but if the delimiters for

591

              * normal properties and attributes are set to the same string, it is

592

              * possible that both methods return <b>true</b>.

593

              *

594

              * @return a flag if the current key is a property key

595

              * @see #isAttribute()

596

              */

597

             public boolean isPropertyKey()

598

             {

599

12445

                 return !attribute;

600

             }

601

602

             /**

603

              * Returns the index value of the current key. If the current key does

604

              * not have an index, return value is -1. This method can be called

605

              * after <code>next()</code>.

606

              *

607

              * @return the index value of the current key

608

              */

609

             public int getIndex()

610

             {

611

971

                 return indexValue;

612

             }

613

614

             /**

615

              * Returns a flag if the current key has an associated index. This

616

              * method can be called after <code>next()</code>.

617

              *

618

              * @return a flag if the current key has an index

619

              */

620

             public boolean hasIndex()

621

             {

622

9963

                 return hasIndex;

623

             }

624

625

             /**

626

              * Creates a clone of this object.

627

              *

628

              * @return a clone of this object

629

              */

630

             public Object clone()

631

             {

632

                 try

633

                 {

634

7041

                     return super.clone();

635

                 }

636

                 catch (CloneNotSupportedException cex)

637

                 {

638

                     // should not happen

639

0

                     return null;

640

                 }

641

             }

642

643

             /**

644

              * Helper method for determining the next indices.

645

              *

646

              * @return the next key part

647

              */

648

             private String findNextIndices()

649

             {

650

11839

                 startIndex = endIndex;

651

                 // skip empty names

652

11839

                 while (startIndex < length()

653

18448

                         && hasLeadingDelimiter(keyBuffer.substring(startIndex)))

654

                 {

655

6609

                     startIndex += getExpressionEngine().getPropertyDelimiter()

656

                             .length();

657

                 }

658

659

                 // Key ends with a delimiter?

660

11839

                 if (startIndex >= length())

661

                 {

662

0

                     endIndex = length();

663

0

                     startIndex = endIndex - 1;

664

0

                     return keyBuffer.substring(startIndex, endIndex);

665

                 }

666

                 else

667

                 {

668

11839

                     return nextKeyPart();

669

                 }

670

             }

671

672

             /**

673

              * Helper method for extracting the next key part. Takes escaping of

674

              * delimiter characters into account.

675

              *

676

              * @return the next key part

677

              */

678

             private String nextKeyPart()

679

             {

680

11839

                 int attrIdx = keyBuffer.toString().indexOf(

681

                         getExpressionEngine().getAttributeStart(), startIndex);

682

11839

                 if (attrIdx < 0 || attrIdx == startIndex)

683

                 {

684

11091

                     attrIdx = length();

685

                 }

686

687

11839

                 int delIdx = nextDelimiterPos(keyBuffer.toString(), startIndex,

688

                         attrIdx);

689

11839

                 if (delIdx < 0)

690

                 {

691

5544

                     delIdx = attrIdx;

692

                 }

693

694

11839

                 endIndex = Math.min(attrIdx, delIdx);

695

11839

                 return unescapeDelimiters(keyBuffer.substring(startIndex, endIndex));

696

             }

697

698

             /**

699

              * Searches the next unescaped delimiter from the given position.

700

              *

701

              * @param key the key

702

              * @param pos the start position

703

              * @param endPos the end position

704

              * @return the position of the next delimiter or -1 if there is none

705

              */

706

             private int nextDelimiterPos(String key, int pos, int endPos)

707

             {

708

11839

                 int delimiterPos = pos;

709

11839

                 boolean found = false;

710

711

                 do

712

                 {

713

11927

                     delimiterPos = key.indexOf(getExpressionEngine()

714

                             .getPropertyDelimiter(), delimiterPos);

715

11927

                     if (delimiterPos < 0 || delimiterPos >= endPos)

716

                     {

717

5544

                         return -1;

718

                     }

719

6383

                     int escapePos = escapedPosition(key, delimiterPos);

720

6383

                     if (escapePos < 0)

721

                     {

722

6295

                         found = true;

723

                     }

724

                     else

725

                     {

726

88

                         delimiterPos = escapePos;

727

                     }

728

                 }

729

6383

                 while (!found);

730

731

6295

                 return delimiterPos;

732

             }

733

734

             /**

735

              * Checks if a delimiter at the specified position is escaped. If this

736

              * is the case, the next valid search position will be returned.

737

              * Otherwise the return value is -1.

738

              *

739

              * @param key the key to check

740

              * @param pos the position where a delimiter was found

741

              * @return information about escaped delimiters

742

              */

743

             private int escapedPosition(String key, int pos)

744

             {

745

6383

                 if (getExpressionEngine().getEscapedDelimiter() == null)

746

                 {

747

                     // nothing to escape

748

13

                     return -1;

749

                 }

750

6370

                 int escapeOffset = escapeOffset();

751

6370

                 if (escapeOffset < 0 || escapeOffset > pos)

752

                 {

753

                     // No escaping possible at this position

754

55

                     return -1;

755

                 }

756

757

6315

                 int escapePos = key.indexOf(getExpressionEngine()

758

                         .getEscapedDelimiter(), pos - escapeOffset);

759

6315

                 if (escapePos <= pos && escapePos >= 0)

760

                 {

761

                     // The found delimiter is escaped. Next valid search position

762

                     // is behind the escaped delimiter.

763

88

                     return escapePos

764

                             + getExpressionEngine().getEscapedDelimiter().length();

765

                 }

766

                 else

767

                 {

768

6227

                     return -1;

769

                 }

770

             }

771

772

             /**

773

              * Determines the relative offset of an escaped delimiter in relation to

774

              * a delimiter. Depending on the used delimiter and escaped delimiter

775

              * tokens the position where to search for an escaped delimiter is

776

              * different. If, for instance, the dot character (&quot;.&quot;) is

777

              * used as delimiter, and a doubled dot (&quot;..&quot;) as escaped

778

              * delimiter, the escaped delimiter starts at the same position as the

779

              * delimiter. If the token &quot;\.&quot; was used, it would start one

780

              * character before the delimiter because the delimiter character

781

              * &quot;.&quot; is the second character in the escaped delimiter

782

              * string. This relation will be determined by this method. For this to

783

              * work the delimiter string must be contained in the escaped delimiter

784

              * string.

785

              *

786

              * @return the relative offset of the escaped delimiter in relation to a

787

              * delimiter

788

              */

789

             private int escapeOffset()

790

             {

791

6370

                 return getExpressionEngine().getEscapedDelimiter().indexOf(

792

                         getExpressionEngine().getPropertyDelimiter());

793

             }

794

795

             /**

796

              * Helper method for checking if the passed key is an attribute. If this

797

              * is the case, the internal fields will be set.

798

              *

799

              * @param key the key to be checked

800

              * @return a flag if the key is an attribute

801

              */

802

             private boolean checkAttribute(String key)

803

             {

804

11839

                 if (isAttributeKey(key))

805

                 {

806

888

                     current = removeAttributeMarkers(key);

807

888

                     return true;

808

                 }

809

                 else

810

                 {

811

10951

                     return false;

812

                 }

813

             }

814

815

             /**

816

              * Helper method for checking if the passed key contains an index. If

817

              * this is the case, internal fields will be set.

818

              *

819

              * @param key the key to be checked

820

              * @return a flag if an index is defined

821

              */

822

             private boolean checkIndex(String key)

823

             {

824

11839

                 boolean result = false;

825

826

11839

                 int idx = key.lastIndexOf(getExpressionEngine().getIndexStart());

827

11839

                 if (idx > 0)

828

                 {

829

481

                     int endidx = key.indexOf(getExpressionEngine().getIndexEnd(),

830

                             idx);

831

832

481

                     if (endidx > idx + 1)

833

                     {

834

479

                         indexValue = Integer.parseInt(key

835

                                 .substring(idx + 1, endidx));

836

479

                         current = key.substring(0, idx);

837

479

                         result = true;

838

                     }

839

                 }

840

841

11839

                 return result;

842

             }

843

844

             /**

845

              * Returns a flag whether attributes are marked the same way as normal

846

              * property keys. We call this the &quot;attribute emulating mode&quot;.

847

              * When navigating through node hierarchies it might be convenient to

848

              * treat attributes the same way than other child nodes, so an

849

              * expression engine supports to set the attribute markers to the same

850

              * value than the property delimiter. If this is the case, some special

851

              * checks have to be performed.

852

              *

853

              * @return a flag if attributes and normal property keys are treated the

854

              * same way

855

              */

856

             private boolean isAttributeEmulatingMode()

857

             {

858

6374

                 return getExpressionEngine().getAttributeEnd() == null

859

                         && StringUtils.equals(getExpressionEngine()

860

                                 .getPropertyDelimiter(), getExpressionEngine()

861

                                 .getAttributeStart());

862

             }

863

         }

864

     }