blob: a4900efce84f588bf6d60c9f0b5c6db92a32ed23 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are 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:
* IBM Corporation - initial API and implementation
* Jens Lukowski/Innoopract - initial renaming/restructuring
*
*******************************************************************************/
package org.eclipse.wst.xml.core.internal.contentmodel.modelqueryimpl;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.wst.sse.core.utils.StringUtils;
import org.eclipse.wst.xml.core.internal.Logger;
import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.CMDocumentManager;
import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.IExternalSchemaLocationProvider;
import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.ModelQuery;
import org.eclipse.wst.xml.core.internal.contentmodel.util.CMDocumentCache;
import org.eclipse.wst.xml.core.internal.contentmodel.util.NamespaceInfo;
import org.eclipse.wst.xml.core.internal.contentmodel.util.NamespaceTable;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
*
*/
public class CMDocumentLoader
{
private final static boolean _trace = Boolean.valueOf(Platform.getDebugOption("org.eclipse.wst.xml.core/externalSchemaLocation")).booleanValue(); //$NON-NLS-1$
protected Document document;
protected ModelQuery modelQuery;
protected CMDocumentManager cmDocumentManager;
protected boolean isInferredGrammarEnabled = true;
protected CMDocumentLoadingNamespaceTable namespaceTable;
protected int count = 0;
public CMDocumentLoader(Document document, ModelQuery modelQuery)
{
this(document, modelQuery.getCMDocumentManager());
}
public CMDocumentLoader(Document document, CMDocumentManager cmDocumentManager)
{
this.document = document;
this.cmDocumentManager = cmDocumentManager;
}
public void loadCMDocuments()
{
//System.out.println("----------loadCMDocuments ------------");
//long time = System.currentTimeMillis();
boolean walkDocument = false;
cmDocumentManager.removeAllReferences();
String[] doctypeInfo = XMLAssociationProvider.getDoctypeInfo(document);
if (doctypeInfo != null)
{
// load the doctype if required
walkDocument = handleGrammar(doctypeInfo[0], doctypeInfo[1], "DTD"); //$NON-NLS-1$
}
else
{
Element element = getRootElement(document);
if (element != null)
{
namespaceTable = new CMDocumentLoadingNamespaceTable(document);
namespaceTable.addElement(element);
if (namespaceTable.isNamespaceEncountered())
{
walkDocument = true;
//System.out.println("isNamespaceAware");
}
else
{
namespaceTable = null;
walkDocument = isInferredGrammarEnabled;
//System.out.println("is NOT namespaceAware");
}
}
}
if (walkDocument)
{
if (!checkExternalSchema())
visitNode(document);
}
//System.out.println("--- elapsed time (" + count + ") = " + (System.currentTimeMillis() - time));
}
protected boolean checkExternalSchema() {
boolean externalSchemaLoaded = false;
if (document instanceof IDOMDocument) {
final String baseLocation = ((IDOMDocument) document).getModel().getBaseLocation();
if (baseLocation == null)
return false;
final IPath basePath = new Path(baseLocation);
IFile file = null;
if (basePath.segmentCount() > 1) {
file = ResourcesPlugin.getWorkspace().getRoot().getFile(basePath);
}
final URI uri = (file == null || !file.isAccessible()) ? new File(baseLocation).toURI() : file.getLocationURI();
if (uri != null) {
IExternalSchemaLocationProvider[] providers = ExternalSchemaLocationProviderRegistry.getInstance().getProviders();
for (int i = 0; i < providers.length; i++) {
long time = _trace ? System.currentTimeMillis(): 0;
final Map locations = providers[i].getExternalSchemaLocation(uri);
if (_trace) {
long diff = System.currentTimeMillis() - time;
if (diff > 250)
Logger.log(Logger.INFO, "Schema location provider took [" + diff + "ms] for URI [" + uri + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if (locations != null && !locations.isEmpty()) {
// Use the externalSchemaLocation
if (namespaceTable != null && namespaceTable.isNamespaceEncountered()) {
final String location = locations.get(IExternalSchemaLocationProvider.SCHEMA_LOCATION).toString();
if (location != null) {
final String[] ids = StringUtils.asArray(location);
// namespace : location pairs
if (ids.length >= 2 && ids.length % 2 == 0) {
if (!externalSchemaLoaded)
cmDocumentManager.removeAllReferences();
for (int j = 0; j < ids.length; j+=2) {
handleGrammar(ids[j], ids[j + 1], "XSD"); //$NON-NLS-1$
externalSchemaLoaded = true;
}
}
}
}
else { // noNamespace
handleGrammar(uri.toString(), locations.get(IExternalSchemaLocationProvider.NO_NAMESPACE_SCHEMA_LOCATION).toString(), "XSD"); //$NON-NLS-1$
externalSchemaLoaded = true;
break;
}
}
}
}
}
return externalSchemaLoaded;
}
public boolean handleGrammar(String publicId, String systemId, String type)
{
boolean result = false;
int status = cmDocumentManager.getCMDocumentStatus(publicId);
if (status == CMDocumentCache.STATUS_NOT_LOADED)
{
cmDocumentManager.addCMDocumentReference(publicId, systemId, type);
}
else if (status == CMDocumentCache.STATUS_ERROR)
{
result = true;
}
return result;
}
public void handleElement(Element element)
{
visitChildNodes(element);
}
public void handleElementNS(Element element)
{
namespaceTable.addElement(element);
visitChildNodes(element);
}
public void visitNode(Node node)
{
int nodeType = node.getNodeType();
if (nodeType == Node.ELEMENT_NODE)
{
count++;
Element element = (Element)node;
if (namespaceTable == null)
{
handleElement(element);
}
else
{
handleElementNS(element);
}
}
else if (nodeType == Node.DOCUMENT_NODE)
{
visitChildNodes(node);
}
}
protected void visitChildNodes(Node node)
{
for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling())
{
visitNode(child);
}
}
protected class CMDocumentLoadingNamespaceTable extends NamespaceTable
{
protected List newNamespaceList;
public CMDocumentLoadingNamespaceTable(Document document)
{
super(document);
}
public void addElement(Element element)
{
newNamespaceList = null;
super.addElement(element);
if (newNamespaceList != null)
{
for (Iterator i = newNamespaceList.iterator(); i.hasNext(); )
{
NamespaceInfo info = (NamespaceInfo)i.next();
handleGrammar(info.uri, info.locationHint, "XSD"); //$NON-NLS-1$
}
}
}
protected void internalAddNamespaceInfo(String key, NamespaceInfo info)
{
super.internalAddNamespaceInfo(key, info);
if (newNamespaceList == null)
{
newNamespaceList = new ArrayList();
}
newNamespaceList.add(info);
}
}
protected Element getRootElement(Document document)
{
Element result = null;
NodeList nodeList = document.getChildNodes();
int nodeListLength = nodeList.getLength();
for (int i = 0 ; i < nodeListLength; i++)
{
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE)
{
result = (Element)node;
break;
}
}
return result;
}
}