/projects/netbeans-7.3/maven/src/org/netbeans/modules/maven/classpath/MavenSourcesImpl.java
Java | 655 lines | 508 code | 60 blank | 87 comment | 135 complexity | f353817697c92a6138a5c1574fd34a8e MD5 | raw file
- /*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
- *
- * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
- * Other names may be trademarks of their respective owners.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common
- * Development and Distribution License("CDDL") (collectively, the
- * "License"). You may not use this file except in compliance with the
- * License. You can obtain a copy of the License at
- * http://www.netbeans.org/cddl-gplv2.html
- * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
- * specific language governing permissions and limitations under the
- * License. When distributing the software, include this License Header
- * Notice in each file and include the License file at
- * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the GPL Version 2 section of the License file that
- * accompanied this code. If applicable, add the following below the
- * License Header, with the fields enclosed by brackets [] replaced by
- * your own identifying information:
- * "Portions Copyrighted [year] [name of copyright owner]"
- *
- * If you wish your version of this file to be governed by only the CDDL
- * or only the GPL Version 2, indicate your decision by adding
- * "[Contributor] elects to include this software in this distribution
- * under the [CDDL or GPL Version 2] license." If you do not indicate a
- * single choice of license, a recipient has the option to distribute
- * your version of this file under either the CDDL, the GPL Version 2 or
- * to extend the choice of license to its licensees as provided above.
- * However, if you add GPL Version 2 code and therefore, elected the GPL
- * Version 2 license, then the option applies only if the new code is
- * made subject to such option by the copyright holder.
- *
- * Contributor(s):
- *
- * Portions Copyrighted 2008 Sun Microsystems, Inc.
- */
- package org.netbeans.modules.maven.classpath;
- import java.awt.Image;
- import org.netbeans.modules.maven.api.FileUtilities;
- import java.beans.PropertyChangeEvent;
- import java.beans.PropertyChangeListener;
- import java.beans.PropertyChangeSupport;
- import java.io.File;
- import java.io.IOException;
- import java.net.URI;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.TreeMap;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import javax.swing.Icon;
- import javax.swing.event.ChangeListener;
- import org.apache.maven.model.Resource;
- import org.apache.maven.project.MavenProject;
- import org.netbeans.api.annotations.common.NullAllowed;
- import org.netbeans.modules.maven.api.NbMavenProject;
- import org.netbeans.api.java.project.JavaProjectConstants;
- import org.netbeans.api.project.FileOwnerQuery;
- import org.netbeans.api.project.Project;
- import org.netbeans.api.project.ProjectManager;
- import org.netbeans.api.project.ProjectUtils;
- import org.netbeans.api.project.SourceGroup;
- import org.netbeans.api.project.Sources;
- import org.netbeans.api.queries.SharabilityQuery;
- import org.netbeans.modules.maven.NbMavenProjectImpl;
- import org.netbeans.modules.maven.spi.nodes.NodeUtils;
- import org.netbeans.spi.project.SourceGroupModifierImplementation;
- import org.netbeans.spi.project.support.GenericSources;
- import org.openide.filesystems.FileObject;
- import org.openide.filesystems.FileUtil;
- import org.openide.util.ChangeSupport;
- import org.openide.util.Exceptions;
- import org.openide.util.ImageUtilities;
- import static org.netbeans.modules.maven.classpath.Bundle.*;
- import org.netbeans.spi.project.ProjectServiceProvider;
- import org.openide.util.NbBundle.Messages;
- import org.openide.util.Utilities;
- /**
- * Implementation of Sources interface for maven projects.
- * generic and java are necessary for proper workings of the project, the rest is custom thing..
- * IMHO at least..
- * @author Milos Kleint
- */
- @ProjectServiceProvider(service={Sources.class, SourceGroupModifierImplementation.class}, projectType="org-netbeans-modules-maven")
- public class MavenSourcesImpl implements Sources, SourceGroupModifierImplementation {
- public static final String TYPE_OTHER = "Resources"; //NOI18N
- public static final String TYPE_TEST_OTHER = "TestResources"; //NOI18N
- public static final String TYPE_GEN_SOURCES = "GeneratedSources"; //NOI18N
- public static final String NAME_PROJECTROOT = "ProjectRoot"; //NOI18N
- public static final String NAME_XDOCS = "XDocs"; //NOI18N
- public static final String NAME_SOURCE = "1SourceRoot"; //NOI18N
- public static final String NAME_TESTSOURCE = "2TestSourceRoot"; //NOI18N
- public static final String NAME_GENERATED_SOURCE = "6GeneratedSourceRoot"; //NOI18N
- public static final String NAME_GENERATED_TEST_SOURCE = "7GeneratedSourceRoot"; //NOI18N
-
- private final Project proj;
- private final ChangeSupport cs = new ChangeSupport(this);
- private final PropertyChangeListener pcl = new PropertyChangeListener() {
- public @Override void propertyChange(PropertyChangeEvent event) {
- checkChanges(true, true);
- }
- };
-
- private Map<String, SourceGroup> javaGroup;
- private Map<File, SourceGroup> genSrcGroup;
- private Map<File, OtherGroup> otherMainGroups;
- private Map<File, OtherGroup> otherTestGroups;
-
- private final Object lock = new Object();
-
- public MavenSourcesImpl(Project proj) {
- this.proj = proj;
- javaGroup = new TreeMap<String, SourceGroup>();
- genSrcGroup = new TreeMap<File, SourceGroup>();
- otherMainGroups = new TreeMap<File, OtherGroup>();
- otherTestGroups = new TreeMap<File, OtherGroup>();
- }
-
- private NbMavenProjectImpl project() {
- return proj.getLookup().lookup(NbMavenProjectImpl.class);
- }
- @Messages({
- "SG_Sources=Source Packages",
- "SG_Test_Sources=Test Packages"
- })
- private void checkChanges(boolean fireChanges, boolean checkAlsoNonJavaStuff) {
- boolean changed = false;
- synchronized (lock) {
- NbMavenProjectImpl project = project();
- MavenProject mp = project.getOriginalMavenProject();
- NbMavenProject watcher = project.getProjectWatcher();
- File folder = FileUtilities.convertStringToFile(mp.getBuild().getSourceDirectory());
- //QualitasCorpus.class: Created due to compilation errors
- //changed = changed | checkSourceGroupCache(folder, NAME_SOURCE, SG_Sources(), javaGroup, watcher);
- folder = FileUtilities.convertStringToFile(mp.getBuild().getTestSourceDirectory());
- //QualitasCorpus.class: Created due to compilation errors
- //changed = changed | checkSourceGroupCache(folder, NAME_TESTSOURCE, SG_Test_Sources(), javaGroup, watcher);
- changed = changed | checkGeneratedGroupsCache();
- if (checkAlsoNonJavaStuff) {
- changed = changed | checkOtherGroupsCache(project.getOtherRoots(false), false);
- changed = changed | checkOtherGroupsCache(project.getOtherRoots(true), true);
- }
- }
- if (changed) {
- if (fireChanges) {
- cs.fireChange();
- }
- }
- }
- public @Override void addChangeListener(ChangeListener changeListener) {
- if (!cs.hasListeners()) {
- NbMavenProject.addPropertyChangeListener(project(), pcl);
- }
- cs.addChangeListener(changeListener);
- }
-
- public @Override void removeChangeListener(ChangeListener changeListener) {
- cs.removeChangeListener(changeListener);
- if (!cs.hasListeners()) {
- NbMavenProject.removePropertyChangeListener(project(), pcl);
- }
- }
-
- public @Override SourceGroup[] getSourceGroups(String str) {
- if (Sources.TYPE_GENERIC.equals(str)) {
- return new SourceGroup[] { GenericSources.group(proj, proj.getProjectDirectory(), NAME_PROJECTROOT,
- ProjectUtils.getInformation(proj).getDisplayName(), null, null) };
- }
- if (JavaProjectConstants.SOURCES_TYPE_JAVA.equals(str)) {
- List<SourceGroup> toReturn = new ArrayList<SourceGroup>();
- synchronized (lock) {
- // don't fire event at all..
- checkChanges(false, false);
- toReturn.addAll(javaGroup.values());
- }
- SourceGroup[] grp = new SourceGroup[toReturn.size()];
- grp = toReturn.toArray(grp);
- return grp;
- }
- if (TYPE_GEN_SOURCES.equals(str)) {
- List<SourceGroup> toReturn = new ArrayList<SourceGroup>();
- synchronized (lock) {
- checkGeneratedGroupsCache();
- toReturn.addAll(genSrcGroup.values());
- }
- SourceGroup[] grp = new SourceGroup[toReturn.size()];
- grp = toReturn.toArray(grp);
- return grp;
- }
- if (TYPE_OTHER.equals(str) || TYPE_TEST_OTHER.equals(str)) {
- // TODO not all these are probably resources.. maybe need to split in 2 groups..
- boolean test = TYPE_TEST_OTHER.equals(str);
- List<SourceGroup> toReturn = new ArrayList<SourceGroup>();
- File[] roots = project().getOtherRoots(test);
- synchronized (lock) {
- // don't fire event synchronously..
- checkOtherGroupsCache(roots, test);
- if (test && !otherTestGroups.isEmpty()) {
- toReturn.addAll(otherTestGroups.values());
- } else if (!test && !otherMainGroups.isEmpty()) {
- toReturn.addAll(otherMainGroups.values());
- }
- }
- SourceGroup[] grp = new SourceGroup[toReturn.size()];
- grp = toReturn.toArray(grp);
- return grp;
- }
- if (JavaProjectConstants.SOURCES_TYPE_RESOURCES.equals(str)) {
- return getOrCreateResourceSourceGroup(false, false);
- }
- // logger.warn("unknown source type=" + str);
- return new SourceGroup[0];
- }
- @Messages("SG_Project_Resources=Project Resources")
- private SourceGroup[] getOrCreateResourceSourceGroup(boolean test, boolean create) {
- URI[] uris = project().getResources(test);
- if (uris.length > 0) {
- List<URI> virtuals = new ArrayList<URI>();
- List<SourceGroup> existing = new ArrayList<SourceGroup>();
- for (URI u : uris) {
- FileObject fo = FileUtilities.convertURItoFileObject(u);
- if (fo == null) {
- virtuals.add(u);
- } else if (fo.isFolder()) {
- existing.add(GenericSources.group(proj, fo, "resources", //NOI18N
- SG_Project_Resources(), null, null));
- }
- }
- if (create && existing.isEmpty()) {
- File root = Utilities.toFile(virtuals.get(0));
- try {
- FileObject fo = FileUtil.createFolder(root);
- existing.add(GenericSources.group(proj, fo, "resources", //NOI18N
- SG_Project_Resources(), null, null));
- } catch (IOException ex) {
- Exceptions.printStackTrace(ex);
- }
-
- }
- //TODO we should probably add includes/excludes to source groups.
- return existing.toArray(new SourceGroup[0]);
- } else {
- //TODO add <Resources> element to pom??
- }
- return new SourceGroup[0];
- }
-
- //QualitasCorpus.class: Created due to compilation errors
- private String SG_Project_Resources() {
- // TODO Auto-generated method stub
- return null;
- }
- /**
- * consult the SourceGroup cache, return true if anything changed..
- */
- private boolean checkSourceGroupCache(@NullAllowed File rootF, String name, String displayName, Map<String, SourceGroup> groups, NbMavenProject watcher) {
- FileObject root;
- if (rootF != null) {
- watcher.addWatchedPath(Utilities.toURI(rootF));
- root = FileUtil.toFileObject(rootF);
- } else {
- root = null;
- }
- SourceGroup group = groups.get(name);
- if ((root == null || root.isData()) && group != null) {
- groups.remove(name);
- return true;
- }
- if (root == null || root.isData()) {
- return false;
- }
- boolean changed = false;
- if (group == null) {
- group = GenericSources.group(proj, root, name, displayName, null, null);
- groups.put(name, group);
- changed = true;
- } else {
- if (!group.getRootFolder().equals(root)) {
- group = GenericSources.group(proj, root, name, displayName, null, null);
- groups.put(name, group);
- changed = true;
- }
- }
- return changed;
- }
- private boolean checkGeneratedGroupsCache() {
- boolean changed = false;
- List<File> checked = new ArrayList<File>();
- for (boolean test : new boolean[] {false, true}) {
- for (URI u : project().getGeneratedSourceRoots(test)) {
- File file = FileUtil.normalizeFile(Utilities.toFile(u));
- FileObject folder = FileUtil.toFileObject(file);
- changed |= checkGeneratedGroupCache(folder, file, file.getName(), test);
- checked.add(file);
- }
- }
- Set<File> currs = new HashSet<File>();
- currs.addAll(genSrcGroup.keySet());
- for (File curr : currs) {
- if (!checked.contains(curr)) {
- genSrcGroup.remove(curr);
- changed = true;
- }
- }
- return changed;
- }
- /**
- * consult the SourceGroup cache, return true if anything changed..
- */
- @Messages({
- "# {0} - name suffix", "SG_Generated_Sources=Generated Sources ({0})",
- "# {0} - name suffix", "SG_Generated_Test_Sources=Generated Test Sources ({0})"
- })
- private boolean checkGeneratedGroupCache(FileObject root, File rootFile, String nameSuffix, boolean test) {
- SourceGroup group = genSrcGroup.get(rootFile);
- if ((root == null || root.isData()) && group != null) {
- genSrcGroup.remove(rootFile);
- return true;
- }
- if (root == null || root.isData()) {
- return false;
- }
- boolean changed = false;
- String name = (test ? NAME_GENERATED_TEST_SOURCE : NAME_GENERATED_SOURCE) + nameSuffix;
- String displayName = (String) (test ? SG_Generated_Test_Sources(nameSuffix) : SG_Generated_Sources(nameSuffix));
- if (group == null) {
- group = new GeneratedGroup(project(), root, name, displayName);
- genSrcGroup.put(rootFile, group);
- changed = true;
- } else {
- if (!group.getRootFolder().isValid() || !group.getRootFolder().equals(root)) {
- group = new GeneratedGroup(project(), root, name, displayName);
- genSrcGroup.put(rootFile, group);
- changed = true;
- }
- }
- return changed;
- }
- //QualitasCorpus.class: Created due to compilation errors
- private Object SG_Generated_Test_Sources(String nameSuffix) {
- // TODO Auto-generated method stub
- return null;
- }
- private Object SG_Generated_Sources(String nameSuffix) {
- // TODO Auto-generated method stub
- return null;
- }
- private boolean checkOtherGroupsCache(File[] roots, boolean test) {
- boolean ch = false;
- Set<File> toRemove = new HashSet<File>(test ? otherTestGroups.keySet() : otherMainGroups.keySet());
- toRemove.removeAll(Arrays.asList(roots));
- URI[] res = project().getResources(test);
- Set<File> resources = new HashSet<File>();
- for (URI ur : res) {
- resources.add(Utilities.toFile(ur));
- }
- for (File f : roots) {
- ch = ch | checkOtherGroup(f, resources, test);
- }
- for (File f : toRemove) {
- //now this shall remove the nonexisting ones and even mark the change..
- ch = ch | checkOtherGroup(f, resources, test);
- }
- return ch;
- }
- private boolean checkOtherGroup(File rootFile, Set<File> resourceRoots, boolean test) {
- FileObject root = FileUtil.toFileObject(rootFile);
- if (root != null && !root.isFolder()) {
- root = null;
- }
- Map<File, OtherGroup> map = test ? otherTestGroups : otherMainGroups;
- OtherGroup grp = map.get(rootFile);
- boolean isResourceNow = resourceRoots.contains(rootFile);
- boolean wasResourceBefore = grp != null && grp.getResource() != null;
- if ((root == null && grp != null) || (root != null && grp != null && wasResourceBefore && !isResourceNow)) {
- map.remove(rootFile);
- return true;
- }
- if (root == null) {
- return false;
- }
- boolean changed = false;
- if (grp == null || !grp.getRootFolder().isValid() || !grp.getRootFolder().equals(root) ||
- isResourceNow != wasResourceBefore) {
- grp = new OtherGroup(project(), root, "Resource" + (test ? "Test":"Main") + root.getNameExt(), root.getName(), test); //NOI18N
- map.put(rootFile, grp);
- changed = true;
- }
- return changed;
- }
- public @Override SourceGroup createSourceGroup(String type, String hint) {
- assert type != null;
- MavenProject mp = project().getOriginalMavenProject();
- File folder = null;
- if (JavaProjectConstants.SOURCES_TYPE_RESOURCES.equals(type)) {
- boolean main = JavaProjectConstants.SOURCES_HINT_MAIN.equals(hint);
- SourceGroup[] grps = getOrCreateResourceSourceGroup(!main, true);
- if (grps.length > 0) {
- return grps[0];
- }
- return null;
- }
- if (JavaProjectConstants.SOURCES_TYPE_JAVA.equals(type)) {
- if (JavaProjectConstants.SOURCES_HINT_MAIN.equals(hint)) {
- folder = FileUtilities.convertStringToFile(mp.getBuild().getSourceDirectory());
- }
- if (JavaProjectConstants.SOURCES_HINT_TEST.equals(hint)) {
- folder = FileUtilities.convertStringToFile(mp.getBuild().getTestSourceDirectory());
- }
- }
- if (folder != null) {
- FileObject fo;
- try {
- fo = FileUtil.createFolder(folder);
- } catch (IOException x) { // XXX not allowed to rethrow
- Logger.getLogger(MavenSourcesImpl.class.getName()).log(Level.INFO, null, x);
- return null;
- }
- SourceGroup[] grps = getSourceGroups(type);
- for (SourceGroup sg : grps) {
- if (fo.equals(sg.getRootFolder())) {
- return sg;
- }
- }
- //shall we somehow report it?
- }
- return null;
- }
- public @Override boolean canCreateSourceGroup(String type, String hint) {
- return (JavaProjectConstants.SOURCES_TYPE_RESOURCES.equals(type) ||
- JavaProjectConstants.SOURCES_TYPE_JAVA.equals(type))
- && (JavaProjectConstants.SOURCES_HINT_MAIN.equals(hint) ||
- JavaProjectConstants.SOURCES_HINT_TEST.equals(hint));
- }
-
-
- public static final class OtherGroup implements SourceGroup {
-
- private final FileObject rootFolder;
- private File rootFile;
- private final String name;
- private final String displayName;
- private final Icon icon;
- private final Icon openedIcon;
- private NbMavenProjectImpl project;
- private Resource resource;
- private PropertyChangeSupport support = new PropertyChangeSupport(this);
-
- @Messages("SG_Root_not_defined=<Root not defined>")
- OtherGroup(NbMavenProjectImpl p, FileObject rootFold, String nm, String displayNm, boolean test) {
- project = p;
- rootFolder = rootFold;
- rootFile = FileUtil.toFile(rootFolder);
- resource = checkResource(rootFold,
- test ? project.getOriginalMavenProject().getTestResources() :
- project.getOriginalMavenProject().getResources());
- if (resource != null) {
- Image badge = ImageUtilities.loadImage("org/netbeans/modules/maven/others-badge.png", true); //NOI18N
- // ImageUtilities.addToolTipToImage(badge, "Resource root as defined in POM.");
- icon = ImageUtilities.image2Icon(ImageUtilities.mergeImages(NodeUtils.getTreeFolderIcon(false), badge, 8, 8));
- openedIcon = ImageUtilities.image2Icon(ImageUtilities.mergeImages(NodeUtils.getTreeFolderIcon(true), badge, 8, 8));
- name = FileUtilities.relativizeFile(FileUtil.toFile(project.getProjectDirectory()), FileUtilities.convertStringToFile(resource.getDirectory()));
- displayName = name;
- } else {
- icon = ImageUtilities.image2Icon(NodeUtils.getTreeFolderIcon(false));
- openedIcon = ImageUtilities.image2Icon(NodeUtils.getTreeFolderIcon(true));
- name = nm;
- displayName = displayNm != null ? displayNm : SG_Root_not_defined();
- }
- }
- //QualitasCorpus.class: Created due to compilation errors
- private String SG_Root_not_defined() {
- // TODO Auto-generated method stub
- return null;
- }
- public @Override FileObject getRootFolder() {
- return rootFolder;
- }
-
- public File getRootFolderFile() {
- return rootFile;
- }
- public Resource getResource() {
- return resource;
- }
-
- public @Override String getName() {
- return name;
- }
-
- public @Override String getDisplayName() {
- if (resource != null && resource.getTargetPath() != null) {
- return displayName + " -> " + resource.getTargetPath();
- }
- return displayName;
- }
-
- public @Override Icon getIcon(boolean opened) {
- return opened ? icon : openedIcon;
- }
-
- public @Override boolean contains(FileObject file) {
- if (file != rootFolder && !FileUtil.isParentOf(rootFolder, file)) {
- return false;
- }
- if (project != null) {
- if (file.isFolder() && file != project.getProjectDirectory() && ProjectManager.getDefault().isProject(file)) {
- // #67450: avoid actually loading the nested project.
- return false;
- }
- if (FileOwnerQuery.getOwner(file) != project) {
- return false;
- }
- }
- File f = FileUtil.toFile(file);
- if (f != null) {
- // MIXED, UNKNOWN, and SHARABLE -> include it
- return SharabilityQuery.getSharability(f) != SharabilityQuery.NOT_SHARABLE;
- } else {
- // Not on disk, include it.
- return true;
- }
- }
-
- public @Override void addPropertyChangeListener(PropertyChangeListener l) {
- support.addPropertyChangeListener(l);
- }
-
- public @Override void removePropertyChangeListener(PropertyChangeListener l) {
- support.removePropertyChangeListener(l);
- }
- private Resource checkResource(FileObject rootFold, List<Resource> list) {
- for (Resource elem : list) {
- String dir = elem.getDirectory();
- if (dir == null) { // #203635
- continue;
- }
- URI uri = FileUtilities.getDirURI(project.getProjectDirectory(), dir);
- FileObject fo = FileUtilities.convertURItoFileObject(uri);
- if (fo != null && fo.equals(rootFold)) {
- return elem;
- }
- }
- return null;
- }
-
- }
-
- /**
- * MEVENIDE-536 - cannot use default implementation of SourceGroup because it
- * won't include non-shareable folders..
- */
- public static final class GeneratedGroup implements SourceGroup {
-
- private final FileObject rootFolder;
- private final String name;
- private final String displayName;
- private final Icon icon = null;
- private final Icon openedIcon = null;
- private NbMavenProjectImpl project;
-
- GeneratedGroup(NbMavenProjectImpl p, FileObject rootFold, String nm, String displayNm/*,
- Icon icn, Icon opened*/) {
- project = p;
- rootFolder = rootFold;
- name = nm;
- displayName = displayNm != null ? displayNm : SG_Root_not_defined();
- // icon = icn;
- // openedIcon = opened;
- }
- //QualitasCorpus.class: Created due to compilation errors
- private String SG_Root_not_defined() {
- // TODO Auto-generated method stub
- return null;
- }
- public @Override FileObject getRootFolder() {
- return rootFolder;
- }
-
- public @Override String getName() {
- return name;
- }
-
- public @Override String getDisplayName() {
- return displayName;
- }
-
- public @Override Icon getIcon(boolean opened) {
- return opened ? icon : openedIcon;
- }
-
- public @Override boolean contains(FileObject file) {
- if (file != rootFolder && !FileUtil.isParentOf(rootFolder, file)) {
- return false;
- }
- if (project != null) {
- if (file.isFolder() && file != project.getProjectDirectory() && ProjectManager.getDefault().isProject(file)) {
- // #67450: avoid actually loading the nested project.
- return false;
- }
- if (FileOwnerQuery.getOwner(file) != project) {
- return false;
- }
- }
- return true;
- }
-
- public @Override void addPropertyChangeListener(PropertyChangeListener l) {
- // XXX should react to ProjectInformation changes
- }
-
- public @Override void removePropertyChangeListener(PropertyChangeListener l) {
- // XXX
- }
-
- }
-
- }