org.eclipse.xtext.builder.impl.RegistryBuilderParticipant.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.xtext.builder.impl.RegistryBuilderParticipant.java

Source

/*******************************************************************************
 * Copyright (c) 2010 itemis AG (http://www.itemis.eu) 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
 *******************************************************************************/
package org.eclipse.xtext.builder.impl;

import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.ecore.plugin.RegistryReader;
import org.eclipse.xtext.builder.IXtextBuilderParticipant;
import org.eclipse.xtext.builder.internal.Activator;
import org.eclipse.xtext.resource.IResourceDescription.Delta;

import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Singleton;

/**
 * @author Sebastian Zarnekow - Initial contribution and API
 * @author Jan Koehnlein
 */
@Singleton
public class RegistryBuilderParticipant implements IXtextBuilderParticipant {

    private static final String PARTICIPANT = "participant"; //$NON-NLS-1$

    private static final String EXTENSION_POINT_ID = PARTICIPANT;

    private static final String ATT_CLASS = "class"; //$NON-NLS-1$

    private static final String ATT_FILE_EXTENSIONS = "fileExtensions"; //$NON-NLS-1$

    private static final Splitter FILE_EXTENSION_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();

    private static final Logger readerLog = Logger.getLogger(BuilderParticipantReader.class);

    @Inject
    private IExtensionRegistry extensionRegistry;

    private volatile ImmutableList<IXtextBuilderParticipant> participants;

    private Map<String, IXtextBuilderParticipant> classToParticipant;

    @Override
    public void build(IBuildContext buildContext, IProgressMonitor monitor) throws CoreException {
        ImmutableList<IXtextBuilderParticipant> participants = getParticipants();
        if (participants.isEmpty())
            return;
        SubMonitor progress = SubMonitor.convert(monitor, participants.size());
        progress.subTask(Messages.RegistryBuilderParticipant_InvokingBuildParticipants);
        for (IXtextBuilderParticipant participant : participants) {
            if (progress.isCanceled())
                throw new OperationCanceledException();
            participant.build(buildContext, progress.newChild(1));
        }
    }

    public ImmutableList<IXtextBuilderParticipant> getParticipants() {
        ImmutableList<IXtextBuilderParticipant> result = participants;
        if (participants == null) {
            result = initParticipants();
        }
        return result;
    }

    protected synchronized ImmutableList<IXtextBuilderParticipant> initParticipants() {
        ImmutableList<IXtextBuilderParticipant> result = participants;
        if (result == null) {
            if (classToParticipant == null) {
                classToParticipant = Maps.newHashMap();
                Activator activator = Activator.getDefault();
                if (activator != null) {
                    String pluginID = activator.getBundle().getSymbolicName();
                    String extensionPointID = EXTENSION_POINT_ID;
                    BuilderParticipantReader reader = new BuilderParticipantReader(extensionRegistry, pluginID,
                            extensionPointID);
                    reader.readRegistry();
                }
            }
            result = ImmutableList.copyOf(classToParticipant.values());
            participants = result;
        }
        return result;
    }

    public class BuilderParticipantReader extends RegistryReader {

        public BuilderParticipantReader(IExtensionRegistry pluginRegistry, String pluginID,
                String extensionPointID) {
            super(pluginRegistry, pluginID, extensionPointID);
        }

        @Override
        protected boolean readElement(IConfigurationElement element, boolean add) {
            if (element.getName().equals(PARTICIPANT)) {
                String className = element.getAttribute(ATT_CLASS);
                if (className == null) {
                    logMissingAttribute(element, ATT_CLASS);
                } else if (add) {
                    IXtextBuilderParticipant participant = new DeferredBuilderParticipant(element);
                    if (classToParticipant.containsKey(className)) {
                        readerLog.warn("The builder participant '" + className + "' was registered twice."); //$NON-NLS-1$ //$NON-NLS-2$
                    }
                    classToParticipant.put(className, participant);
                    participants = null;
                    return true;
                } else {
                    classToParticipant.remove(className);
                    participants = null;
                    return true;
                }
            }
            return false;
        }

        @Override
        protected void logError(IConfigurationElement element, String text) {
            doLogError(element, text);
        }
    }

    private static void doLogError(IConfigurationElement element, String text) {
        IExtension extension = element.getDeclaringExtension();
        readerLog.error("Plugin " + extension.getContributor().getName() + ", extension " //$NON-NLS-1$//$NON-NLS-2$
                + extension.getExtensionPointUniqueIdentifier());
        readerLog.error(text);
    }

    private static class NoOpBuilderParticipant implements IXtextBuilderParticipant {
        @Override
        public void build(IBuildContext context, IProgressMonitor monitor) throws CoreException {
        }
    }

    public static class DeferredBuilderParticipant implements IXtextBuilderParticipant {
        private final IConfigurationElement element;
        private final ImmutableList<String> handledFileExtensions;

        private IXtextBuilderParticipant delegate;

        public DeferredBuilderParticipant(IConfigurationElement element) {
            this.element = element;
            String fileExtensionsAtt = Strings.nullToEmpty(element.getAttribute(ATT_FILE_EXTENSIONS));
            this.handledFileExtensions = ImmutableList.copyOf(FILE_EXTENSION_SPLITTER.split(fileExtensionsAtt));
        }

        @Override
        public void build(IBuildContext context, IProgressMonitor monitor) throws CoreException {
            getDelegate(context).build(context, monitor);
        }

        private IXtextBuilderParticipant getDelegate(IBuildContext context) {
            if (!interestedIn(context)) {
                return new NoOpBuilderParticipant();
            }
            return getDelegate();
        }

        public IXtextBuilderParticipant getDelegate() {
            if (delegate == null) {
                initDelegate();
            }
            return delegate;
        }

        private synchronized void initDelegate() {
            if (delegate != null)
                return;
            try {
                Object participant = element.createExecutableExtension(ATT_CLASS);
                if (participant instanceof IXtextBuilderParticipant) {
                    delegate = (IXtextBuilderParticipant) participant;
                } else {
                    doLogError(element, element.getAttribute(ATT_CLASS)
                            + " did not yield an instance of IXtextBuilderParticipant but " + //$NON-NLS-1$
                            participant.getClass().getName());
                }
            } catch (CoreException e) {
                doLogError(element, e.getMessage());
            } catch (NoClassDefFoundError e) {
                doLogError(element, e.getMessage());
            }
            if (delegate == null) {
                delegate = new NoOpBuilderParticipant();
            }
        }

        private boolean interestedIn(IBuildContext context) {
            List<String> extensions = getHandledFileExtensions();
            if (extensions.isEmpty()) {
                return true;
            }
            for (Delta change : context.getDeltas()) {
                String fileExtension = change.getUri().fileExtension();
                if (extensions.contains(fileExtension)) {
                    return true;
                }
            }
            return false;
        }

        /**
         * Ask the participant whether it is interesting in the given file extension.
         * Does not initialize the delegate or the injector of the contributing language.
         */
        public boolean isParticipating(String fileExtension) {
            List<String> extensions = getHandledFileExtensions();
            return extensions.isEmpty() || extensions.contains(fileExtension);
        }

        private List<String> getHandledFileExtensions() {
            return handledFileExtensions;
        }

    }

}