| /*=============================================================================# |
| # Copyright (c) 2015, 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.base.ui.processing; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.osgi.util.NLS; |
| |
| import org.eclipse.statet.jcommons.lang.Disposable; |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.docmlet.base.ui.DocmlBaseUI; |
| import org.eclipse.statet.docmlet.base.ui.processing.DocProcessingManager; |
| import org.eclipse.statet.internal.docmlet.base.ui.DocmlBaseUIPlugin; |
| |
| |
| @NonNullByDefault |
| public class DocProcessingRegistry implements Disposable { |
| |
| |
| private static final String EXTENSION_POINT_ID= "org.eclipse.statet.docmlet.DocProcessing"; //$NON-NLS-1$ |
| |
| private static final String PROCESSING_TYPE_ELEMENT_NAME= "processingType"; //$NON-NLS-1$ |
| private static final String CONTENT_TYPE_ID_ATTR_NAME= "contentTypeId"; //$NON-NLS-1$ |
| private static final String CONFIG_TYPE_ID_ATTR_NAME= "configTypeId"; //$NON-NLS-1$ |
| private static final String MANAGER_CLASS_ATTR_NAME= "managerClass"; //$NON-NLS-1$ |
| |
| |
| public static class ManagerConfig { |
| |
| public final String contentTypeId; |
| |
| public final String configTypeId; |
| |
| public ManagerConfig(final String contentTypeId, final String configTypeId) { |
| this.contentTypeId= contentTypeId; |
| this.configTypeId= configTypeId; |
| } |
| |
| } |
| |
| private static class TypeEntry { |
| |
| private static final byte S_MANAGER_FAILED= 0b0_00000001; |
| private static final byte S_DISPOSED= (byte) 0b0_10000000; |
| |
| |
| private final String contentTypeId; |
| |
| |
| private final IConfigurationElement element; |
| |
| private byte state; |
| |
| |
| private @Nullable DocProcessingManager manager; |
| |
| |
| public TypeEntry(final String contentTypeId, final IConfigurationElement element) { |
| this.contentTypeId= contentTypeId.intern(); |
| this.element= element; |
| } |
| |
| |
| public String getContentTypeId() { |
| return this.contentTypeId; |
| } |
| |
| public @Nullable DocProcessingManager getManager() { |
| DocProcessingManager manager= this.manager; |
| if (manager == null) { |
| synchronized (this) { |
| manager= this.manager; |
| if (manager == null && (this.state & (S_MANAGER_FAILED | S_DISPOSED)) == 0) { |
| try { |
| final ManagerConfig config= new ManagerConfig( |
| this.contentTypeId, |
| this.element.getAttribute(CONFIG_TYPE_ID_ATTR_NAME) ); |
| manager= (DocProcessingManager) |
| this.element.createExecutableExtension(MANAGER_CLASS_ATTR_NAME); |
| manager.init(config); |
| this.manager= manager; |
| } |
| catch (final CoreException e) { |
| this.state|= S_MANAGER_FAILED; |
| DocmlBaseUIPlugin.log(new Status(IStatus.ERROR, DocmlBaseUI.BUNDLE_ID, 0, |
| NLS.bind("An error occurred when loading document processing type ''{0}''.", getContentTypeId()), |
| e )); |
| return null; |
| } |
| } |
| } |
| } |
| return manager; |
| } |
| |
| public void dispose() { |
| synchronized (this) { |
| this.state|= S_DISPOSED; |
| final DocProcessingManager manager= this.manager; |
| if (manager != null) { |
| manager.dispose(); |
| this.manager= null; |
| } |
| } |
| } |
| |
| } |
| |
| |
| private final Map<String, TypeEntry> entries; |
| |
| |
| public DocProcessingRegistry() { |
| |
| this.entries= loadEntries(); |
| } |
| |
| |
| private Map<String, TypeEntry> loadEntries() { |
| final Map<String, TypeEntry> entries= new HashMap<>(); |
| final IConfigurationElement[] elements= Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID); |
| for (final IConfigurationElement element : elements) { |
| if (element.getName().equals(PROCESSING_TYPE_ELEMENT_NAME)) { |
| final String contentTypeId= element.getAttribute(CONTENT_TYPE_ID_ATTR_NAME); |
| if (contentTypeId != null && !contentTypeId.isEmpty()) { |
| final TypeEntry item= new TypeEntry(contentTypeId, element); |
| entries.put(item.getContentTypeId(), item); |
| } |
| } |
| } |
| |
| return entries; |
| } |
| |
| public @Nullable DocProcessingManager getDocProcessingManager(final String contentTypeId) { |
| final TypeEntry item= this.entries.get(contentTypeId); |
| return (item != null) ? item.getManager() : null; |
| } |
| |
| @Override |
| public void dispose() { |
| for (final TypeEntry entry : this.entries.values()) { |
| entry.dispose(); |
| } |
| } |
| |
| } |