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

org.netbeans.modules.maven.grammar.EffectivePomMD Maven / Gradle / Ivy

/*
 * 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.maven.grammar;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Image;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.text.BadLocationException;
import javax.swing.text.EditorKit;
import javax.swing.text.Position;
import org.apache.maven.DefaultMaven;
import org.apache.maven.Maven;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.model.Model;
import org.apache.maven.model.building.ModelBuildingException;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.model.building.ModelBuildingResult;
import org.apache.maven.model.building.ModelProblem;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.project.ProjectBuildingResult;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.editor.mimelookup.MimeLookup;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.core.spi.multiview.CloseOperationState;
import org.netbeans.core.spi.multiview.MultiViewDescription;
import org.netbeans.core.spi.multiview.MultiViewElement;
import org.netbeans.core.spi.multiview.MultiViewElementCallback;
import org.netbeans.modules.editor.NbEditorDocument;
import org.netbeans.modules.maven.api.Constants;
import org.netbeans.modules.maven.api.NbMavenProject;
import org.netbeans.modules.maven.embedder.EmbedderFactory;
import org.netbeans.modules.maven.embedder.MavenEmbedder;
import static org.netbeans.modules.maven.grammar.Bundle.*;
import org.netbeans.modules.maven.grammar.effpom.AnnotationBarManager;
import org.netbeans.modules.maven.grammar.effpom.LocationAwareMavenXpp3Writer;
import org.netbeans.modules.maven.grammar.effpom.LocationAwareMavenXpp3Writer.Location;
import org.netbeans.modules.maven.indexer.api.RepositoryPreferences;
import org.openide.awt.UndoRedo;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.text.Annotation;
import org.openide.util.Exceptions;
import org.openide.util.HelpCtx;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.openide.util.RequestProcessor;
import org.openide.util.WeakListeners;
import org.openide.windows.TopComponent;

public class EffectivePomMD implements MultiViewDescription, Serializable {
    private static final Logger LOG = Logger.getLogger(EffectivePomMD.class.getName());

    private static final RequestProcessor RP = new RequestProcessor(EffectivePomMD.class);

    private final Lookup lookup;

    private EffectivePomMD(Lookup lookup) {
        this.lookup = lookup;
    }

    @Override public int getPersistenceType() {
        return TopComponent.PERSISTENCE_NEVER;
    }

    @Messages("TAB_EFF_Pom=Effective POM")
    @Override public String getDisplayName() {
        return TAB_EFF_Pom();
    }

    @Override public Image getIcon() {
        return ImageUtilities.loadImage(POMDataObject.POM_ICON, true);
    }

    @Override public HelpCtx getHelpCtx() {
        return HelpCtx.DEFAULT_HELP;
    }

    @Override public String preferredID() {
        return "effpom"; // XXX could be ArtifactViewer.HINT_* constant
    }

    @Override public MultiViewElement createElement() {
        return new EffPOMView(lookup);
    }

//    @ServiceProvider(service=ArtifactViewerPanelProvider.class, position=600)
//    public static class Factory implements ArtifactViewerPanelProvider {
//
//        @Override public MultiViewDescription createPanel(Lookup lookup) {
//            return new EffectivePomMD(lookup);
//        }
//    }
    
    @MultiViewElement.Registration(
        displayName="#TAB_Effective",
        iconBase=POMDataObject.POM_ICON,
        persistenceType=TopComponent.PERSISTENCE_NEVER,
        preferredID="effectivePom",
        mimeType=Constants.POM_MIME_TYPE,
        position=101
    )
    @Messages("TAB_Effective=Effective")
    public static MultiViewElement forPOMEditor(final Lookup editor) {
        return new EffPOMView(editor);
    }    

    private static class EffPOMView implements MultiViewElement, Runnable, PropertyChangeListener {
        private static final String EFF_MIME_TYPE = "text/x-maven-pom+xml";

        private final Lookup lookup;
        private final RequestProcessor.Task task = RP.create(this);
        private JToolBar toolbar;
        private JPanel panel;
        boolean firstTimeShown = true;
        private final Lookup mime;

        EffPOMView(Lookup lookup) {
            this.lookup = lookup;
            mime = MimeLookup.getLookup(EFF_MIME_TYPE);
        }
        
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (NbMavenProject.PROP_PROJECT.equals(evt.getPropertyName())) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        if (panel != null && panel.isVisible()) {
                            panel.add(new JLabel(LBL_loading_Eff(), SwingConstants.CENTER), BorderLayout.CENTER);

                            task.schedule(0);
                        } else {
                            firstTimeShown = true;
                        }
                    }
                });
            }
        }
        

        @Override public JComponent getVisualRepresentation() {
            if (panel == null) {
                panel = new JPanel(new BorderLayout());
                if( "Aqua".equals(UIManager.getLookAndFeel().getID()) ) { //NOI18N
                    panel.setBackground(UIManager.getColor("NbExplorerView.background")); //NOI18N
                }                
            }
            return panel;
        }

        @Override public JComponent getToolbarRepresentation() {
            if (toolbar == null) {
                toolbar = new JToolBar();
                toolbar.setFloatable(false);
                if( "Aqua".equals(UIManager.getLookAndFeel().getID()) ) { //NOI18N
                    toolbar.setBackground(UIManager.getColor("NbExplorerView.background")); //NOI18N
                }
                effDiffAction = new ShowEffPomDiffAction(lookup);
                effDiffAction.setEnabled(false);
                toolbar.add(effDiffAction);
                //TODO
            }
            return toolbar;
        }
        private ShowEffPomDiffAction effDiffAction;

        @Override public void setMultiViewCallback(MultiViewElementCallback callback) {}

        @Override public CloseOperationState canCloseElement() {
            return CloseOperationState.STATE_OK;
        }

        @Override public Action[] getActions() {
            return new Action[0];
        }

        @Override public Lookup getLookup() {
            return lookup;
        }

        @Override public void componentOpened() {}

        @Override public void componentClosed() {}

        private @NullAllowed JEditorPane pane;
        
        private int caretPosition;
        
        @Messages("LBL_loading_Eff=Loading Effective POM...")
        @Override public void componentShowing() {
            if (firstTimeShown) {
                firstTimeShown = false;
                getVisualRepresentation().add(new JLabel(LBL_loading_Eff(), SwingConstants.CENTER), BorderLayout.CENTER);
                task.schedule(0);
            } else {
                EventQueue.invokeLater(new Runnable() {
                    @Override public void run() {
                        if (pane != null) {
                            pane.requestFocus();
                            pane.setCaretPosition(caretPosition);
                        }
                    }
                });
            }
        }

        @Override public void componentHidden() {}

        @Override public void componentActivated() {}

        @Override public void componentDeactivated() {
            if (pane != null) {
                caretPosition = pane.getCaretPosition();
            }
        }

        @Override public UndoRedo getUndoRedo() {
            return UndoRedo.NONE;
        }

        @Messages({
            "ERR_No_Project_Loaded=No project associated with the project or loading failed. See Source tab for errors", 
            "ERR_Unloadable=POM's project currently unloadable.",
            "ERR_In_Jar=Cannot show effective POM for jar file content."
        })
        @Override public void run() {
            EventQueue.invokeLater(new Runnable() {
                @Override public void run() {
                    effDiffAction.setEnabled(false);
                }
            });
            try {
                FileObject pom = lookup.lookup(FileObject.class);
                Model model = null;
                String errorMessage = null;
                if (pom != null) {
                    Project p = null;
                    
                    try {
                        p = ProjectManager.getDefault().findProject(pom.getParent());
                    } catch (IOException ex) {
                        LOG.log(Level.FINE, ex.getMessage(), ex);
                    } catch (IllegalArgumentException ex) {
                        LOG.log(Level.FINE, ex.getMessage(), ex);
                    }
                    if (p != null) {
                        NbMavenProject nbmp = p.getLookup().lookup(NbMavenProject.class);
                        if (nbmp != null) {
                            model = nbmp.getMavenProject().getModel();
                            if (model == null || nbmp.isUnloadable()) {
                                errorMessage = ERR_Unloadable();
                            }
                            nbmp.addPropertyChangeListener(WeakListeners.propertyChange(this, nbmp));
                        } else {
                            LOG.log(Level.WARNING, "not a Maven project: {0}", p);
                            ModelBuildingResult res = EmbedderFactory.getProjectEmbedder().executeModelBuilder(FileUtil.toFile(pom));
                            model = res.getEffectiveModel();
                        }
                    } else {
                        LOG.log(Level.WARNING, "not a project: {0}", p);
                        File fl = FileUtil.toFile(pom);
                        if (fl != null) {
                            ModelBuildingResult res = EmbedderFactory.getProjectEmbedder().executeModelBuilder(fl);
                            model = res.getEffectiveModel();
                        } else {
                            errorMessage = ERR_In_Jar();
                        }
                    }
                } else {
                    LOG.log(Level.WARNING, "no file in lookup");
                    errorMessage = "No file in editor lookup";
                }                
                
                
                if (errorMessage != null) {
                    final String message = errorMessage;
                    EventQueue.invokeLater(new Runnable() {
                        @Override public void run() {
                            JComponent pnl = getVisualRepresentation();
                            pnl.removeAll();
                            pnl.add(new JLabel(message, SwingConstants.CENTER), BorderLayout.CENTER);
                            pnl.revalidate();
                        }
                    });
                    return;
                }
                assert model != null;
                assert pom != null;
                LocationAwareMavenXpp3Writer writer = new LocationAwareMavenXpp3Writer();
                final StringWriter sw = new StringWriter();
                final List loc = writer.write(sw, model);
                List problems = new ArrayList();
                final Map prblmMap = new HashMap();
                if (pom != null) {
                    File file = FileUtil.toFile(pom);
                    problems.addAll(runMavenValidationImpl(file));
                    for (Location lo : loc) {
                        Iterator it2 = problems.iterator();
                        while (it2.hasNext()) {
                            ModelProblem modelProblem = it2.next();
                            if (modelProblem.getLineNumber() == lo.loc.getLineNumber() && modelProblem.getModelId().equals(lo.loc.getSource().getModelId())) {
                                prblmMap.put(modelProblem, lo);
                                it2.remove();
                            }
                        }
                    }
                }
                EventQueue.invokeLater(new Runnable() {
                    @Override public void run() {
                        EditorKit kit = mime.lookup(EditorKit.class);
                        NbEditorDocument doc = (NbEditorDocument) kit.createDefaultDocument();
                        pane = new JEditorPane(EFF_MIME_TYPE, null);
                        pane.setDocument(doc);
                        JComponent pnl = getVisualRepresentation(); 
                        pnl.removeAll();
                        pnl.add(doc.createEditor(pane), BorderLayout.CENTER);
                        pane.setEditable(false);

                        try {
                            doc.insertString(0, sw.toString(), null);
                        } catch (BadLocationException ex) {
                            Exceptions.printStackTrace(ex);
                        }
                        pane.requestFocus();
                        pane.setCaretPosition(0);

                        for (final Map.Entry ent : prblmMap.entrySet()) {
                            doc.addAnnotation(new Position() {

                                @Override
                                public int getOffset() {
                                    return ent.getValue().startOffset;
                                }
                            }, 1, new Annotation() {

                                @Override
                                public String getAnnotationType() {
                                    if (ent.getKey().getSeverity() == ModelProblem.Severity.ERROR || ent.getKey().getSeverity() == ModelProblem.Severity.FATAL) {
                                        return "org-netbeans-spi-editor-hints-parser_annotation_err";
                                    } else {
                                        return "org-netbeans-spi-editor-hints-parser_annotation_warn";
                                    }
                                }

                                @Override
                                public String getShortDescription() {
                                    return ent.getKey().getMessage();
                                }
                            });
                        }
                        pnl.revalidate();
                        AnnotationBarManager.showAnnotationBar(pane, loc);
                    }
                });
            } catch (final Exception x) {
                EventQueue.invokeLater(new Runnable() {
                    @Override public void run() {
                        JComponent pnl = getVisualRepresentation();
                        pnl.removeAll();
                        pnl.add(new JLabel(LBL_failed_to_load(x.getLocalizedMessage()), SwingConstants.CENTER), BorderLayout.CENTER);
                        pnl.revalidate();
                        LOG.log(Level.FINE, "Exception thrown while loading effective POM", x);
                        Exceptions.printStackTrace(x);
                        firstTimeShown = true;
                    }
                });
            } finally {
                EventQueue.invokeLater(new Runnable() {
                @Override public void run() {
                    effDiffAction.calculateEnabledState();
                }
            });
            }
        }

    }
    
    //copied from maven.hints Status Provider..
    //eventually should have the model problems coming from either the Mavenproject or the modelBuilder result.
    static List runMavenValidationImpl(final File pom) {
        //TODO profiles based on current configuration??
        MavenEmbedder embedder = EmbedderFactory.getProjectEmbedder();
        MavenExecutionRequest meReq = embedder.createMavenExecutionRequest();
        ProjectBuildingRequest req = meReq.getProjectBuildingRequest();
        req.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1); // currently enables just  warning
        req.setLocalRepository(embedder.getLocalRepository());
        List remoteRepos = RepositoryPreferences.getInstance().remoteRepositories(embedder);
        req.setRemoteRepositories(remoteRepos);
        req.setRepositorySession(((DefaultMaven) embedder.lookupComponent(Maven.class)).newRepositorySession(meReq));
        List problems;
        try {
            problems = embedder.lookupComponent(ProjectBuilder.class).build(pom, req).getProblems();
        } catch (ProjectBuildingException x) {
            problems = new ArrayList();
            List results = x.getResults();
            if (results != null) { //one code point throwing ProjectBuildingException contains results,
                for (ProjectBuildingResult result : results) {
                    problems.addAll(result.getProblems());
                }
            } else {
                // another code point throwing ProjectBuildingException doesn't contain results..
                Throwable cause = x.getCause();
                if (cause instanceof ModelBuildingException) {
                    problems.addAll(((ModelBuildingException) cause).getProblems());
                }
            }
        }
        return problems;
    }    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy