| /*=============================================================================# |
| # Copyright (c) 2014, 2019 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.internal.docmlet.wikitext.core; |
| |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IContributor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.content.IContentType; |
| import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; |
| import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; |
| import org.eclipse.osgi.util.NLS; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.ecommons.preferences.core.Preference; |
| import org.eclipse.statet.ecommons.preferences.core.PreferenceAccess; |
| import org.eclipse.statet.ecommons.preferences.core.util.PreferenceUtils; |
| |
| import org.eclipse.statet.docmlet.wikitext.core.WikitextCore; |
| import org.eclipse.statet.docmlet.wikitext.core.markup.MarkupConfig; |
| import org.eclipse.statet.docmlet.wikitext.core.markup.WikitextMarkupLanguage; |
| import org.eclipse.statet.docmlet.wikitext.core.markup.WikitextMarkupLanguageManager; |
| |
| |
| public class MarkupLanguageManager implements WikitextMarkupLanguageManager { |
| |
| |
| private static final String EXTENSION_POINT_ID= "org.eclipse.statet.docmlet.WikitextMarkupLanguages"; //$NON-NLS-1$ |
| |
| private static final String NAME_ATTRIBUTE_NAME= "name"; //$NON-NLS-1$ |
| private static final String LABEL_ATTRIBUTE_NAME= "label"; //$NON-NLS-1$ |
| private static final String CLASS_ATTRIBUTE_NAME= "class"; //$NON-NLS-1$ |
| private static final String CONFIG_CLASS_ATTRIBUTE_NAME= "configClass"; //$NON-NLS-1$ |
| private static final String CONTENT_TYPE_ID_ATTRIBUTE_NAME= "contentTypeId"; //$NON-NLS-1$ |
| |
| private static final String CONFIG_WORKBENCH_KEY= "MarkupConfig.Workbench.config"; //$NON-NLS-1$ |
| |
| |
| protected final class MLEntry implements WikitextMarkupLanguageDescriptor, IPreferenceChangeListener { |
| |
| private static final byte S_LANGUAGE_FAILED= 0b0_00010000; |
| private static final byte S_CONFIG_FAILED= 0b0_00100000; |
| |
| |
| private final String name; |
| private final String label; |
| |
| private final String contentTypdId; |
| |
| |
| private final IConfigurationElement element; |
| |
| private byte state; |
| |
| |
| private final String prefQualifier; |
| |
| private volatile WikitextMarkupLanguage mlInstance; |
| |
| |
| public MLEntry(final String name, final IConfigurationElement element) { |
| this.name= name.intern(); |
| |
| { final String value= element.getAttribute(LABEL_ATTRIBUTE_NAME); |
| this.label= (value != null && !value.isEmpty()) ? value.intern() : this.name; |
| } |
| { final String value= element.getAttribute(CONTENT_TYPE_ID_ATTRIBUTE_NAME); |
| this.contentTypdId= (value != null && !value.isEmpty()) ? value.intern() : null; |
| } |
| |
| this.element= element; |
| |
| final String pluginId= this.element.getContributor().getName(); |
| this.prefQualifier= pluginId + "/markup/" + name; //$NON-NLS-1$ |
| } |
| |
| |
| @Override |
| public String getName() { |
| return this.name; |
| } |
| |
| @Override |
| public IContributor getContributor() { |
| return this.element.getContributor(); |
| } |
| |
| @Override |
| public String getPreferenceQualifier() { |
| return this.prefQualifier; |
| } |
| |
| @Override |
| public String getLabel() { |
| return this.label; |
| } |
| |
| public String getContentTypdId() { |
| return this.contentTypdId; |
| } |
| |
| public WikitextMarkupLanguage getLanguage() { |
| WikitextMarkupLanguage markupLanguage= this.mlInstance; |
| if (markupLanguage == null) { |
| synchronized (this) { |
| markupLanguage= this.mlInstance; |
| if (markupLanguage == null && (this.state & S_LANGUAGE_FAILED) == 0) { |
| try { |
| markupLanguage= (WikitextMarkupLanguage) |
| this.element.createExecutableExtension(CLASS_ATTRIBUTE_NAME); |
| if (!getName().equals(markupLanguage.getName())) { |
| throw new IllegalArgumentException("name"); //$NON-NLS-1$ |
| } |
| final MarkupConfig config= loadWorkbenchConfig(); |
| if (config != null) { |
| markupLanguage.setMarkupConfig(config); |
| } |
| this.mlInstance= markupLanguage; |
| } |
| catch (final CoreException e) { |
| this.state|= S_LANGUAGE_FAILED; |
| WikitextCorePlugin.log(new Status(IStatus.ERROR, WikitextCore.BUNDLE_ID, |
| NLS.bind("An error occurred when loading markup language ''{0}''.", getName()), |
| e )); |
| return null; |
| } |
| } |
| } |
| } |
| return markupLanguage; |
| } |
| |
| protected MarkupConfig loadWorkbenchConfig() { |
| if (this.prefQualifier == null) { |
| return null; |
| } |
| |
| final MarkupConfig config= newConfig(); |
| if (config == null) { |
| return null; |
| } |
| |
| final PreferenceAccess prefs= PreferenceUtils.getInstancePrefs(); |
| prefs.addPreferenceNodeListener(this.prefQualifier, this); |
| final Preference<@Nullable String> pref= new Preference.NullableStringPref(this.prefQualifier, |
| "MarkupConfig.Workbench.config" ); //$NON-NLS-1$ |
| final String configString= prefs.getPreferenceValue(pref); |
| if (configString != null) { |
| config.load(configString); |
| } |
| return config; |
| } |
| |
| @Override |
| public boolean isConfigSupported() { |
| return (this.element.getAttribute(CONFIG_CLASS_ATTRIBUTE_NAME) != null |
| && (this.state & S_CONFIG_FAILED) == 0); |
| } |
| |
| @Override |
| public MarkupConfig newConfig() { |
| if (isConfigSupported()) { |
| try { |
| return (MarkupConfig) this.element.createExecutableExtension(CONFIG_CLASS_ATTRIBUTE_NAME); |
| } |
| catch (final CoreException e) { |
| this.state|= S_CONFIG_FAILED; |
| WikitextCorePlugin.log(new Status(IStatus.ERROR, WikitextCore.BUNDLE_ID, |
| NLS.bind("An error occurred when loading markup language ''{0}''.", getName()), |
| e )); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public void preferenceChange(final PreferenceChangeEvent event) { |
| if (event.getKey().equals(CONFIG_WORKBENCH_KEY)) { |
| synchronized (this) { |
| this.mlInstance.setMarkupConfig(loadWorkbenchConfig()); |
| } |
| configChanged(this.name); |
| } |
| } |
| |
| } |
| |
| |
| private List<String> names; |
| private final Map<String, MLEntry> nameMap= new HashMap<>(); |
| private final Map<String, MLEntry> contentTypeMap= new HashMap<>(); |
| |
| |
| public MarkupLanguageManager() { |
| readRegistry(); |
| } |
| |
| |
| private void readRegistry() { |
| final IConfigurationElement[] elements= Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID); |
| for (final IConfigurationElement element : elements) { |
| if (element.getName().equals("markupLanguage")) { //$NON-NLS-1$ |
| final String name= element.getAttribute(NAME_ATTRIBUTE_NAME); |
| if (name == null || name.isEmpty()) { |
| continue; |
| } |
| final MLEntry mlEntry= new MLEntry(name, element); |
| this.nameMap.put(mlEntry.getName(), mlEntry); |
| if (mlEntry.getContentTypdId() != null) { |
| this.contentTypeMap.put(mlEntry.getContentTypdId(), mlEntry); |
| } |
| } |
| } |
| { final Set<String> nameSet= this.nameMap.keySet(); |
| final String[] array= nameSet.toArray(new String[nameSet.size()]); |
| Arrays.sort(array); |
| this.names= ImCollections.newList(array); |
| } |
| } |
| |
| |
| @Override |
| public List<String> getLanguageNames() { |
| return this.names; |
| } |
| |
| @Override |
| public MLEntry getLanguageDescriptor(final String name) { |
| return this.nameMap.get(name); |
| } |
| |
| @Override |
| public WikitextMarkupLanguage getLanguage(final String name) { |
| final MLEntry mlEntry= this.nameMap.get(name); |
| return (mlEntry != null) ? mlEntry.getLanguage() : null; |
| } |
| |
| @Override |
| public WikitextMarkupLanguage getLanguage(final IContentType contentType) { |
| final MLEntry mlEntry= this.contentTypeMap.get(contentType.getId()); |
| return (mlEntry != null) ? mlEntry.getLanguage() : null; |
| } |
| |
| public String getLanguageName(final IContentType contentType) { |
| final MLEntry mlEntry= this.contentTypeMap.get(contentType.getId()); |
| return (mlEntry != null) ? mlEntry.getName() : null; |
| } |
| |
| protected MarkupConfig createNewConfig(final String languageName) { |
| final MLEntry mlEntry= this.nameMap.get(languageName); |
| return (mlEntry != null) ? mlEntry.newConfig() : null; |
| } |
| |
| protected void configChanged(final String languageName) { |
| } |
| |
| } |