org.vaadin.netbeans.impl.WebVaadinSupportImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.vaadin.netbeans.impl.WebVaadinSupportImpl.java

Source

/*
 * Copyright 2000-2013 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.vaadin.netbeans.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.logging.Level;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.TypeElement;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.project.MavenProject;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.source.ClassIndex;
import org.netbeans.api.java.source.ClassIndexListener;
import org.netbeans.api.java.source.ClasspathInfo;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.ElementHandle;
import org.netbeans.api.java.source.RootsEvent;
import org.netbeans.api.java.source.TypesEvent;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.modules.maven.api.NbMavenProject;
import org.netbeans.spi.project.ProjectServiceProvider;
import org.netbeans.spi.project.ui.ProjectOpenedHook;
import org.openide.filesystems.FileObject;
import org.openide.util.Utilities;
import org.vaadin.netbeans.VaadinSupport;
import org.vaadin.netbeans.model.ModelOperation;
import org.vaadin.netbeans.model.VaadinModel;
import org.vaadin.netbeans.utils.JavaUtils;

/**
 * @author denis
 */
@ProjectServiceProvider(service = { VaadinSupport.class,
        ProjectOpenedHook.class }, projectType = "org-netbeans-modules-maven")
public class WebVaadinSupportImpl extends VaadinSupportImpl {

    public WebVaadinSupportImpl(Project project) {
        super(project);
        myRootsListener = new ClassIndexListenerImpl();
    }

    @Override
    public Project getWidgetsetProject() {
        if (isWeb()) {
            if (hasGwtModel(getProject(), this)) {
                return getProject();
            }
            for (File file : getRuntimeDependecies(getProject())) {
                Project dependency = FileOwnerQuery.getOwner(Utilities.toURI(file));
                if (dependency != null) {
                    VaadinSupport support = dependency.getLookup().lookup(VaadinSupport.class);
                    if (support != null && support.isEnabled() && !support.isWeb()
                            && hasClientCompilerDependency(dependency) && hasGwtModel(dependency, support)) {
                        return dependency;
                    }
                }
            }
            return getProject();
        } else {
            return super.getWidgetsetProject();
        }
    }

    @Override
    protected void updateModel(CompilationController controller, TypeElement element) {
        if (isWeb()) {
            ElementHandle<TypeElement> handle = ElementHandle.create(element);
            AnnotationMirror annotation = JavaUtils.getAnnotation(element, JavaUtils.VAADIN_SERVLET_CONFIGURATION);
            if (annotation != null) {
                String widgetset = JavaUtils.getValue(annotation, JavaUtils.WIDGETSET);
                if (widgetset != null) {
                    ServletConfigurationImpl impl = new ServletConfigurationImpl();
                    impl.setWidgetset(widgetset);
                    getModel().add(handle, impl);
                }
            }
            annotation = JavaUtils.getAnnotation(element, JavaUtils.SERVLET_ANNOTATION);
            if (annotation != null) {
                String widgetset = JavaUtils.getWidgetsetWebInit(annotation);
                if (widgetset != null) {
                    ServletConfigurationImpl impl = new ServletConfigurationImpl();
                    impl.setWidgetset(widgetset);
                    getModel().add(handle, impl);
                }
            }
        }
    }

    @Override
    protected void remove(CompilationController controller, ElementHandle<TypeElement> handle) {
        if (isWeb()) {
            getModel().remove(handle);
        }
    }

    @Override
    protected void initClassModel(CompilationController controller) throws InterruptedException {
        if (isWeb()) {
            List<TypeElement> elements = JavaUtils.findAnnotatedElements(JavaUtils.VAADIN_SERVLET_CONFIGURATION,
                    controller);
            for (TypeElement element : elements) {
                updateModel(controller, element);
            }
            elements = JavaUtils.findAnnotatedElements(JavaUtils.SERVLET_ANNOTATION, controller);
            for (TypeElement element : elements) {
                updateModel(controller, element);
            }
        }
    }

    @Override
    protected void removeFileSystemListener() {
        Set<Project> allProjects = new HashSet<>();
        removeListener(getProject(), allProjects);
        myRootsListener.clean();
    }

    @Override
    protected void initializeFileSystemListener() {
        Set<Project> allProjects = new HashSet<>();
        addListener(getProject(), allProjects);

        synchronized (myRootsListener) {
            for (Project project : allProjects) {
                if (project.equals(getProject())) {
                    continue;
                }
                ClasspathInfo info = ClasspathInfo.create(getClassPath(project, ClassPath.BOOT),
                        getClassPath(project, ClassPath.COMPILE), getClassPath(project, ClassPath.SOURCE));
                myRootsListener.listenIndex(project, info.getClassIndex());
            }
        }
    }

    private void removeListener(Project project, Set<Project> projects) {
        if (projects.contains(project)) {
            return;
        }
        projects.add(project);
        doRemoveListener(project);
        for (File file : getRuntimeDependecies(project)) {
            Project dependency = FileOwnerQuery.getOwner(Utilities.toURI(file));
            if (dependency != null) {
                removeListener(dependency, projects);
            }
        }
    }

    private void addListener(Project project, Set<Project> projects) {
        if (projects.contains(project)) {
            return;
        }
        projects.add(project);
        doAddListener(project);
        for (File file : getRuntimeDependecies(project)) {
            Project dependency = FileOwnerQuery.getOwner(Utilities.toURI(file));
            if (dependency != null) {
                addListener(dependency, projects);
            }
        }
    }

    private boolean hasGwtModel(final Project project, VaadinSupport support) {
        final boolean[] result = new boolean[1];
        try {
            support.runModelOperation(new ModelOperation() {

                @Override
                public void run(VaadinModel model) {
                    FileObject gwtXml = model.getGwtXml();
                    if (gwtXml == null) {
                        return;
                    }
                    result[0] = project.equals(FileOwnerQuery.getOwner(gwtXml));
                }
            });
        } catch (IOException e) {
            LOG.log(Level.INFO, null, e);
        }
        return result[0];
    }

    private static Set<Artifact> getDependencies(Project project) {
        NbMavenProject nbMvnProject = project.getLookup().lookup(NbMavenProject.class);
        MavenProject mavenProject = nbMvnProject.getMavenProject();
        return mavenProject.getArtifacts();
    }

    static List<File> getRuntimeDependecies(Project project) {
        Set<Artifact> artifacts = getDependencies(project);
        List<File> result = new ArrayList<>(artifacts.size());
        for (Artifact artifact : artifacts) {
            if (Artifact.SCOPE_COMPILE.equals(artifact.getScope())
                    || Artifact.SCOPE_RUNTIME.equals(artifact.getScope())) {
                result.add(artifact.getFile());
            }
        }
        return result;
    }

    private final class ClassIndexListenerImpl implements ClassIndexListener, ChangeListener {

        ClassIndexListenerImpl() {
            myIndeces = new WeakHashMap<>();
        }

        @Override
        public void rootsAdded(RootsEvent event) {
            initializeClassIndex(sourceRootsAffected(event));
        }

        @Override
        public void rootsRemoved(RootsEvent event) {
            initializeClassIndex(sourceRootsAffected(event));
        }

        @Override
        public void typesAdded(TypesEvent event) {
        }

        @Override
        public void typesChanged(TypesEvent event) {
        }

        @Override
        public void typesRemoved(TypesEvent event) {
        }

        @Override
        public void stateChanged(ChangeEvent e) {
            initializeClassIndex(true);
        }

        void listenIndex(Project project, ClassIndex index) {
            synchronized (this) {
                myIndeces.put(project, index);
            }
            index.addClassIndexListener(this);
            ProjectUtils.getSources(project).addChangeListener(this);
        }

        synchronized void clean() {
            for (Entry<Project, ClassIndex> entry : myIndeces.entrySet()) {
                Project project = entry.getKey();
                ClassIndex index = entry.getValue();
                index.removeClassIndexListener(this);
                ProjectUtils.getSources(project).removeChangeListener(this);
            }
            myIndeces.clear();
        }

        private final Map<Project, ClassIndex> myIndeces;

    }

    private final ClassIndexListenerImpl myRootsListener;

}