blob: 4c442976fd1c0916fc2cf6e5ef85886fc02493e5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 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
*******************************************************************************/
package org.eclipse.wst.html.core.internal.modelquery;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.Platform;
import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument;
import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.CMDocumentManager;
import org.eclipse.wst.xml.core.internal.contentmodel.modelqueryimpl.XMLAssociationProvider;
import org.eclipse.wst.xml.core.internal.contentmodel.util.CMDocumentCache;
import org.w3c.dom.Document;
/**
* A Class to provide an association between XHTML documents and DTDs for
* XHTML. This class is intended to be used only in HTMLModelQueryCMProvider.
*/
/*
* This class closely resemble XMLModelQueryAssociationProvider.
*/
class XHTMLAssociationProvider extends XMLAssociationProvider {
/**
* set CACHE_FIXED_DOCUMENTS to false to test effects of not caching certain catalog-contributed schemas.
*/
private static final boolean CACHE_FIXED_DOCUMENTS = true;
private static final String[] STANDARD_SCHEMA_BUNDLES = new String[] {"org.eclipse.wst.standard.schemas","org.eclipse.jst.standard.schemas"};
private static final String XML_CATALOG_EXT_POINT = "org.eclipse.wst.xml.core.catalogContributions";
private static Collection fFixedPublicIDs = null;
private static Map fFixedCMDocuments = new HashMap();
/**
* set USE_QUICK_CACHE to false to test effects of not caching at all.
*/
private static final boolean USE_QUICK_CACHE = true;
protected URIResolver idResolver;
private String fCachedGrammerURI;
private String fCachedPublicID;
private String fCachedSystemID;
private boolean cached;
public XHTMLAssociationProvider(CMDocumentCache cache, URIResolver idResolver) {
super(cache);
this.idResolver = idResolver;
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=136399. If the CM document URI
// is resolved and cached at this level instruct the CM model manager to avoid
// re-resolving the URI.
if (USE_QUICK_CACHE) {
documentManager.setPropertyEnabled(CMDocumentManager.PROPERTY_PERFORM_URI_RESOLUTION, false);
}
}
/**
*
* @param publicId
* @param systemId
* @return
*/
public CMDocument getXHTMLCMDocument(String publicId, String systemId) {
if (idResolver == null)
return null;
String grammerURI = null;
if (USE_QUICK_CACHE) {
/*
* In parsing a document, we get many identical requests to this
* method, so instead of looking up (resolving) grammerURI each
* time, we'll just return previously cached one. Probably not
* worth have a more complex cache than that.
*/
if (cached && sameAs(fCachedPublicID, publicId) && sameAs(fCachedSystemID, systemId)) {
grammerURI = fCachedGrammerURI;
}
else {
grammerURI = idResolver.resolve(null, publicId, systemId);
fCachedGrammerURI = grammerURI;
fCachedPublicID = publicId;
fCachedSystemID = systemId;
cached = true;
}
}
else {
grammerURI = idResolver.resolve(null, publicId, systemId);
}
if (grammerURI == null)
return null;
CMDocument cmDocument = null;
if (CACHE_FIXED_DOCUMENTS) {
Reference ref = (Reference) fFixedCMDocuments.get(publicId);
if (ref != null) {
cmDocument = (CMDocument) ref.get();
if (cmDocument != null) {
return cmDocument;
}
}
}
/*
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=88896
*
* We once called the deprecated 2 argument form of getCMDocument.
*
* CMDocument cmDocument = documentManager.getCMDocument(publicId,
* grammerURI);
*
* which eventually resulted in empty string for type, which I don't
* think the infrastructure handles any longer. So, I deleted
* deprecated methods, and switched to null for type argument.
*
* 'null' means to "create based on uri".
*
* FYI, 'dtd' would mean load only those registered as dtd's
*
* CMDocument cmDocument = documentManager.getCMDocument(publicId,
* grammerURI); CMDocument cmDocument =
* documentManager.getCMDocument(publicId, grammerURI, "dtd");
*/
synchronized (grammerURI) {
cmDocument = documentManager.getCMDocument(publicId, grammerURI, null);
}
if (CACHE_FIXED_DOCUMENTS && getFixedPublicIDs().contains(publicId)) {
fFixedCMDocuments.put(publicId, new SoftReference(cmDocument));
}
return cmDocument;
}
/**
*/
protected String resolveGrammarURI(Document document, String publicId, String systemId) {
return idResolver.resolve(null, publicId, systemId);
}
private boolean sameAs(String a, String b) {
boolean result = false;
if (a == null) {
result = b == null;
}
else {
result = a.equals(b);
}
return result;
}
/**
* This added and/or made public specifically for experimentation. It
* will change as this functionality becomes API. See
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=119084
*/
public String getCachedGrammerURI() {
return fCachedGrammerURI;
}
/**
* @return the fFixedPublicIDs, a collection of contributed Public
* Identifiers from the known schema plug-ins.
*/
private static Collection getFixedPublicIDs() {
/**
* public:publicId
* TODO: system:systemId and uri:name in their own methods and maps?
*/
synchronized (STANDARD_SCHEMA_BUNDLES) {
if (fFixedPublicIDs == null) {
fFixedPublicIDs = new HashSet();
for (int i = 0; i < STANDARD_SCHEMA_BUNDLES.length; i++) {
IExtension[] extensions = Platform.getExtensionRegistry().getExtensions(STANDARD_SCHEMA_BUNDLES[i]);
for (int j = 0; j < extensions.length; j++) {
if (XML_CATALOG_EXT_POINT.equals(extensions[j].getExtensionPointUniqueIdentifier())) {
IConfigurationElement[] configurationElements = extensions[j].getConfigurationElements();
for (int k = 0; k < configurationElements.length; k++) {
IConfigurationElement[] publics = configurationElements[k].getChildren("public");
for (int l = 0; l < publics.length; l++) {
String publicId = publics[l].getAttribute("publicId");
if (publicId != null && publicId.length() > 0) {
fFixedPublicIDs.add(publicId);
}
}
}
}
}
}
}
}
return fFixedPublicIDs;
}
}