All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.javafx2.project.JFXProjectProblems Maven / Gradle / Ivy

There is a newer version: RELEASE220
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.netbeans.modules.javafx2.project;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.java.platform.JavaPlatform;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.modules.java.j2seproject.api.J2SEProjectPlatform;
import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator;
import org.netbeans.modules.javafx2.platform.api.JavaFXPlatformUtils;
import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport;
import org.netbeans.spi.project.ProjectServiceProvider;
import org.netbeans.spi.project.ui.ProjectProblemResolver;
import org.netbeans.spi.project.ui.ProjectProblemsProvider;
import org.netbeans.spi.project.ui.support.ProjectProblemsProviderSupport;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.util.Lookup;
import org.openide.util.Mutex;
import org.openide.util.MutexException;
import org.openide.util.NbBundle;
import org.openide.util.Parameters;
import org.openide.util.RequestProcessor;
import org.openide.util.RequestProcessor.Task;
import org.openide.util.TaskListener;

/**
 * Problem resolver specific to JavaFX Application project type
 *
 * @author Petr Somol, Tomas Zezula
 */
@ProjectServiceProvider(
        service = ProjectProblemsProvider.class,
        projectType = "org-netbeans-modules-java-j2seproject")
public class JFXProjectProblems implements ProjectProblemsProvider, PropertyChangeListener  {

    private static final String PLATFORM_ACTIVE = JFXProjectProperties.PLATFORM_ACTIVE;
    private final ProjectProblemsProviderSupport problemsProviderSupport = new ProjectProblemsProviderSupport(this);
    private static final Logger LOGGER = Logger.getLogger("javafx"); // NOI18N
    private static final RequestProcessor RP = new RequestProcessor(JFXProjectProblems.class);
    private AtomicReference updateClassPathExtensionTask = new AtomicReference();
    private AtomicBoolean testedCorrectClassPathExtension = new AtomicBoolean(false);
    private AtomicBoolean updatedClassPathExtension = new AtomicBoolean(false);
    private final Project prj;
    private final J2SEPropertyEvaluator eval;
    private final J2SEProjectPlatform platformSetter;
    private JFXPlatformUpdater updater;

    public JFXProjectProblems(final Lookup lkp) {
        this.updater = null;
        Parameters.notNull("lkp", lkp); //NOI18N
        this.prj = lkp.lookup(Project.class);
        Parameters.notNull("prj", prj); //NOI18N
        this.eval = lkp.lookup(J2SEPropertyEvaluator.class);
        Parameters.notNull("eval", eval);   //NOI18N
        this.platformSetter = lkp.lookup(J2SEProjectPlatform.class);
        Parameters.notNull("platformSetter", platformSetter);   //NOI18N
        eval.evaluator().addPropertyChangeListener(JFXProjectProblems.this);
        platformSetter.addPropertyChangeListener(JFXProjectProblems.this);
    }
    
    @Override
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        Parameters.notNull("listener", listener);   //NOI18N
        problemsProviderSupport.addPropertyChangeListener(listener);
    }

    @Override
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        Parameters.notNull("listener", listener);   //NOI18N
        problemsProviderSupport.removePropertyChangeListener(listener);
    }

    @Override
    @NbBundle.Messages({
        "LBL_FX_Not_Supported_By_JDK=Java Platform Does Not Support FX",
        "HINT_FX_Not_Supported_By_JDK=The active project platform is not JavaFX-enabled."
    })
    public Collection getProblems() {
        if(updater == null) {
            updater = prj.getLookup().lookup(JFXPlatformUpdater.class);
            if(updater != null) {
                updater.addListener(this);
            }
        }
        if(updater != null) {
            if(!updater.hasUpdated()) {
                return Collections.emptySet();
            }
        } else {
            return Collections.emptySet();
        }
        // initiate or evaluate classpathextension correctness test
        if((updater == null || updater.hasUpdated()) && !testedCorrectClassPathExtension.get()) {
            // if async evaluation does not run yet, launch it, otherwise cancel this problem check
            if (updateClassPathExtensionTask.get() == null || updateClassPathExtensionTask.get().isFinished()) {
                updateClassPathExtensionTask.set(RP.create(new Runnable() { // NOI18N
                    @Override
                    public void run() {
                        updatedClassPathExtension.set(false);
                        try {
                            if(!JFXProjectUtils.hasCorrectClassPathExtension(prj)) {
                                JFXProjectUtils.updateClassPathExtension(prj);
                                updatedClassPathExtension.set(true);
                            }
                            testedCorrectClassPathExtension.set(true);
                            
                        } catch (IOException ex) {
                            LOGGER.log(Level.WARNING, "Can't access project properties: {0}", ex); // NOI18N
                        }
                    }
                }));
                updateClassPathExtensionTask.get().addTaskListener(new TaskListener() {
                    @Override
                    public void taskFinished(org.openide.util.Task task) {
                        if (updatedClassPathExtension.get()) {
                            problemsProviderSupport.fireProblemsChange();
                        }
                    }
                });
                updateClassPathExtensionTask.get().schedule(0);
            }
            return Collections.emptySet();
        }
        testedCorrectClassPathExtension.set(false);

        if(!isFXProject(eval)) {
            return Collections.emptySet();
        }

        return problemsProviderSupport.getProblems(new ProjectProblemsProviderSupport.ProblemsCollector() {
            @Override
            public Collection collectProblems() {
                Collection currentProblems = ProjectManager.mutex().readAccess(
                        new Mutex.Action>() {
                            @Override
                            public Collection run() {
                                final JavaPlatform activePlatform = platformSetter.getProjectPlatform();
                                boolean hasFXProblem = activePlatform != null && !JavaFXPlatformUtils.isJavaFXEnabled(activePlatform);
                                return !hasFXProblem  ? Collections.emptySet() :
                                    Collections.singleton(ProjectProblem.createError(
                                        Bundle.LBL_FX_Not_Supported_By_JDK(),
                                        Bundle.HINT_FX_Not_Supported_By_JDK(),
                                        new JFXProjectProblems.NonFXPlatformResolver(
                                            prj,
                                            platformSetter,
                                            null,
                                            JavaPlatform.getDefault().getSpecification().getName()))) ;
                            }
                    });
                return currentProblems;
            }
        });
    }

    private static boolean isFXProject(@NonNull final J2SEPropertyEvaluator eval) {
        if (eval == null) {
            return false;
        }
        //Don't use JFXProjectProperties.isTrue to prevent JFXProjectProperties from being loaded
        //JFXProjectProperties.JAVAFX_ENABLED is inlined by compliler
        return isTrue(eval.evaluator().getProperty(JFXProjectProperties.JAVAFX_ENABLED));
    }

    private static boolean isTrue(@NullAllowed final String value) {
        return  value != null && (
           "true".equalsIgnoreCase(value) ||    //NOI18N
           "yes".equalsIgnoreCase(value) ||     //NOI18N
           "on".equalsIgnoreCase(value));       //NOI18N
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        final String propName = evt.getPropertyName();
        if (propName == null || PLATFORM_ACTIVE.equals(propName)) { // || versionProps.contains(propName)) {
            problemsProviderSupport.fireProblemsChange();
        }
    }

    private static class NonFXPlatformResolver implements ProjectProblemResolver {

        private final Project project;
        private final String type;
        private final BrokenReferencesSupport.PlatformUpdatedCallBack hook;
        private final J2SEProjectPlatform platformSetter;

        NonFXPlatformResolver(
            @NonNull final Project project,
            @NonNull final J2SEProjectPlatform platformSetter,
            @NullAllowed final BrokenReferencesSupport.PlatformUpdatedCallBack hook,
            @NonNull final String type) {
            Parameters.notNull("project", project);   //NOI18N
            Parameters.notNull("type", type);   //NOI18N
            Parameters.notNull("platformSetter", platformSetter);   //NOI18N
            this.project = project;
            this.platformSetter = platformSetter;
            this.hook = hook;
            this.type = type;
        }


        @NbBundle.Messages({"LBL_ResolveFXJDK=Choose FX-enabled Java Platform - \"{0}\" Project"})
        @Override
        public Future resolve() {
            final ChooseOtherPlatformPanel choosePlatform = new ChooseOtherPlatformPanel(type);
            final DialogDescriptor dd = new DialogDescriptor(choosePlatform, Bundle.LBL_ResolveFXJDK(ProjectUtils.getInformation(project).getDisplayName()));
            if (DialogDisplayer.getDefault().notify(dd) == DialogDescriptor.OK_OPTION) {
                final Callable resultFnc =
                        new Callable() {
                    @Override
                    public Result call() throws Exception {
                        final JavaPlatform jp = choosePlatform.getSelectedPlatform();
                        if(jp != null) {
                            try {
                                ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction() {
                                    @Override
                                    public Void run() throws IOException {
                                        platformSetter.setProjectPlatform(jp);
                                        JFXProjectUtils.updateClassPathExtension(project);
                                        return null;
                                    }
                                });
                            } catch (MutexException e) {
                                throw (IOException) e.getCause();
                            }
                            LOGGER.info("Set " + PLATFORM_ACTIVE + " to platform " + jp);
                            return ProjectProblemsProvider.Result.create(ProjectProblemsProvider.Status.RESOLVED);
                        }
                        return ProjectProblemsProvider.Result.create(ProjectProblemsProvider.Status.UNRESOLVED);
                    }
                };
                final RunnableFuture result = new FutureTask(resultFnc);
                RP.post(result);
                return result;
            }
            return new JFXProjectProblems.Done(
                    Result.create(ProjectProblemsProvider.Status.UNRESOLVED));
        }

        @Override
        public boolean equals(Object other) {
            if (!(other instanceof JFXProjectProblems.NonFXPlatformResolver)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            return 29;

        }
        
    }

    private static final class Done implements Future {

        private final ProjectProblemsProvider.Result result;

        Done(@NonNull final ProjectProblemsProvider.Result result) {
            Parameters.notNull("result", result);   //NOI18N
            this.result = result;
        }

        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            return false;
        }

        @Override
        public boolean isCancelled() {
            return false;
        }

        @Override
        public boolean isDone() {
            return true;
        }

        @Override
        public ProjectProblemsProvider.Result get() throws InterruptedException, ExecutionException {
            return result;
        }

        @Override
        public ProjectProblemsProvider.Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            return get();
        }

    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy