PageRenderTime 73ms CodeModel.GetById 43ms app.highlight 24ms RepoModel.GetById 2ms app.codeStats 1ms

/bundles/plugins-trunk/XML/xml/parser/EntityMgrFixerConfiguration.java

#
Java | 362 lines | 256 code | 50 blank | 56 comment | 43 complexity | f13df38f733fd7157c93c29e41336b52 MD5 | raw file
  1/*
  2 * EntityMgrFixerConfiguration.java - work-around for XERCESJ-1205
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * copyright (C) 2011 Eric Le Lay
  7 *
  8 * The XML plugin is licensed under the GNU General Public License, with
  9 * the following exception:
 10 *
 11 * "Permission is granted to link this code with software released under
 12 * the Apache license version 1.1, for example used by the Xerces XML
 13 * parser package."
 14 */
 15package xml.parser;
 16
 17import java.io.IOException;
 18
 19import org.apache.xerces.impl.XMLEntityManager;
 20import org.apache.xerces.impl.dtd.DTDGrammar;
 21import org.apache.xerces.impl.dtd.XMLDTDDescription;
 22import org.apache.xerces.impl.dtd.XMLEntityDecl;
 23import org.apache.xerces.parsers.XIncludeAwareParserConfiguration;
 24import org.apache.xerces.util.SymbolTable;
 25import org.apache.xerces.xni.Augmentations;
 26import org.apache.xerces.xni.NamespaceContext;
 27import org.apache.xerces.xni.QName;
 28import org.apache.xerces.xni.XMLAttributes;
 29import org.apache.xerces.xni.XMLDocumentHandler;
 30import org.apache.xerces.xni.XMLLocator;
 31import org.apache.xerces.xni.XMLResourceIdentifier;
 32import org.apache.xerces.xni.XMLString;
 33import org.apache.xerces.xni.XNIException;
 34import org.apache.xerces.xni.grammars.XMLGrammarPool;
 35import org.apache.xerces.xni.parser.XMLComponent;
 36import org.apache.xerces.xni.parser.XMLComponentManager;
 37import org.apache.xerces.xni.parser.XMLConfigurationException;
 38import org.apache.xerces.xni.parser.XMLDocumentFilter;
 39import org.apache.xerces.xni.parser.XMLDocumentSource;
 40import org.gjt.sp.util.Log;
 41
 42/**
 43 * fix for bug #3393297 - "XMLPlugin doesn't find DTD upon second parse".
 44 * work-around for Xerces bug [XERCESJ-1205]
 45 * "Entity resolution does not work with DTD grammar caching resolved". code is
 46 * brittle (depends on the implementation in XIncludeAwareParserConfiguration
 47 * and the like).
 48 * 
 49 * @see http://sourceforge.net/tracker/?func=detail&aid=3393297&group_id=588&atid=565475
 50 * @see https://issues.apache.org/jira/browse/XERCESJ-1205
 51 * @author kerik-sf
 52 * @version $Id: EntityMgrFixerConfiguration.java 20051 2011-10-05 16:36:13Z kerik-sf $
 53 * */
 54class EntityMgrFixerConfiguration extends XIncludeAwareParserConfiguration {
 55	protected EntityMgrFixer fEntityMgrFixer;
 56
 57	private class EntityMgrFixer implements XMLComponent, XMLDocumentFilter {
 58		// instance variables
 59
 60		// for XMLDocumentFilter
 61		protected XMLDocumentHandler fDocumentHandler;
 62		protected XMLDocumentSource fDocumentSource;
 63
 64		protected XMLLocator fDocLocation;
 65
 66		/**
 67		 * save locator for future use and forward.
 68		 * */
 69		@Override
 70		public void startDocument(XMLLocator locator, String encoding,
 71				NamespaceContext namespaceContext, Augmentations augs)
 72				throws XNIException {
 73
 74			// save XMLLocator for future use
 75			fDocLocation = locator;
 76
 77			if (fDocumentHandler != null) {
 78				fDocumentHandler.startDocument(locator, encoding,
 79						namespaceContext, augs);
 80			}
 81		}
 82
 83		/**
 84		 * copy external entities from a cached grammar to the entity manager.
 85		 * relies on being called when the grammar has been loaded (see
 86		 * XMLDTDValidator, line 769)
 87		 **/
 88		@Override
 89		public void doctypeDecl(String rootElement, String publicId,
 90				String systemId, Augmentations augs) throws XNIException {
 91			if (fDocumentHandler != null) {
 92				fDocumentHandler.doctypeDecl(rootElement, publicId, systemId,
 93						augs);
 94			}
 95			if (fValidationManager.isCachedDTD()) {
 96				// duplicates code from XMLDTDValidator to retrieve the grammar
 97				String eid = null;
 98				try {
 99					eid = XMLEntityManager.expandSystemId(systemId,
100							fDocLocation.getExpandedSystemId(), false);
101				} catch (java.io.IOException e) {
102				}
103				XMLDTDDescription grammarDesc = new XMLDTDDescription(publicId,
104						systemId, fDocLocation.getExpandedSystemId(), eid,
105						rootElement);
106				DTDGrammar grammar = (DTDGrammar) fGrammarPool
107						.retrieveGrammar(grammarDesc);
108				// grammar is cached so it should be retrieved
109				assert (grammar != null);
110
111				// now copy to the entityManager
112				((EntityMgrFixerConfiguration.MyEntityManager) fEntityManager)
113						.copyEntitiesFromDTD(grammar);
114			}
115		}
116
117		/* {{{ forward-only */
118		@Override
119		public void xmlDecl(String version, String encoding, String standalone,
120				Augmentations augs) throws XNIException {
121			if (fDocumentHandler != null) {
122				fDocumentHandler.xmlDecl(version, encoding, standalone, augs);
123			}
124		}
125
126		@Override
127		public void comment(XMLString text, Augmentations augs)
128				throws XNIException {
129			if (fDocumentHandler != null) {
130				fDocumentHandler.comment(text, augs);
131			}
132		}
133
134		@Override
135		public void processingInstruction(String target, XMLString data,
136				Augmentations augs) throws XNIException {
137			if (fDocumentHandler != null) {
138				fDocumentHandler.processingInstruction(target, data, augs);
139			}
140		}
141
142		@Override
143		public void startElement(QName element, XMLAttributes attributes,
144				Augmentations augs) throws XNIException {
145			if (fDocumentHandler != null) {
146				fDocumentHandler.startElement(element, attributes, augs);
147			}
148		}
149
150		@Override
151		public void emptyElement(QName element, XMLAttributes attributes,
152				Augmentations augs) throws XNIException {
153			if (fDocumentHandler != null) {
154				fDocumentHandler.emptyElement(element, attributes, augs);
155			}
156		}
157
158		@Override
159		public void startGeneralEntity(String name,
160				XMLResourceIdentifier identifier, String encoding,
161				Augmentations augs) throws XNIException {
162			if (fDocumentHandler != null) {
163				fDocumentHandler.startGeneralEntity(name, identifier, encoding,
164						augs);
165			}
166		}
167
168		@Override
169		public void textDecl(String version, String encoding, Augmentations augs)
170				throws XNIException {
171			if (fDocumentHandler != null) {
172				fDocumentHandler.textDecl(version, encoding, augs);
173			}
174		}
175
176		@Override
177		public void endGeneralEntity(String name, Augmentations augs)
178				throws XNIException {
179			if (fDocumentHandler != null) {
180				fDocumentHandler.endGeneralEntity(name, augs);
181			}
182		}
183
184		@Override
185		public void characters(XMLString text, Augmentations augs)
186				throws XNIException {
187			if (fDocumentHandler != null) {
188				fDocumentHandler.characters(text, augs);
189			}
190		}
191
192		@Override
193		public void ignorableWhitespace(XMLString text, Augmentations augs)
194				throws XNIException {
195			if (fDocumentHandler != null) {
196				fDocumentHandler.ignorableWhitespace(text, augs);
197			}
198		}
199
200		@Override
201		public void endElement(QName element, Augmentations augs)
202				throws XNIException {
203			if (fDocumentHandler != null) {
204				fDocumentHandler.endElement(element, augs);
205			}
206		}
207
208		@Override
209		public void startCDATA(Augmentations augs) throws XNIException {
210			if (fDocumentHandler != null) {
211				fDocumentHandler.startCDATA(augs);
212			}
213		}
214
215		@Override
216		public void endCDATA(Augmentations augs) throws XNIException {
217			if (fDocumentHandler != null) {
218				fDocumentHandler.endCDATA(augs);
219			}
220		}
221
222		@Override
223		public void endDocument(Augmentations augs) throws XNIException {
224			if (fDocumentHandler != null) {
225				fDocumentHandler.endDocument(augs);
226			}
227		}
228
229		/* }}} */
230
231		/* {{{ piping */
232		@Override
233		public void setDocumentSource(XMLDocumentSource source) {
234			fDocumentSource = source;
235		}
236
237		@Override
238		public XMLDocumentSource getDocumentSource() {
239			return fDocumentSource;
240		}
241
242		@Override
243		public void setDocumentHandler(XMLDocumentHandler handler) {
244			fDocumentHandler = handler;
245		}
246
247		@Override
248		public XMLDocumentHandler getDocumentHandler() {
249			return fDocumentHandler;
250		}
251
252		/* }}} */
253		/* {{{ unimplemented stubs */
254		@Override
255		public void reset(XMLComponentManager componentManager)
256				throws XMLConfigurationException {
257		}
258
259		@Override
260		public String[] getRecognizedFeatures() {
261			return null;
262		}
263
264		@Override
265		public void setFeature(String featureId, boolean state)
266				throws XMLConfigurationException {
267		}
268
269		@Override
270		public String[] getRecognizedProperties() {
271			return null;
272		}
273
274		@Override
275		public void setProperty(String propertyId, Object value)
276				throws XMLConfigurationException {
277		}
278
279		@Override
280		public Boolean getFeatureDefault(String featureId) {
281			return null;
282		}
283
284		@Override
285		public Object getPropertyDefault(String propertyId) {
286			return null;
287		}
288		/* }}} */
289
290	}
291
292	/**
293	 * add a method to copy external entities from a cached grammar to
294	 * XMLEntityManager. fInExternalSubset is what requires subclassing.
295	 **/
296	private static class MyEntityManager extends XMLEntityManager {
297
298		private void copyEntitiesFromDTD(DTDGrammar grammar) {
299
300			XMLEntityDecl entityDecl = new XMLEntityDecl();
301
302			for (int i = 0; grammar.getEntityDecl(i, entityDecl); i++) {
303				fInExternalSubset = entityDecl.inExternal;
304				// see test_data/dtd/sample2.xml for an example why internal
305				// entities should not be added
306				if (entityDecl.inExternal) {
307					if (entityDecl.publicId != null
308							|| entityDecl.systemId != null) {
309						try {
310							addExternalEntity(entityDecl.name,
311									entityDecl.publicId, entityDecl.systemId,
312									entityDecl.baseSystemId);
313						} catch (IOException e) {
314							Log.log(Log.WARNING,
315									EntityMgrFixerConfiguration.class,
316									"error adding external entity from cached grammar ("
317											+ entityDecl + ")", e);
318						}
319					} else {
320						addInternalEntity(entityDecl.name, entityDecl.value);
321					}
322				}
323			}
324			fInExternalSubset = false;
325		}
326	}
327
328	public EntityMgrFixerConfiguration(SymbolTable symbolTable,
329			XMLGrammarPool cachedGrammarPool) {
330		super(symbolTable, cachedGrammarPool);
331
332		// override fEntityManager with my own
333		// XXX: code is brittle, check with XML11Configuration() for any other
334		// use of fEntityManager on new release
335		fCommonComponents.remove(fEntityManager);
336		fEntityManager = new MyEntityManager();
337		fProperties.put(ENTITY_MANAGER, fEntityManager);
338		addCommonComponent(fEntityManager);
339
340		fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner());
341	}
342
343	@Override
344	protected void configurePipeline() {
345		super.configurePipeline();
346
347		fEntityMgrFixer = new EntityMgrFixer();
348
349		// insert the EntityMgrFixer in the end of the pipeline
350		XMLDocumentSource prev = fLastComponent;
351		fLastComponent = fEntityMgrFixer;
352
353		XMLDocumentHandler next = prev.getDocumentHandler();
354		prev.setDocumentHandler(fEntityMgrFixer);
355		fEntityMgrFixer.setDocumentSource(prev);
356		if (next != null) {
357			fEntityMgrFixer.setDocumentHandler(next);
358			next.setDocumentSource(fEntityMgrFixer);
359		}
360
361	}
362}