blob: 2a63cfa7c48dbcb8eac877a56b28f92813485edb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2004 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.sse.core.internal.modelhandler;
import java.io.IOException;
import java.io.InputStream;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.wst.sse.core.internal.Logger;
import org.eclipse.wst.sse.core.internal.encoding.CodedIO;
import org.eclipse.wst.sse.core.internal.ltk.modelhandler.IModelHandler;
import org.eclipse.wst.sse.core.internal.util.Utilities;
public class ModelHandlerRegistry {
private static ModelHandlerRegistry instance = null;
static final String INTERNAL_DEFAULT_EXTENSION = "org.eclipse.wst.xml.core.internal.modelhandler"; //$NON-NLS-1$
public synchronized static ModelHandlerRegistry getInstance() {
if (instance == null) {
instance = new ModelHandlerRegistry();
}
return instance;
}
private IModelHandler defaultHandler = null;
private ModelHandlerRegistryReader reader = new ModelHandlerRegistryReader();
private ModelHandlerRegistry() {
super();
reader = new ModelHandlerRegistryReader().readRegistry();
}
/**
* Finds the default model handler. Note: we still go through the registry
* to be sure to get the existing instance, but then we do remember it, so
* subsequent requests will be faster. The first time through, we do check
* the whole list, to be sure there is only one.
*
*/
final public IModelHandler getDefault() {
if (defaultHandler == null) {
IConfigurationElement[] elements = reader.elements;
for (int i = 0; i < elements.length; i++) {
boolean ofInterest = reader.isElementDefault(elements[i]);
if (ofInterest) {
/*
* If, here within the search loop we've already found one
* defaultHandler, then something is wrong!
*/
if (defaultHandler == null) {
defaultHandler = reader.getInstance(elements[i]);
}
else {
String errorString = "Program or configuration error. More than one default content handler found"; //$NON-NLS-1$
Logger.log(Logger.ERROR, errorString);
throw new IllegalStateException(errorString);
}
}
}
}
if (defaultHandler == null) {
String errorString = "Program or configuration error. No default content type handler found."; //$NON-NLS-1$
Logger.log(Logger.ERROR, errorString);
throw new IllegalStateException(errorString);
}
return defaultHandler;
}
/**
* Finds a ModelHandler based on literal extension id. It's basically a
* "first found first returned". No specific order is guaranteed and the
* uniqueness of IDs is not considered.
*
* @param extensionId
* @return the given extension, or null
*/
private IModelHandler getHandlerExtension(String extensionId) {
IModelHandler found = null;
IConfigurationElement[] elements = reader.elements;
if (elements != null) {
for (int i = 0; i < elements.length; i++) {
String currentId = reader.getId(elements[i]);
if (extensionId.equals(currentId)) {
IModelHandler item = reader.getInstance(elements[i]);
found = item;
}
}
}
else if (Logger.DEBUG){
Logger.log(Logger.WARNING, "There were no Model Handler found in registry"); //$NON-NLS-1$
}
return found;
}
/**
* Finds the registered IModelHandler for a given named file's content
* type.
*
* @param file
* @return The IModelHandler registered for the content type of the given
* file. If an exact match is not found, the most-specific match
* according to IContentType.isKindOf() will be returned. If none
* are found, either a default or null will be returned.
* @throws CoreException
*/
public IModelHandler getHandlerFor(IFile file) throws CoreException {
IModelHandler modelHandler = null;
IContentDescription contentDescription = null;
IContentType contentType = null;
boolean accessible = file.isAccessible();
if (accessible) {
/* Try the optimized method first as the description may be cached */
contentDescription = file.getContentDescription();
if (contentDescription != null) {
// use the provided description
contentType = contentDescription.getContentType();
}
else {
/* use the more thorough discovery method to get a description */
InputStream contents = null;
try {
contents = file.getContents(true);
contentDescription = Platform.getContentTypeManager().getDescriptionFor(contents, file.getName(), IContentDescription.ALL);
if (contentDescription != null) {
contentType = contentDescription.getContentType();
}
}
catch (IOException e) {
// nothing further can be done, but will log for debugging
Logger.logException(e);
}
finally {
if (contents != null) {
try {
contents.close();
}
catch (IOException e1) {
// nothing can be done
}
}
}
}
}
/*
* If we couldn't get the content type from a description, try basing
* it on just the filename
*/
if (contentType == null) {
contentType = Platform.getContentTypeManager().findContentTypeFor(file.getName());
}
if (contentType != null) {
modelHandler = getHandlerForContentType(contentType);
}
else {
// hard coding for null content type
modelHandler = getHandlerExtension(INTERNAL_DEFAULT_EXTENSION); //$NON-NLS-1$
}
return modelHandler;
}
/**
* Finds the registered IModelHandler for a given named InputStream.
*
* @param inputName
* @param inputStream
* @return The IModelHandler registered for the content type of the given
* input. If an exact match is not found, the most-specific match
* according to IContentType.isKindOf() will be returned. If none
* are found, either a default or null will be returned.
* @throws IOException
*/
public IModelHandler getHandlerFor(String inputName, InputStream inputStream) throws IOException {
InputStream iStream = Utilities.getMarkSupportedStream(inputStream);
IModelHandler modelHandler = null;
IContentType contentType = null;
if (inputStream != null) {
try {
iStream.mark(CodedIO.MAX_MARK_SIZE);
contentType = Platform.getContentTypeManager().findContentTypeFor(Utilities.getLimitedStream(iStream), inputName);
}
finally {
if (iStream != null && iStream.markSupported()) {
iStream.reset();
}
}
}
if (contentType == null) {
contentType = Platform.getContentTypeManager().findContentTypeFor(inputName);
}
// if all else failed, try to detect solely on contents; done last for
// performance reasons
if (contentType == null) {
contentType = Platform.getContentTypeManager().findContentTypeFor(Utilities.getLimitedStream(iStream), null);
}
modelHandler = getHandlerForContentType(contentType);
return modelHandler;
}
/**
* Finds the registered IModelHandler for a given IContentType.
*
* @param contentType
* @return The IModelHandler registered for the given content type. If an
* exact match is not found, the most-specific match according to
* IContentType.isKindOf() will be returned. If none are found,
* either a default or null will be returned.
*/
private IModelHandler getHandlerForContentType(IContentType contentType) {
IModelHandler handler = null;
if (contentType != null) {
IConfigurationElement exactContentTypeElement = null;
IConfigurationElement kindOfContentTypeElement = null;
int kindOfContentTypeDepth = 0;
IConfigurationElement[] elements = reader.elements;
if (elements != null) {
for (int i = 0; i < elements.length && exactContentTypeElement == null; i++) {
String currentId = reader.getAssociatedContentTypeId(elements[i]);
IContentType associatedContentType = Platform.getContentTypeManager().getContentType(currentId);
if (contentType.equals(associatedContentType)) {
exactContentTypeElement = elements[i];
}
else if (contentType.isKindOf(associatedContentType)) {
/*
* Update the kindOfElement variable only if this
* element's content type is "deeper" (depth test
* ensures the first content type is remembered)
*/
IContentType testContentType = associatedContentType;
int testDepth = 0;
while (testContentType != null) {
testDepth++;
testContentType = testContentType.getBaseType();
}
if (testDepth > kindOfContentTypeDepth) {
kindOfContentTypeElement = elements[i];
kindOfContentTypeDepth = testDepth;
}
}
}
}
else if (Logger.DEBUG){
Logger.log(Logger.WARNING, "There were no Model Handler found in registry"); //$NON-NLS-1$
}
if (exactContentTypeElement != null) {
handler = reader.getInstance(exactContentTypeElement);
}
else if (kindOfContentTypeElement != null) {
handler = reader.getInstance(kindOfContentTypeElement);
}
}
if (handler == null) {
// temp hard coding for null content type arguments
handler = getHandlerExtension(INTERNAL_DEFAULT_EXTENSION); //$NON-NLS-1$
}
return handler;
}
/**
* Finds the registered IModelHandler for a given content type ID. No
* specific order is guaranteed and the uniqueness of IDs is not
* considered.
*
* @param contentType
* @return The IModelHandler registered for the given content type ID. If
* an exact match is not found, the most-specific match according
* to IContentType.isKindOf() will be returned. If none are found,
* either a default or null will be returned.
*/
public IModelHandler getHandlerForContentTypeId(String contentTypeId) {
IContentType contentType = Platform.getContentTypeManager().getContentType(contentTypeId);
return getHandlerForContentType(contentType);
}
}