/*******************************************************************************
* Copyright (c) 2007 IBM Corporation.
* 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:
* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation
*******************************************************************************/
package org.eclipse.imp.language;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.eclipse.imp.editor.OutlineContentProviderBase;
import org.eclipse.imp.editor.OutlineLabelProvider.IElementImageProvider;
import org.eclipse.imp.indexing.IndexContributorBase;
import org.eclipse.imp.parser.IModelListener;
import org.eclipse.imp.parser.IParseController;
import org.eclipse.imp.runtime.RuntimePlugin;
import org.eclipse.imp.services.IASTAdapter;
import org.eclipse.imp.services.IAnnotationHover;
import org.eclipse.imp.services.IAutoEditStrategy;
import org.eclipse.imp.services.ICompareNodeIdentifier;
import org.eclipse.imp.services.IContentProposer;
import org.eclipse.imp.services.IDocumentationProvider;
import org.eclipse.imp.services.IEntityImageDecorator;
import org.eclipse.imp.services.IEntityNameLocator;
import org.eclipse.imp.services.IFoldingUpdater;
import org.eclipse.imp.services.IHelpService;
import org.eclipse.imp.services.IHoverHelper;
import org.eclipse.imp.services.ILabelProvider;
import org.eclipse.imp.services.ILanguageActionsContributor;
import org.eclipse.imp.services.ILanguageSyntaxProperties;
import org.eclipse.imp.services.INavigationTargetFinder;
import org.eclipse.imp.services.IOccurrenceMarker;
import org.eclipse.imp.services.IOutliner;
import org.eclipse.imp.services.IRefactoringContributor;
import org.eclipse.imp.services.IReferenceResolver;
import org.eclipse.imp.services.ISourceFormatter;
import org.eclipse.imp.services.ISourceHyperlinkDetector;
import org.eclipse.imp.services.IToggleBreakpointsHandler;
import org.eclipse.imp.services.ITokenColorer;
import org.eclipse.imp.services.base.TreeModelBuilderBase;
import org.eclipse.imp.utils.ExtensionException;
import org.eclipse.imp.utils.ExtensionFactory;
/**
* This class stores language services. IMP services are configured with
* language specific extension points. This registry provides implementations
* for them. It finds the implementations by looking for Eclipse extensions for
* IMP's extension points.
*
* If IMP is extended with a new kind of language service, this class must be
* extended.
*
* The getter methods of this class return 'null' when a service does not exist
* (i.e. an extension has not been provided yet)
*
* The getter methods of this class will throw unchecked exceptions when the
* extension implementations are not well formed.
*
* The getter methods only load the extension implementations the first time
* somebody asks for them. After that they are cached in the registry. This lazy
* behavior is necessary to optimize the startup time of Eclipse.
*
* @author jurgenv
*/
public class ServiceFactory {
private static ServiceFactory sInstance;
/**
* The unqualified extension point ID for IMP language descriptors.
*/
public static final String LANGUAGE_DESCRIPTION_POINT_ID = "languageDescription";
/**
* The qualified extension point ID for IMP language descriptors.
*/
public static final String LANGUAGE_DESCRIPTION_QUALIFIED_POINT_ID = RuntimePlugin.IMP_RUNTIME + ".languageDescription";
static final String AUTO_EDIT_STRATEGY_SERVICE = "autoEditStrategy";
static final String ANNOTATION_HOVER_SERVICE = "annotationHover";
static final String AST_ADAPTER_SERVICE = "astAdapter";
static final String COMPARE_NODE_IDENTIFIER_SERVICE = "compareNodeIdentifier";
static final String CONTENT_PROPOSER_SERVICE = "contentProposer";
static final String CONTEXT_HELPER_SERVICE= "contextHelper";
static final String DOCUMENTATION_PROVIDER_SERVICE = "documentationProvider";
static final String EDITOR_ACTION_CONTRIBUTIONS_SERVICE = "editorActionContributions";
static final String EDITOR_SERVICE= "editorService";
static final String ENTITY_IMAGE_DECORATOR_SERVICE = "entityImageDecorator";
static final String ENTITY_NAME_LOCATOR_SERVICE = "entityNameLocator";
static final String FOLDING_UPDATER_SERVICE = "foldingUpdater";
static final String FORMATTER_SERVICE = "formatter";
static final String HOVER_HELPER_SERVICE = "hoverHelper";
static final String HYPER_LINK_SERVICE = "hyperLink";
static final String IMAGE_DECORATOR_SERVICE = "imageDecorator";
static final String INDEX_CONTRIBUTOR_SERVICE = "indexContributor";
static final String LABEL_PROVIDER_SERVICE = "labelProvider";
static final String MODEL_LISTENER_SERVICE = "modelListener";
static final String MODEL_TREE_BUILDER_SERVICE = "modelTreeBuilder";
static final String MARK_OCCURRENCES_SERVICE = "markOccurrences";
static final String NAVIGATION_TARGET_FINDER_SERVICE = "navigationTargetFinder";
static final String OUTLINE_CONTENT_PROVIDER_SERVICE = "outlineContentProvider";
static final String OUTLINER_SERVICE = "outliner";
static final String PARSER_SERVICE = "parser";
static final String PREFERENCES_SERVICE = "preferencesDialog";
static final String PREFERENCES_SPECIFICATION = "preferencesSpecification";
static final String REFACTORING_CONTRIBUTIONS_SERVICE = "refactoringContributions";
static final String REFERENCE_RESOLVER_SERVICE = "referenceResolvers";
static final String SYNTAX_PROPS_SERVICE = "syntaxProps";
static final String TOGGLE_BREAKPOINTS_HANDLER_SERVICE= "toggleBreakpointHandler";
static final String TOKEN_COLORER_SERVICE = "tokenColorer";
static final String VIEWER_FILTER_SERVICE = "viewerFilter";
/**
* The list of fully-qualified extension point IDs for all IMP language services.
* Does not include the language descriptor extension point ID.
*/
public static final List<String> ALL_SERVICES= new LinkedList<String>();
static {
Class<ServiceFactory> clazz= ServiceFactory.class;
Field[] fields= clazz.getDeclaredFields();
for(int i= 0; i < fields.length; i++) {
Field field= fields[i];
if (field.getName().endsWith("_SERVICE") && Modifier.isStatic(field.getModifiers())) {
try {
String val= (String) field.get(null);
ALL_SERVICES.add(RuntimePlugin.IMP_RUNTIME + "." + val);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
}
}
protected ServiceFactory() { }
/**
* Returns the {@link ServiceFactory}. IMP services are configured with
* language specific extension points. This registry provides the
* implementations for them. This class finds these implementations via
* Eclipse's extension point mechanism.
*
* @return
*/
public static ServiceFactory getInstance() {
if (sInstance == null) {
sInstance = new ServiceFactory();
}
return sInstance;
}
public static ServiceFactory otherGetInstance() {
return sInstance;
}
public IAnnotationHover getAnnotationHover(Language lang) {
try {
return (IAnnotationHover) loadService(lang, ANNOTATION_HOVER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + ANNOTATION_HOVER_SERVICE + " does not implement IAnnotationHover",
e);
return null;
}
}
public IASTAdapter getASTAdapter(Language lang) {
try {
return (IASTAdapter) loadService(lang, AST_ADAPTER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + AST_ADAPTER_SERVICE + " does not implement IASTAdapter",
e);
return null;
}
}
public Set<IAutoEditStrategy> getAutoEditStrategies(Language lang) {
try {
Set<ILanguageService> services = loadServices(lang, AUTO_EDIT_STRATEGY_SERVICE);
Set<IAutoEditStrategy> autoEditStrategies = new HashSet<IAutoEditStrategy>();
for (ILanguageService s : services) {
autoEditStrategies.add((IAutoEditStrategy) s);
}
return autoEditStrategies;
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + AUTO_EDIT_STRATEGY_SERVICE + " does not implement IAutoEditStrategy",
e);
return null;
}
}
public ICompareNodeIdentifier getCompareNodeIdentifier(Language lang) {
try {
return (ICompareNodeIdentifier) loadService(lang, COMPARE_NODE_IDENTIFIER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + COMPARE_NODE_IDENTIFIER_SERVICE + " does not implement ICompareNodeIdentifier",
e);
return null;
}
}
public IContentProposer getContentProposer(Language lang) {
try {
return (IContentProposer) loadService(lang, CONTENT_PROPOSER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + CONTENT_PROPOSER_SERVICE + " does not implement IContentProposer",
e);
return null;
}
}
public IHelpService getContextHelper(Language lang) {
try {
return (IHelpService) loadService(lang, CONTEXT_HELPER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + CONTEXT_HELPER_SERVICE + " does not implement IHelpService",
e);
return null;
}
}
public IDocumentationProvider getDocumentationProvider(Language lang) {
try {
return (IDocumentationProvider) loadService(lang, DOCUMENTATION_PROVIDER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + DOCUMENTATION_PROVIDER_SERVICE + " does not implement IDocumentationProvider",
e);
return null;
}
}
public Set<IModelListener> getEditorServices(Language lang) {
Set<IModelListener> result= new HashSet<IModelListener>();
for(ILanguageService service: createExtensions(lang, EDITOR_SERVICE)) {
result.add((IModelListener) service);
}
return result;
}
public IElementImageProvider getElementImageProvider(Language lang) {
try {
return (IElementImageProvider) loadService(lang, IMAGE_DECORATOR_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + IMAGE_DECORATOR_SERVICE + " does not implement IElementImageProvider",
e);
return null;
}
}
public IEntityImageDecorator getEntityImageDecorator(Language lang) {
try {
return (IEntityImageDecorator) loadService(lang, ENTITY_IMAGE_DECORATOR_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + ENTITY_IMAGE_DECORATOR_SERVICE + " does not implement IEntityImageDecorator",
e);
return null;
}
}
public IEntityNameLocator getEntityNameLocator(Language lang) {
try {
return (IEntityNameLocator) loadService(lang, ENTITY_NAME_LOCATOR_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + ENTITY_NAME_LOCATOR_SERVICE + " does not implement IEntityNameLocator",
e);
return null;
}
}
public IFoldingUpdater getFoldingUpdater(Language lang) {
try {
return (IFoldingUpdater) loadService(lang, FOLDING_UPDATER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + FOLDING_UPDATER_SERVICE + " does not implement IFoldingUpdater",
e);
return null;
}
}
public IHoverHelper getHoverHelper(Language lang) {
try {
return (IHoverHelper) loadService(lang, HOVER_HELPER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + HOVER_HELPER_SERVICE + " does not implement IHoverHelper",
e);
return null;
}
}
public IndexContributorBase getIndexContributor(Language lang) {
try {
return (IndexContributorBase) loadService(lang,
INDEX_CONTRIBUTOR_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + INDEX_CONTRIBUTOR_SERVICE + " does not implement IndexContributorBase",
e);
return null;
}
}
public ILabelProvider getLabelProvider(Language lang) {
try {
return (ILabelProvider) loadService(lang, LABEL_PROVIDER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + LABEL_PROVIDER_SERVICE + " does not implement ILabelProvider",
e);
return null;
}
}
public Set<ILanguageActionsContributor> getLanguageActionsContributors(
Language lang) {
try {
Set<ILanguageService> services = loadServices(lang, EDITOR_ACTION_CONTRIBUTIONS_SERVICE);
Set<ILanguageActionsContributor> actionContributors = new HashSet<ILanguageActionsContributor>();
for (ILanguageService s : services) {
actionContributors.add((ILanguageActionsContributor) s);
}
return actionContributors;
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + EDITOR_ACTION_CONTRIBUTIONS_SERVICE + " does not implement ILanguageActionConstributor",
e);
return null;
}
}
public IModelListener getModelListener(Language lang) {
try {
return (IModelListener) loadService(lang, MODEL_LISTENER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + MODEL_LISTENER_SERVICE + " does not implement IModelListener",
e);
return null;
}
}
public INavigationTargetFinder getNavigationTargetFinder(Language lang) {
try {
return (INavigationTargetFinder) loadService(lang, NAVIGATION_TARGET_FINDER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of NAVIGATION_TARGET_FINDER does not implement INavigationTargetFinder",
e);
return null;
}
}
public IOccurrenceMarker getOccurrenceMarker(Language lang) {
try {
return (IOccurrenceMarker) loadService(lang, MARK_OCCURRENCES_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + MARK_OCCURRENCES_SERVICE + " does not implement IOccurrenceMarker",
e);
return null;
}
}
public OutlineContentProviderBase getOutlineContentProvider(Language lang) {
try {
return (OutlineContentProviderBase) loadService(lang, OUTLINE_CONTENT_PROVIDER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + OUTLINE_CONTENT_PROVIDER_SERVICE + " does not implement OutlineContentProviderBase",
e);
return null;
}
}
public IOutliner getOutliner(Language lang) {
try {
return (IOutliner) loadService(lang, OUTLINER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + OUTLINER_SERVICE + " does not implement IOutliner",
e);
return null;
}
}
public IParseController getParseController(Language lang) {
try {
return (IParseController) loadService(lang, PARSER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + PARSER_SERVICE + " does not implement IParseController",
e);
return null;
}
}
public Set<IRefactoringContributor> getRefactoringContributors(Language lang) {
try {
Set<ILanguageService> services = loadServices(lang, REFACTORING_CONTRIBUTIONS_SERVICE);
Set<IRefactoringContributor> refactoringContribs = new HashSet<IRefactoringContributor>();
for (ILanguageService s : services) {
refactoringContribs.add((IRefactoringContributor) s);
}
return refactoringContribs;
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + REFACTORING_CONTRIBUTIONS_SERVICE + " does not implement IRefactoringContributor",
e);
return null;
}
}
public IReferenceResolver getReferenceResolver(Language lang) {
try {
return (IReferenceResolver) loadService(lang, REFERENCE_RESOLVER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + REFERENCE_RESOLVER_SERVICE + " does not implement IReferenceResolver",
e);
return null;
}
}
public ISourceFormatter getSourceFormatter(Language lang) {
try {
return (ISourceFormatter) loadService(lang, FORMATTER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + FORMATTER_SERVICE + " does not implement ISourceFormatter",
e);
return null;
}
}
public ISourceHyperlinkDetector getSourceHyperlinkDetector(Language lang) {
try {
return (ISourceHyperlinkDetector) loadService(lang, HYPER_LINK_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + HYPER_LINK_SERVICE + " does not implement ISourceHyperlinkDetector",
e);
return null;
}
}
public ILanguageSyntaxProperties getSyntaxProperties(Language lang) {
try {
return (ILanguageSyntaxProperties) loadService(lang, SYNTAX_PROPS_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + SYNTAX_PROPS_SERVICE + " does not implement ILanguageSyntaxProperties",
e);
return null;
}
}
public IToggleBreakpointsHandler getToggleBreakpointsHandler(Language lang) {
try {
return (IToggleBreakpointsHandler) loadService(lang, TOGGLE_BREAKPOINTS_HANDLER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + TOGGLE_BREAKPOINTS_HANDLER_SERVICE + " does not implement IToggleBreakpointsHandler",
e);
return null;
}
}
public ITokenColorer getTokenColorer(Language lang) {
try {
return (ITokenColorer) loadService(lang, TOKEN_COLORER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + TOKEN_COLORER_SERVICE + " does not implement ITokenColorer",
e);
return null;
}
}
public TreeModelBuilderBase getTreeModelBuilder(Language lang) {
try {
return (TreeModelBuilderBase) loadService(lang, MODEL_TREE_BUILDER_SERVICE);
} catch (ClassCastException e) {
RuntimePlugin.getInstance().logException(
"Alleged implementation of " + MODEL_TREE_BUILDER_SERVICE + " does not implement TreeModelBuilderBase",
e);
return null;
}
}
private ILanguageService createExtension(Language lang, String id) {
try {
return ExtensionFactory.createServiceExtension(lang, id);
} catch (ExtensionException e) {
RuntimePlugin.getInstance().logException(
"Failed to create extension: " + id, e);
return null;
}
}
private Set<ILanguageService> createExtensions(Language lang, String id) {
try {
return ExtensionFactory.createServiceExtensionSet(lang, id);
}
catch (ExtensionException e) {
RuntimePlugin.getInstance().logException(
"Failed to create set of extensions for: " + id, e);
return new HashSet<ILanguageService>();
}
}
private Set<ILanguageService> loadServices(Language lang, String serviceId) {
return createExtensions(lang, serviceId);
}
private ILanguageService loadService(Language lang, String name) {
if (lang == null) {
RuntimePlugin.getInstance().writeErrorMsg("Null language for service = " + name);
return null;
}
if (name == null) {
RuntimePlugin.getInstance().writeErrorMsg("Null service for language = " + lang);
return null;
}
return createExtension(lang, name);
}
}