Coverage report

| %line | %branch
--- | --- | ---

org.apache.commons.jelly.parser.XMLParser

68%

92%

1

     /*

2

      * Copyright 2002,2004 The Apache Software Foundation.

3

      *

4

      * Licensed under the Apache License, Version 2.0 (the "License");

5

      * you may not use this file except in compliance with the License.

6

      * You may obtain a copy of the License at

7

      *

8

      *      http://www.apache.org/licenses/LICENSE-2.0

9

      *

10

      * Unless required by applicable law or agreed to in writing, software

11

      * distributed under the License is distributed on an "AS IS" BASIS,

12

      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

13

      * See the License for the specific language governing permissions and

14

      * limitations under the License.

15

      */

16

     package org.apache.commons.jelly.parser;

17

18

     import java.io.File;

19

     import java.io.InputStream;

20

     import java.io.IOException;

21

     import java.io.Reader;

22

     import java.net.URL;

23

     import java.util.ArrayList;

24

     import java.util.EmptyStackException;

25

     import java.util.HashMap;

26

     import java.util.Iterator;

27

     import java.util.Map;

28

     import java.util.Properties;

29

30

     import javax.xml.parsers.SAXParser;

31

     import javax.xml.parsers.SAXParserFactory;

32

33

     import org.apache.commons.collections.ArrayStack;

34

35

     import org.apache.commons.jelly.JellyContext;

36

     import org.apache.commons.jelly.JellyException;

37

     import org.apache.commons.jelly.Script;

38

     import org.apache.commons.jelly.Tag;

39

     import org.apache.commons.jelly.TagLibrary;

40

     import org.apache.commons.jelly.impl.CompositeTextScriptBlock;

41

     import org.apache.commons.jelly.impl.ExpressionScript;

42

     import org.apache.commons.jelly.impl.StaticTag;

43

     import org.apache.commons.jelly.impl.ScriptBlock;

44

     import org.apache.commons.jelly.impl.StaticTagScript;

45

     import org.apache.commons.jelly.impl.TagFactory;

46

     import org.apache.commons.jelly.impl.TagScript;

47

     import org.apache.commons.jelly.impl.TextScript;

48

     import org.apache.commons.jelly.util.ClassLoaderUtils;

49

     import org.apache.commons.jelly.expression.CompositeExpression;

50

     import org.apache.commons.jelly.expression.ConstantExpression;

51

     import org.apache.commons.jelly.expression.Expression;

52

     import org.apache.commons.jelly.expression.ExpressionFactory;

53

     import org.apache.commons.jelly.expression.jexl.JexlExpressionFactory;

54

55

     import org.apache.commons.logging.Log;

56

     import org.apache.commons.logging.LogFactory;

57

58

     import org.xml.sax.Attributes;

59

     import org.xml.sax.ErrorHandler;

60

     import org.xml.sax.helpers.DefaultHandler;

61

     import org.xml.sax.InputSource;

62

     import org.xml.sax.Locator;

63

     import org.xml.sax.SAXException;

64

     import org.xml.sax.SAXParseException;

65

     import org.xml.sax.XMLReader;

66

     import org.xml.sax.helpers.AttributesImpl;

67

68

     /** <p><code>XMLParser</code> parses the XML Jelly format.

69

      * The SAXParser and XMLReader portions of this code come from Digester.</p>

70

      *

71

      * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>

72

      * @version $Revision: 155420 $

73

      */

74

     public class XMLParser extends DefaultHandler {

75

76

         /**

77

          * Share the Jelly properties across parsers

78

          */

79

         private static Properties jellyProperties;

80

81

82

         /** JellyContext which is used to locate tag libraries*/

83

1027

         private JellyContext context = new JellyContext();

84

85

         /** the expression factory used to evaluate tag attributes */

86

         private ExpressionFactory expressionFactory;

87

88

         /** The current script block */

89

         private ScriptBlock script;

90

91

         /** The current, parent tagScript */

92

         private TagScript tagScript;

93

94

         /** The stack of body scripts. */

95

1027

         private ArrayStack scriptStack = new ArrayStack();

96

97

         /** The stack of tagScripts - use ArrayList as it allows null. */

98

1027

         private ArrayList tagScriptStack = new ArrayList();

99

100

         /** The current text buffer where non-custom tags get written */

101

         private StringBuffer textBuffer;

102

103

         /**

104

          * The class loader to use for instantiating application objects.

105

          * If not specified, the context class loader, or the class loader

106

          * used to load XMLParser itself, is used, based on the value of the

107

          * <code>useContextClassLoader</code> variable.

108

          */

109

1027

         protected ClassLoader classLoader = null;

110

111

         /**

112

          * Do we want to use the Context ClassLoader when loading classes

113

          * for instantiating new objects?  Default is <code>false</code>.

114

          */

115

1027

         protected boolean useContextClassLoader = false;

116

117

         /**

118

          * The application-supplied error handler that is notified when parsing

119

          * warnings, errors, or fatal errors occur.

120

          */

121

1027

         protected ErrorHandler errorHandler = null;

122

123

         /**

124

          * The SAXParserFactory that is created the first time we need it.

125

          */

126

273

         protected static SAXParserFactory factory = null;

127

128

         /**

129

          * The SAXParser we will use to parse the input stream.

130

          */

131

1027

         protected SAXParser parser = null;

132

133

         /**

134

          * The XMLReader used to parse digester rules.

135

          */

136

1027

         protected XMLReader reader = null;

137

138

         /**

139

          * The Locator associated with our parser.

140

          */

141

1027

         protected Locator locator = null;

142

143

         /**

144

          * Registered namespaces we are currently processing.  The key is the

145

          * namespace prefix that was declared in the document.  The value is an

146

          * ArrayStack of the namespace URIs this prefix has been mapped to --

147

          * the top Stack element is the most current one.  (This architecture

148

          * is required because documents can declare nested uses of the same

149

          * prefix for different Namespace URIs).

150

          */

151

1027

         protected Map namespaces = new HashMap();

152

153

         /** The Map of the namespace prefix -&gt; URIs defined for the current element */

154

         private Map elementNamespaces;

155

156

         /**

157

          * The name of the file being parsed that is passed to the TagScript objects

158

          * for error reporting

159

          */

160

         private String fileName;

161

162

         /**

163

          * Do we want to use a validating parser?

164

          */

165

1027

         protected boolean validating = false;

166

167

         /** Flag to indicate if this object has been configured */

168

         private boolean configured;

169

170

         /**

171

          * when not null, set the default namespace for

172

          * unprefixed elements via the DefaultNamespaceFilter

173

          * class

174

          */

175

1027

         private String defaultNamespaceURI = null;

176

177

         /**

178

          * The Log to which logging calls will be made.

179

          */

180

1300

         private Log log = LogFactory.getLog(XMLParser.class);

181

182

         /**

183

          * Construct a new XMLParser with default properties.

184

          */

185

1027

         public XMLParser() {

186

1027

         }

187

188

         /**

189

          * Construct a new XMLParser, allowing a SAXParser to be passed in.  This

190

          * allows XMLParser to be used in environments which are unfriendly to

191

          * JAXP1.1 (such as WebLogic 6.0).  Thanks for the request to change go to

192

          * James House (james@interobjective.com).  This may help in places where

193

          * you are able to load JAXP 1.1 classes yourself.

194

          */

195

0

         public XMLParser(SAXParser parser) {

196

0

             this.parser = parser;

197

0

         }

198

199

         /**

200

          * Construct a new XMLParser, allowing an XMLReader to be passed in.  This

201

          * allows XMLParser to be used in environments which are unfriendly to

202

          * JAXP1.1 (such as WebLogic 6.0).  Note that if you use this option you

203

          * have to configure namespace and validation support yourself, as these

204

          * properties only affect the SAXParser and emtpy constructor.

205

          */

206

0

         public XMLParser(XMLReader reader) {

207

0

             this.reader = reader;

208

0

         }

209

210

         /**

211

          * Parse the content of the specified file using this XMLParser.  Returns

212

          * the root element from the object stack (if any).

213

          *

214

          * @param file File containing the XML data to be parsed

215

          *

216

          * @exception IOException if an input/output error occurs

217

          * @exception SAXException if a parsing exception occurs

218

          */

219

         public Script parse(File file) throws IOException, SAXException {

220

0

             return parse(file.toURL());

221

         }

222

223

         /**

224

          * Parse the content of the specified file using this XMLParser.  Returns

225

          * the root element from the object stack (if any).

226

          *

227

          * @param url URL containing the XML data to be parsed

228

          *

229

          * @exception IOException if an input/output error occurs

230

          * @exception SAXException if a parsing exception occurs

231

          */

232

         public Script parse(URL url) throws IOException, SAXException {

233

845

             ensureConfigured();

234

845

             this.fileName = url.toString();

235

236

845

             InputSource source = new InputSource(url.toString());

237

238

845

             getXMLReader().parse(source);

239

806

             return script;

240

         }

241

242

         /**

243

          * Parse the content of the specified input source using this XMLParser.

244

          * Returns the root element from the object stack (if any).

245

          *

246

          * @param input Input source containing the XML data to be parsed

247

          *

248

          * @exception IOException if an input/output error occurs

249

          * @exception SAXException if a parsing exception occurs

250

          */

251

         public Script parse(InputSource input) throws IOException, SAXException {

252

130

             ensureConfigured();

253

130

             this.fileName = input.getSystemId();

254

130

             getXMLReader().parse(input);

255

130

             return script;

256

         }

257

258

         /**

259

          * Parse the content of the specified input stream using this XMLParser.

260

          * Returns the root element from the object stack (if any).

261

          * (Note: if reading a File or URL, use one of the URL-based

262

          * parse methods instead.  This method will not be able

263

          * to resolve any relative paths inside a DTD.)

264

          *

265

          * @param input  Input stream containing the XML data to be parsed

266

          * @return

267

          * @exception IOException

268

          *                   if an input/output error occurs

269

          * @exception SAXException

270

          *                   if a parsing exception occurs

271

          */

272

         public Script parse(InputStream input) throws IOException, SAXException {

273

52

             ensureConfigured();

274

52

             this.fileName = getCurrentURI();

275

52

             getXMLReader().parse(new InputSource(input));

276

39

             return script;

277

         }

278

279

         /**

280

          * Parse the content of the specified reader using this XMLParser.

281

          * Returns the root element from the object stack (if any).

282

          * (Note: if reading a File or URL, use one of the URL-based

283

          * parse methods instead.  This method will not be able

284

          * to resolve any relative paths inside a DTD.)

285

          *

286

          * @param reader Reader containing the XML data to be parsed

287

          * @return

288

          * @exception IOException

289

          *                   if an input/output error occurs

290

          * @exception SAXException

291

          *                   if a parsing exception occurs

292

          */

293

         public Script parse(Reader reader) throws IOException, SAXException {

294

0

             ensureConfigured();

295

0

             this.fileName = getCurrentURI();

296

0

             getXMLReader().parse(new InputSource(reader));

297

0

             return script;

298

         }

299

300

         /**

301

          * Parse the content of the specified URI using this XMLParser.

302

          * Returns the root element from the object stack (if any).

303

          *

304

          * @param uri URI containing the XML data to be parsed

305

          *

306

          * @exception IOException if an input/output error occurs

307

          * @exception SAXException if a parsing exception occurs

308

          */

309

         public Script parse(String uri) throws IOException, SAXException {

310

0

             ensureConfigured();

311

0

             this.fileName = uri;

312

0

             getXMLReader().parse(uri);

313

0

             return script;

314

         }

315

316

         /**

317

          * Return the currently mapped namespace URI for the specified prefix,

318

          * if any; otherwise return <code>null</code>.  These mappings come and

319

          * go dynamically as the document is parsed.

320

          *

321

          * @param prefix Prefix to look up

322

          */

323

         public String findNamespaceURI(String prefix) {

324

0

             ArrayStack stack = (ArrayStack) namespaces.get(prefix);

325

0

             if (stack == null) {

326

0

                 return (null);

327

             }

328

             try {

329

0

                 return ((String) stack.peek());

330

             }

331

0

             catch (EmptyStackException e) {

332

0

                 return (null);

333

             }

334

         }

335

336

         // Properties

337

         //-------------------------------------------------------------------------

338

         public JellyContext getContext() {

339

52

             return context;

340

         }

341

342

         public void setContext(JellyContext context) {

343

1014

             this.context = context;

344

1014

         }

345

346

         /**

347

          * Set the jelly namespace to use for unprefixed elements.

348

          * Will be overridden by an explicit namespace in the

349

          * XML document.

350

          *

351

          * @param namespace jelly namespace to use (e.g. 'jelly:core')

352

          */

353

         public void setDefaultNamespaceURI(String namespace) {

354

845

             this.defaultNamespaceURI = namespace;

355

845

         }

356

357

         /**

358

          * Return the class loader to be used for instantiating application objects

359

          * when required.  This is determined based upon the following rules:

360

          * <ul>

361

          * <li>The class loader set by <code>setClassLoader()</code>, if any</li>

362

          * <li>The thread context class loader, if it exists and the

363

          *     <code>useContextClassLoader</code> property is set to true</li>

364

          * <li>The class loader used to load the XMLParser class itself.

365

          * </ul>

366

          */

367

         public ClassLoader getClassLoader() {

368

338

             return ClassLoaderUtils.getClassLoader(classLoader, useContextClassLoader, getClass());

369

         }

370

371

         /**

372

          * Set the class loader to be used for instantiating application objects

373

          * when required.

374

          *

375

          * @param classLoader The new class loader to use, or <code>null</code>

376

          *  to revert to the standard rules

377

          */

378

         public void setClassLoader(ClassLoader classLoader) {

379

0

             this.classLoader = classLoader;

380

0

         }

381

382

         /**

383

          * Return the boolean as to whether the context classloader should be used.

384

          */

385

         public boolean getUseContextClassLoader() {

386

0

             return useContextClassLoader;

387

         }

388

389

         /**

390

          * Determine whether to use the Context ClassLoader (the one found by

391

          * calling <code>Thread.currentThread().getContextClassLoader()</code>)

392

          * to resolve/load classes.  If not

393

          * using Context ClassLoader, then the class-loading defaults to

394

          * using the calling-class' ClassLoader.

395

          *

396

          * @param use determines whether to use JellyContext ClassLoader.

397

          */

398

         public void setUseContextClassLoader(boolean use) {

399

0

             useContextClassLoader = use;

400

0

         }

401

402

         /**

403

          * Return the error handler for this XMLParser.

404

          */

405

         public ErrorHandler getErrorHandler() {

406

0

             return (this.errorHandler);

407

         }

408

409

         /**

410

          * Set the error handler for this XMLParser.

411

          *

412

          * @param errorHandler The new error handler

413

          */

414

         public void setErrorHandler(ErrorHandler errorHandler) {

415

0

             this.errorHandler = errorHandler;

416

0

         }

417

418

         /**

419

          * Return the current Logger associated with this instance of the XMLParser

420

          */

421

         public Log getLogger() {

422

0

             return log;

423

         }

424

425

         /**

426

          * Set the current logger for this XMLParser.

427

          */

428

         public void setLogger(Log log) {

429

0

             this.log = log;

430

0

         }

431

432

         /** @return the expression factory used to evaluate tag attributes */

433

         public ExpressionFactory getExpressionFactory() {

434

53495

             if (expressionFactory == null) {

435

1001

                 expressionFactory = createExpressionFactory();

436

             }

437

53495

             return expressionFactory;

438

         }

439

440

         /** Sets the expression factory used to evaluate tag attributes */

441

         public void setExpressionFactory(ExpressionFactory expressionFactory) {

442

0

             this.expressionFactory = expressionFactory;

443

0

         }

444

445

         /**

446

          * Return the SAXParser we will use to parse the input stream.  If there

447

          * is a problem creating the parser, return <code>null</code>.

448

          */

449

         public SAXParser getParser() {

450

             // Return the parser we already created (if any)

451

1027

             if (parser != null) {

452

0

                 return (parser);

453

             }

454

             // Create and return a new parser

455

1027

             synchronized (this) {

456

                 try {

457

1027

                     if (factory == null) {

458

273

                         factory = SAXParserFactory.newInstance();

459

                     }

460

1027

                     factory.setNamespaceAware(true);

461

1027

                     factory.setValidating(validating);

462

1027

                     parser = factory.newSAXParser();

463

1027

                     return (parser);

464

                 }

465

0

                 catch (Exception e) {

466

0

                     log.error("XMLParser.getParser: ", e);

467

0

                     return (null);

468

                 }

469

0

             }

470

         }

471

472

         /**

473

          * By setting the reader in the constructor, you can bypass JAXP and

474

          * be able to use digester in Weblogic 6.0.

475

          *

476

          * @deprecated Use getXMLReader() instead, which can throw a

477

          *  SAXException if the reader cannot be instantiated

478

          */

479

         public XMLReader getReader() {

480

             try {

481

0

                 return (getXMLReader());

482

             }

483

0

             catch (SAXException e) {

484

0

                 log.error("Cannot get XMLReader", e);

485

0

                 return (null);

486

             }

487

         }

488

489

         /**

490

          * Return the XMLReader to be used for parsing the input document.

491

          *

492

          * @exception SAXException if no XMLReader can be instantiated

493

          */

494

         public synchronized XMLReader getXMLReader() throws SAXException {

495

1027

             if (reader == null) {

496

1027

                 reader = getParser().getXMLReader();

497

1027

                 if (this.defaultNamespaceURI != null) {

498

26

                     reader = new DefaultNamespaceFilter(this.defaultNamespaceURI,reader);

499

                 }

500

             }

501

             //set up the parse

502

1027

             reader.setContentHandler(this);

503

1027

             reader.setDTDHandler(this);

504

             //reader.setEntityResolver(this);

505

1027

             reader.setErrorHandler(this);

506

507

1027

             return reader;

508

         }

509

510

         /**

511

          * Return the validating parser flag.

512

          */

513

         public boolean getValidating() {

514

0

             return (this.validating);

515

         }

516

517

         /**

518

          * Set the validating parser flag.  This must be called before

519

          * <code>parse()</code> is called the first time.

520

          *

521

          * @param validating The new validating parser flag.

522

          */

523

         public void setValidating(boolean validating) {

524

845

             this.validating = validating;

525

845

         }

526

527

528

         /**

529

          * Returns the script that has just been created if this class is used

530

          * as a SAX ContentHandler and passed into some XML processor or parser.

531

          *

532

          * @return the ScriptBlock created if SAX events are piped into this class,

533

          * which must include a startDocument() and endDocument()

534

          */

535

         public ScriptBlock getScript() {

536

0

             return script;

537

         }

538

539

540

         // ContentHandler interface

541

         //-------------------------------------------------------------------------

542

         /**

543

          * Process notification of the beginning of the document being reached.

544

          *

545

          * @exception SAXException if a parsing error is to be reported

546

          */

547

         public void startDocument() throws SAXException {

548

1027

             script = new ScriptBlock();

549

1027

             textBuffer = new StringBuffer();

550

1027

             tagScript = null;

551

1027

             scriptStack.clear();

552

1027

             tagScriptStack.clear();

553

1027

         }

554

555

         /**

556

          * Process notification of the end of the document being reached.

557

          *

558

          * @exception SAXException if a parsing error is to be reported

559

          */

560

         public void endDocument() throws SAXException {

561

975

             textBuffer = null;

562

975

         }

563

564

         /**

565

          * Process notification of the start of an XML element being reached.

566

          *

567

          * @param namespaceURI The Namespace URI, or the empty string if the

568

          *   element has no Namespace URI or if Namespace processing is not

569

          *   being performed.

570

          * @param localName The local name (without prefix), or the empty

571

          *   string if Namespace processing is not being performed.

572

          * @param qName The qualified name (with prefix), or the empty

573

          *   string if qualified names are not available.\

574

          * @param list The attributes attached to the element. If there are

575

          *   no attributes, it shall be an empty Attributes object.

576

          * @exception SAXException if a parsing error is to be reported

577

          */

578

         public void startElement(

579

             String namespaceURI,

580

             String localName,

581

             String qName,

582

             Attributes list)

583

             throws SAXException {

584

585

             try {

586

                 // add check to ensure namespace URI is "" for no namespace

587

19981

                 if ( namespaceURI == null ) {

588

0

                     namespaceURI = "";

589

                 }

590

591

                 // if this is a tag then create a script to run it

592

                 // otherwise pass the text to the current body

593

19981

                 TagScript newTagScript = createTag(namespaceURI, localName, list);

594

19968

                 if (newTagScript == null) {

595

247

                     newTagScript = createStaticTag(namespaceURI, localName, qName, list);

596

                 }

597

19968

                 tagScript = newTagScript;

598

19968

                 tagScriptStack.add(tagScript);

599

19968

                 if (tagScript != null) {

600

                     // set the line number details

601

19968

                     if ( locator != null ) {

602

19968

                         tagScript.setLocator(locator);

603

                     }

604

                     // sets the file name element names

605

19968

                     tagScript.setFileName(fileName);

606

19968

                     tagScript.setElementName(qName);

607

19968

                     tagScript.setLocalName(localName);

608

609

19968

                     if (textBuffer.length() > 0) {

610

17355

                         addTextScript(textBuffer.toString());

611

17355

                         textBuffer.setLength(0);

612

                     }

613

19968

                     script.addScript(tagScript);

614

                     // start a new body

615

19968

                     scriptStack.push(script);

616

19968

                     script = new ScriptBlock();

617

19968

                     tagScript.setTagBody(script);

618

19968

                 }

619

                 else {

620

                     // XXXX: might wanna handle empty elements later...

621

0

                     textBuffer.append("<");

622

0

                     textBuffer.append(qName);

623

0

                     int size = list.getLength();

624

0

                     for (int i = 0; i < size; i++) {

625

0

                         textBuffer.append(" ");

626

0

                         textBuffer.append(list.getQName(i));

627

0

                         textBuffer.append("=");

628

0

                         textBuffer.append("\"");

629

0

                         textBuffer.append(list.getValue(i));

630

0

                         textBuffer.append("\"");

631

                     }

632

0

                     textBuffer.append(">");

633

                 }

634

             }

635

13

             catch (SAXException e) {

636

13

                 throw e;

637

             }

638

0

             catch (Exception e) {

639

0

                 log.error( "Caught exception: " + e, e );

640

0

                 throw new SAXException( "Runtime Exception: " + e, e );

641

19968

             }

642

19968

         }

643

644

         /**

645

          * Process notification of character data received from the body of

646

          * an XML element.

647

          *

648

          * @param buffer The characters from the XML document

649

          * @param start Starting offset into the buffer

650

          * @param length Number of characters from the buffer

651

          *

652

          * @exception SAXException if a parsing error is to be reported

653

          */

654

         public void characters(char buffer[], int start, <span class="keyword">int length)

655

             throws SAXException {

656

31954

             textBuffer.append(buffer, start, length);

657

31954

         }

658

659

         /**

660

          * Process notification of the end of an XML element being reached.

661

          *

662

          * @param namespaceURI The Namespace URI, or the empty string if the

663

          *   element has no Namespace URI or if Namespace processing is not

664

          *   being performed.

665

          * @param localName The local name (without prefix), or the empty

666

          *   string if Namespace processing is not being performed.

667

          * @param qName The qualified XML 1.0 name (with prefix), or the

668

          *   empty string if qualified names are not available.

669

          * @exception SAXException if a parsing error is to be reported

670

          */

671

         public void endElement(String namespaceURI, String localName, String qName)

672

             throws SAXException {

673

             try {

674

19929

                 tagScript = (TagScript) tagScriptStack.remove(tagScriptStack.size() - 1);

675

19929

                 if (tagScript != null) {

676

19929

                     if (textBuffer.length() > 0) {

677

10010

                         addTextScript(textBuffer.toString());

678

10010

                         textBuffer.setLength(0);

679

                     }

680

19929

                     script = (ScriptBlock) scriptStack.pop();

681

19929

                 }

682

                 else {

683

0

                     textBuffer.append("</");

684

0

                     textBuffer.append(qName);

685

0

                     textBuffer.append(">");

686

                 }

687

688

                 // now lets set the parent tag variable

689

19929

                 if ( tagScriptStack.isEmpty() ) {

690

988

                     tagScript = null;

691

988

                 }

692

                 else {

693

18941

                     tagScript = (TagScript) tagScriptStack.get(tagScriptStack.size() - 1);

694

                 }

695

0

             } catch (Exception e) {

696

0

                 log.error( "Caught exception: " + e, e );

697

0

                 throw new SAXException( "Runtime Exception: " + e, e );

698

19929

             }

699

19929

         }

700

701

         /**

702

          * Process notification that a namespace prefix is coming in to scope.

703

          *

704

          * @param prefix Prefix that is being declared

705

          * @param namespaceURI Corresponding namespace URI being mapped to

706

          *

707

          * @exception SAXException if a parsing error is to be reported

708

          */

709

         public void startPrefixMapping(String prefix, String namespaceURI)

710

             throws SAXException {

711

             // Register this prefix mapping

712

1118

             ArrayStack stack = (ArrayStack) namespaces.get(prefix);

713

1118

             if (stack == null) {

714

1118

                 stack = new ArrayStack();

715

1118

                 namespaces.put(prefix, stack);

716

             }

717

1118

             stack.push(namespaceURI);

718

719

1118

             if ( elementNamespaces == null ) {

720

1040

                 elementNamespaces = new HashMap();

721

             }

722

1118

             elementNamespaces.put(prefix, namespaceURI);

723

1118

         }

724

725

         /**

726

          * Process notification that a namespace prefix is going out of scope.

727

          *

728

          * @param prefix Prefix that is going out of scope

729

          *

730

          * @exception SAXException if a parsing error is to be reported

731

          */

732

         public void endPrefixMapping(String prefix) throws SAXException {

733

             // Deregister this prefix mapping

734

1066

             ArrayStack stack = (ArrayStack) namespaces.get(prefix);

735

1066

             if (stack == null) {

736

0

                 return;

737

             }

738

             try {

739

1066

                 stack.pop();

740

1066

                 if (stack.empty()) {

741

1066

                     namespaces.remove(prefix);

742

                 }

743

             }

744

0

             catch (EmptyStackException e) {

745

0

                 throw createSAXException("endPrefixMapping popped too many times");

746

1066

             }

747

1066

         }

748

749

         /**

750

          * Process notification of ignorable whitespace received from the body of

751

          * an XML element.

752

          *

753

          * @param buffer The characters from the XML document

754

          * @param start Starting offset into the buffer

755

          * @param len Number of characters from the buffer

756

          *

757

          * @exception SAXException if a parsing error is to be reported

758

          */

759

         public void ignorableWhitespace(char buffer[], int start, <span class="keyword">int len)

760

             throws SAXException {

761

             ; // No processing required

762

338

         }

763

764

         /**

765

          * Process notification of a processing instruction that was encountered.

766

          *

767

          * @param target The processing instruction target

768

          * @param data The processing instruction data (if any)

769

          *

770

          * @exception SAXException if a parsing error is to be reported

771

          */

772

         public void processingInstruction(String target, String data)

773

             throws SAXException {

774

             ; // No processing is required

775

0

         }

776

777

         /**

778

          * Set the document locator associated with our parser.

779

          *

780

          * @param locator The new locator

781

          */

782

         public void setDocumentLocator(Locator locator) {

783

1027

             this.locator = locator;

784

1027

         }

785

786

         /**

787

          * Process notification of a skipped entity.

788

          *

789

          * @param name Name of the skipped entity

790

          *

791

          * @exception SAXException if a parsing error is to be reported

792

          */

793

         public void skippedEntity(String name) throws SAXException {

794

             ; // No processing required

795

0

         }

796

797

798

         // DTDHandler interface

799

         //-------------------------------------------------------------------------

800

801

         /**

802

          * Receive notification of a notation declaration event.

803

          *

804

          * @param name The notation name

805

          * @param publicId The public identifier (if any)

806

          * @param systemId The system identifier (if any)

807

          */

808

         public void notationDecl(String name, String <span class="keyword">publicId, String systemId) {

809

0

         }

810

811

         /**

812

          * Receive notification of an unparsed entity declaration event.

813

          *

814

          * @param name The unparsed entity name

815

          * @param publicId The public identifier (if any)

816

          * @param systemId The system identifier (if any)

817

          * @param notation The name of the associated notation

818

          */

819

         public void unparsedEntityDecl(

820

             String name,

821

             String publicId,

822

             String systemId,

823

             String notation) {

824

0

         }

825

826

827

         // ErrorHandler interface

828

         //-------------------------------------------------------------------------

829

830

         /**

831

          * Forward notification of a parsing error to the application supplied

832

          * error handler, if any, otherwise throw a SAXException with the error.

833

          *

834

          * @param exception The error information

835

          *

836

          * @exception SAXException if a parsing exception occurs

837

          */

838

         public void error(SAXParseException exception) throws SAXException {

839

26

             log.error(

840

                 "Parse Error at line "

841

                     + exception.getLineNumber()

842

                     + " column "

843

                     + exception.getColumnNumber()

844

                     + ": "

845

                     + exception.getMessage(),

846

                 exception);

847

26

             if (errorHandler != null) {

848

0

                 errorHandler.error(exception);

849

0

             } else {

850

26

                 throw exception;

851

             }

852

0

         }

853

854

         /**

855

          * Forward notification of a fatal parsing error to the application

856

          * supplied error handler, if any, otherwise throw a SAXException with the error.

857

          *

858

          * @param exception The fatal error information

859

          *

860

          * @exception SAXException if a parsing exception occurs

861

          */

862

         public void fatalError(SAXParseException exception) throws SAXException {

863

13

             log.error(

864

                 "Parse Fatal Error at line "

865

                     + exception.getLineNumber()

866

                     + " column "

867

                     + exception.getColumnNumber()

868

                     + ": "

869

                     + exception.getMessage(),

870

                 exception);

871

13

             if (errorHandler != null) {

872

0

                 errorHandler.fatalError(exception);

873

0

             } else {

874

13

                 throw exception;

875

             }

876

0

         }

877

878

         /**

879

          * Forward notification of a parse warning to the application supplied

880

          * error handler (if any).  Unlike XMLParser.error(SAXParseException) and

881

          * XMLParser.fatalError(SAXParseException), this implementation will

882

          * NOT throw a SAXException by default if no error handler is supplied.

883

          *

884

          * @param exception The warning information

885

          *

886

          * @exception SAXException if a parsing exception occurs

887

          */

888

         public void warning(SAXParseException exception) throws SAXException {

889

0

             log.error(

890

                 "Parse Warning at line "

891

                     + exception.getLineNumber()

892

                     + " column "

893

                     + exception.getColumnNumber()

894

                     + ": "

895

                     + exception.getMessage(),

896

                 exception);

897

0

             if (errorHandler != null) {

898

0

                 errorHandler.warning(exception);

899

             }

900

0

         }

901

902

         // Implementation methods

903

         //-------------------------------------------------------------------------

904

         /**

905

          * If this object has not been configured then register the default

906

          * namespaces

907

          */

908

         private void ensureConfigured() {

909

1027

             if (!configured) {

910

1027

                 configure();

911

1027

                 configured = true;

912

             }

913

1027

         }

914

915

         /**

916

          * This method is called only once before parsing occurs

917

          * which allows tag libraries to be registered and so forth

918

          */

919

         protected void configure() {

920

             // load the properties file of libraries available

921

1027

             Properties properties = getJellyProperties();

922

1027

             for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {

923

39026

                 Map.Entry entry = (Map.Entry) iter.next();

924

39026

                 String uri = (String) entry.getKey();

925

39026

                 String className = (String) entry.getValue();

926

39026

                 String libraryURI = "jelly:" + uri;

927

928

                 // don't overload any Mock Tags already

929

39026

                 if ( ! context.isTagLibraryRegistered(libraryURI) ) {

930

35074

                     context.registerTagLibrary(libraryURI, className);

931

                 }

932

39026

             }

933

1027

         }

934

935

936

         /**

937

          * A helper method which loads the static Jelly properties once on startup

938

          */

939

         protected synchronized Properties getJellyProperties() {

940

1027

             if (jellyProperties == null) {

941

273

                 jellyProperties = new Properties();

942

943

273

                 InputStream in = null;

944

273

                 URL url =

945

                     getClassLoader().getResource("org/apache/commons/jelly/jelly.properties");

946

273

                 if (url != null) {

947

273

                     log.debug("Loading Jelly default tag libraries from: " + url);

948

                     try {

949

273

                         in = url.openStream();

950

273

                         jellyProperties .load(in);

951

                     }

952

0

                     catch (IOException e) {

953

0

                         log.error("Could not load jelly properties from: " + url + ". Reason: " + e, e);

954

                     }

955

                     finally {

956

0

                         try {

957

273

                             in.close();

958

                         }

959

0

                         catch (Exception e) {

960

0

                             if (log.isDebugEnabled()) log.debug("error closing jelly.properties", e);

961

273

                         }

962

0

                     }

963

                 }

964

             }

965

1027

             return jellyProperties;

966

         }

967

968

         /**

969

          * Factory method to create new Tag script for the given namespaceURI and name or

970

          * return null if this is not a custom Tag.

971

          */

972

         protected TagScript createTag(

973

             String namespaceURI,

974

             String localName,

975

             Attributes list)

976

             throws SAXException {

977

             try {

978

                 // use the URI to load a taglib

979

19981

                 TagLibrary taglib = context.getTagLibrary(namespaceURI);

980

19981

                 if (taglib == null) {

981

312

                     if (namespaceURI != null && namespaceURI.startsWith("jelly:")) {

982

65

                         String uri = namespaceURI.substring(6);

983

                         // try to find the class on the claspath

984

                         try {

985

65

                             Class taglibClass = getClassLoader().loadClass(uri);

986

52

                             taglib = (TagLibrary) taglibClass.newInstance();

987

52

                             context.registerTagLibrary(namespaceURI, taglib);

988

                         }

989

13

                         catch (ClassNotFoundException e) {

990

13

                             throw createSAXException("Could not load class: " + uri + " so taglib instantiation failed", e);

991

                         }

992

0

                         catch (IllegalAccessException e) {

993

0

                             throw createSAXException("Constructor for class is not accessible: " + uri + " so taglib instantiation failed",e);

994

                         }

995

0

                         catch (InstantiationException e) {

996

0

                             throw createSAXException("Class could not be instantiated: " + uri + " so taglib instantiation failed",e);

997

                         }

998

0

                         catch (ClassCastException e) {

999

0

                             throw createSAXException("Class is not a TagLibrary: " + uri + " so taglib instantiation failed",e);

1000

52

                         }

1001

                     }

1002

                 }

1003

19968

                 if (taglib != null) {

1004

19721

                     TagScript script = taglib.createTagScript(localName, list);

1005

19721

                     if ( script != null ) {

1006

19721

                         configureTagScript(script);

1007

1008

                         // clone the attributes to keep them around after this parse

1009

19721

                         script.setSaxAttributes(new AttributesImpl(list));

1010

1011

                         // now iterate through through the expressions

1012

19721

                         int size = list.getLength();

1013

45747

                         for (int i = 0; i < size; i++) {

1014

26026

                             String attributeName = list.getLocalName(i);

1015

26026

                             String attributeValue = list.getValue(i);

1016

26026

                             Expression expression =

1017

                                 taglib.createExpression(

1018

                                     getExpressionFactory(),

1019

                                     script,

1020

                                     attributeName,

1021

                                     attributeValue);

1022

26026

                             if (expression == null) {

1023

0

                                 expression = createConstantExpression(localName, attributeName, attributeValue);

1024

                             }

1025

26026

                             script.addAttribute(attributeName, expression);

1026

                         }

1027

                     }

1028

19721

                     return script;

1029

                 }

1030

247

                 return null;

1031

             }

1032

13

             catch (Exception e) {

1033

13

                 log.warn(

1034

                     "Could not create taglib or URI: " + namespaceURI + " tag name: " + localName,

1035

                     e);

1036

13

                 throw createSAXException(e);

1037

             }

1038

         }

1039

1040

1041

         /**

1042

          * Factory method to create a static Tag that represents some static content.

1043

          */

1044

         protected TagScript createStaticTag(

1045

             final String namespaceURI,

1046

             final String localName,

1047

             final String qName,

1048

             Attributes list)

1049

             throws SAXException {

1050

             try {

1051

247

                 StaticTag tag = new StaticTag( namespaceURI, localName, qName );

1052

247

                 StaticTagScript script = new StaticTagScript(

1053

                     new TagFactory() {

1054

                         public Tag createTag(String name, Attributes attributes) {

1055

                             return new StaticTag( namespaceURI, localName, qName );

1056

                         }

1057

                     }

1058

                 );

1059

247

                 configureTagScript(script);

1060

1061

                 // now iterate through through the expressions

1062

247

                 int size = list.getLength();

1063

351

                 for (int i = 0; i < size; i++) {

1064

104

                     String attributeValue = list.getValue(i);

1065

104

                     Expression expression = CompositeExpression.parse(

1066

                             attributeValue, getExpressionFactory()

1067

                         );

1068

104

                     String attrQName = list.getQName(i);

1069

104

                     script.addAttribute(attrQName, expression);

1070

                 }

1071

247

                 return script;

1072

             }

1073

0

             catch (Exception e) {

1074

0

                 log.warn(

1075

                     "Could not create static tag for URI: "

1076

                         + namespaceURI

1077

                         + " tag name: "

1078

                         + localName,

1079

                     e);

1080

0

                 throw createSAXException(e);

1081

             }

1082

         }

1083

1084

1085

         /**

1086

          * Configure a newly created TagScript instance before any Expressions are created

1087

          *

1088

          * @param aTagScript

1089

          */

1090

         protected void configureTagScript(TagScript aTagScript) {

1091

             // set parent relationship...

1092

19968

             aTagScript.setParent(this.tagScript);

1093

1094

             // set the namespace Map

1095

19968

             if ( elementNamespaces != null ) {

1096

1040

                 aTagScript.setTagNamespacesMap( elementNamespaces );

1097

1040

                 elementNamespaces = null;

1098

             }

1099

19968

         }

1100

1101

         /**

1102

          * Adds the text to the current script block parsing any embedded

1103

          * expressions inot ExpressionScript objects.

1104

          */

1105

         protected void addTextScript(String text) throws JellyException {

1106

27365

             Expression expression =

1107

                 CompositeExpression.parse(text, getExpressionFactory());

1108

1109

27365

             addExpressionScript(script, expression);

1110

27365

         }

1111

1112

1113

         /**

1114

          * Adds the given Expression object to the current Script.

1115

          */

1116

         protected void addExpressionScript(ScriptBlock script, Expression expression) {

1117

28405

             if ( expression instanceof ConstantExpression ) {

1118

27768

                 ConstantExpression constantExpression

1119

                     = (ConstantExpression) expression;

1120

27768

                 Object value = constantExpression.getValue();

1121

27768

                 if ( value != null ) {

1122

27768

                     script.addScript(new TextScript( value.toString() ));

1123

                 }

1124

27768

             }

1125

             else

1126

637

             if ( expression instanceof CompositeExpression ) {

1127

208

                 CompositeTextScriptBlock newBlock = new CompositeTextScriptBlock();

1128

208

                 script.addScript(newBlock);

1129

1130

208

                 CompositeExpression compositeExpression

1131

                     = (CompositeExpression) expression;

1132

208

                 Iterator iter = compositeExpression.getExpressions().iterator();

1133

1248

                 while (iter.hasNext()) {

1134

1040

                     addExpressionScript( newBlock, (Expression) iter.next() );

1135

1040

                 }

1136

208

             }

1137

             else {

1138

429

                 script.addScript(new ExpressionScript(expression));

1139

             }

1140

28405

         }

1141

1142

         protected Expression createConstantExpression(

1143

             String tagName,

1144

             String attributeName,

1145

             String attributeValue)  {

1146

0

             return new ConstantExpression(attributeValue);

1147

         }

1148

1149

         protected ExpressionFactory createExpressionFactory() {

1150

1001

             return new JexlExpressionFactory();

1151

         }

1152

1153

         /**

1154

          * @return the current context URI as a String or null if there is no

1155

          * current context defined on the JellyContext

1156

          */

1157

         protected String getCurrentURI() {

1158

52

             URL url = this.getContext().getCurrentURL();

1159

52

             return (url != null) ? url.toString() : <span class="keyword">null;

1160

         }

1161

1162

         /**

1163

          * Create a SAX exception which also understands about the location in

1164

          * the file where the exception occurs

1165

          *

1166

          * @return the new exception

1167

          */

1168

         protected SAXException createSAXException(String message, Exception e) {

1169

26

             log.warn("Underlying exception: " + e);

1170

26

             e.printStackTrace();

1171

26

             if (locator != null) {

1172

26

                 String error =

1173

                     "Error at ("

1174

                         + locator.getLineNumber()

1175

                         + ", "

1176

                         + locator.getColumnNumber()

1177

                         + "): "

1178

                         + message;

1179

26

                 if (e != null) {

1180

26

                     return new SAXParseException(error, locator, e);

1181

                 }

1182

                 else {

1183

0

                     return new SAXParseException(error, locator);

1184

                 }

1185

             }

1186

0

             log.error("No Locator!");

1187

0

             if (e != null) {

1188

0

                 return new SAXException(message, e);

1189

             }

1190

             else {

1191

0

                 return new SAXException(message);

1192

             }

1193

         }

1194

1195

         /**

1196

          * Create a SAX exception which also understands about the location in

1197

          * the digester file where the exception occurs

1198

          *

1199

          * @return the new exception

1200

          */

1201

         protected SAXException createSAXException(Exception e) {

1202

13

             return createSAXException(e.getMessage(), e);

1203

         }

1204

         /**

1205

          * Create a SAX exception which also understands about the location in

1206

          * the digester file where the exception occurs

1207

          *

1208

          * @return the new exception

1209

          */

1210

         protected SAXException createSAXException(String message) {

1211

0

             return createSAXException(message, null);

1212

         }

1213

     }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.