/*******************************************************************************
* Copyright (c) 2007 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.model.loaders;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import org.jboss.tools.common.xml.XMLUtilities;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
*
* @author Viacheslav Kabanovich
*
*/
public class XMLRecognizerContext extends EntityRecognizerContext {
protected boolean isDTD = false;
protected DoctypeInfo doctypeInfo = null;
static protected class DoctypeInfo {
protected String publicId;
protected String systemId;
protected String name;
}
static DoctypeInfo NULL_INFO = new DoctypeInfo();
public XMLRecognizerContext(EntityRecognizerContext context) {
super(context.getFileName(), context.getExtension(), context.getBody());
init();
}
void init() {
if(body == null) return;
String doctypeText = getUnformattedDoctypeFromBody(body);
if (doctypeText != null) {
isDTD = true;
doctypeInfo = checkDocType(doctypeText);
}
}
public boolean isDTD() {
return isDTD;
}
public String getPublicId() {
return doctypeInfo == null ? null : doctypeInfo.publicId;
}
public String getSystemId() {
return doctypeInfo == null ? null : doctypeInfo.systemId;
}
public String getRootName() {
if(doctypeInfo != null) {
return doctypeInfo.name;
}
//TODO
return null;
}
public XMLRecognizerContext getXMLContext() {
return this;
}
static HashMap<String, DoctypeInfo> doctypes = new HashMap<String, DoctypeInfo>();
private DoctypeInfo checkDocType(String docTypeString) {
if(doctypes.containsKey(docTypeString)) {
return doctypes.get(docTypeString);
}
Reader xml = new StringReader(docTypeString + "<root></root>"); //$NON-NLS-1$
DocumentBuilder db = XMLUtilities.createDocumentBuilder(false);
if (db == null)
return NULL_INFO;
try {
db.setErrorHandler(new ErrorHandler() {
public void warning(SAXParseException exception)
throws SAXException {
}
public void fatalError(SAXParseException exception)
throws SAXException {
}
public void error(SAXParseException exception)
throws SAXException {
}
});
db.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId,
String systemId) throws SAXException, IOException {
return new InputSource(new StringReader("")); //$NON-NLS-1$
}
});
Document doc = db.parse(new InputSource(xml));
if(doc != null) {
DocumentType dt = doc.getDoctype();
DoctypeInfo doctypeInfo = new DoctypeInfo();
doctypeInfo.publicId = dt.getPublicId();
doctypeInfo.systemId = dt.getSystemId();
doctypeInfo.name = dt.getName();
//'docTypeString' is a substring of the complete text of the file,
//which can be very long; and this substring keeps reference to
//char[] of the entire text. Adding an empty string ensures
//that the result will not keep the reference.
doctypes.put("" + docTypeString, doctypeInfo);
// doctypeInfo.publicId + " " + doctypeInfo.systemId + " " +
// doctypeInfo.name);
return doctypeInfo;
}
} catch (SAXException e1) {
//ignore - doctype is corrupted
} catch (IOException e2) {
//ignore - impossible
} finally {
try {
xml.close();
} catch (IOException e) {
}
}
//See comment to 'docTypeString' above.
doctypes.put("" + docTypeString, NULL_INFO);
return NULL_INFO;
}
private String getUnformattedDoctypeFromBody(String body) {
int i = body.indexOf("<!DOCTYPE"); //$NON-NLS-1$
if (i < 0)
return null;
int j = body.indexOf(">", i); //$NON-NLS-1$
if (j < 0)
return null;
return body.substring(i, j+1);
}
}