blob: bb51cf507aad93340dbd3236b6c5ec040df0abe0 [file] [log] [blame]
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008-2010 Sun Microsystems, Inc. All rights reserved.
*
* 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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-2010 Sun Microsystems, Inc.
*/
package org.netbeans.modules.jackpot30.indexing.batch;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.source.ModificationResult;
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.ui.OpenProjects;
import org.netbeans.api.sendopts.CommandException;
import org.netbeans.modules.java.hints.providers.spi.HintDescription;
import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
import org.netbeans.modules.java.hints.spiimpl.Utilities;
import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch;
import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.BatchResult;
import org.netbeans.modules.java.hints.spiimpl.batch.BatchSearch.Folder;
import org.netbeans.modules.java.hints.spiimpl.batch.BatchUtilities;
import org.netbeans.modules.java.hints.spiimpl.batch.ProgressHandleWrapper;
import org.netbeans.modules.java.hints.spiimpl.batch.Scopes;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.netbeans.spi.java.hints.HintContext.MessageKind;
import org.netbeans.spi.sendopts.Env;
import org.netbeans.spi.sendopts.Option;
import org.netbeans.spi.sendopts.OptionProcessor;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.lookup.ServiceProvider;
/**
*
* @author Jan Lahoda
*/
@ServiceProvider(service=OptionProcessor.class)
public class OptionProcessorImpl extends OptionProcessor {
private static final Logger LOG = Logger.getLogger(OptionProcessorImpl.class.getName());
private static final String APPLY_TRANSFORMATIONS_PROJECT_OPTION = "apply-transformations-project";
private static final Option LIST = Option.withoutArgument(Option.NO_SHORT_NAME, "list-hints-transformation");
private static final Option APPLY_TRANSFORMATIONS = Option.shortDescription(
Option.requiredArgument(Option.NO_SHORT_NAME, "apply-transformations"),
"org.netbeans.modules.jackpot30.impl.batch.Bundle",
"SD_ApplyTransformations");
private static final Option APPLY_TRANSFORMATIONS_PROJECT = Option.shortDescription(
Option.additionalArguments(Option.NO_SHORT_NAME, APPLY_TRANSFORMATIONS_PROJECT_OPTION),
"org.netbeans.modules.jackpot30.impl.batch.Bundle",
"SD_ApplyTransformationsProject");
private static final Set<Option> OPTIONS = new HashSet<Option>(Arrays.asList(LIST, APPLY_TRANSFORMATIONS, APPLY_TRANSFORMATIONS_PROJECT));
@Override
protected Set<Option> getOptions() {
return OPTIONS;
}
@Override
protected void process(Env env, Map<Option, String[]> optionValues) throws CommandException {
List<Project> projects = new LinkedList<Project>();
Map<String, List<ClassPath>> classPaths = new HashMap<String, List<ClassPath>>();
if (optionValues.containsKey(APPLY_TRANSFORMATIONS_PROJECT)) {
String[] projectNames = optionValues.get(APPLY_TRANSFORMATIONS_PROJECT);
if (projectNames.length == 0) {
env.getErrorStream().println("At least one parameter needed for " + APPLY_TRANSFORMATIONS_PROJECT_OPTION);
throw new CommandException(1);
}
FileObject currentDirectory = FileUtil.toFileObject(env.getCurrentDirectory());
OUTER: for (String p : projectNames) {
FileObject projectFile = currentDirectory.getFileObject(p);
if (projectFile == null) {
projectFile = FileUtil.toFileObject(new File(p));
}
if (projectFile == null) {
env.getErrorStream().println("Ignoring file " + p + " - cannot be found.");
continue;
}
if (!projectFile.isFolder()) {
env.getErrorStream().println("Ignoring file " + p + " - not a folder.");
continue;
}
Project project = null;
String error = null;
try {
project = ProjectManager.getDefault().findProject(projectFile);
} catch (IOException ex) {
error = ex.getLocalizedMessage();
} catch (IllegalArgumentException ex) {
error = ex.getLocalizedMessage();
}
if (project == null) {
if (error == null) {
env.getErrorStream().println("Ignoring file " + p + " - not a project.");
} else {
env.getErrorStream().println("Ignoring file " + p + " - not a project (" + error + ").");
}
continue;
}
for (SourceGroup sg : ProjectUtils.getSources(project).getSourceGroups("java")) {
FileObject root = sg.getRootFolder();
for (String type : Arrays.asList(ClassPath.BOOT, ClassPath.COMPILE, ClassPath.SOURCE)) {
if (!handleClassPath(root, type, env, p, classPaths)) {
continue OUTER;
}
}
}
projects.add(project);
}
} else {
projects.addAll(Arrays.asList(OpenProjects.getDefault().getOpenProjects()));
}
if (optionValues.containsKey(LIST)) {
env.getOutputStream().println("Supported Hints:");
Set<ClassPath> cps = new HashSet<ClassPath>();
for (List<ClassPath> c : classPaths.values()) {
cps.addAll(c);
}
Set<String> displayNames = Utilities.sortOutHints(Utilities.listAllHints(cps), new TreeMap<String, Collection<HintDescription>>()).keySet();
for (String displayName : displayNames) {
env.getOutputStream().println(displayName);
}
}
if (optionValues.containsKey(APPLY_TRANSFORMATIONS)) {
String hintsArg = optionValues.get(APPLY_TRANSFORMATIONS)[0];
List<HintDescription> hintDescriptions = new LinkedList<HintDescription>();
Set<ClassPath> cps = new HashSet<ClassPath>();
for (List<ClassPath> c : classPaths.values()) {
cps.addAll(c);
}
Map<String, Collection<HintDescription>> sorted = Utilities.sortOutHints(Utilities.listAllHints(cps), new TreeMap<String, Collection<HintDescription>>());
for (String hint : hintsArg.split(":")) {
Collection<HintDescription> descs = sorted.get(hint);
if (descs == null) {
env.getErrorStream().println("Unknown hint: " + hint);
continue;
}
hintDescriptions.addAll(descs);
}
Collection<Folder> roots = new ArrayList<Folder>();
for (FileObject f : BatchUtilities.getSourceGroups(projects)) {
roots.add(new Folder(f));
}
BatchResult candidates = BatchSearch.findOccurrences(hintDescriptions, Scopes.specifiedFoldersScope(roots.toArray(new Folder[0])));
List<MessageImpl> problems = new LinkedList<MessageImpl>(candidates.problems);
Collection<? extends ModificationResult> res = BatchUtilities.applyFixes(candidates, new ProgressHandleWrapper(100), null, problems);
Set<FileObject> modified = new HashSet<FileObject>();
for (ModificationResult mr : res) {
try {
mr.commit();
} catch (IOException ex) {
ex.printStackTrace(env.getErrorStream());
problems.add(new MessageImpl(MessageKind.ERROR, "Cannot apply changes: " + ex.getLocalizedMessage()));
}
modified.addAll(mr.getModifiedFileObjects());
}
try {
org.netbeans.modules.jackpot30.indexing.batch.BatchUtilities.removeUnusedImports(modified);
} catch (IOException ex) {
ex.printStackTrace(env.getErrorStream());
problems.add(new MessageImpl(MessageKind.ERROR, "Cannot remove unused imports: " + ex.getLocalizedMessage()));
}
if (!problems.isEmpty()) {
env.getErrorStream().println("Problem encountered while applying the transformations:");
for (MessageImpl problem : problems) {
env.getErrorStream().println(problem.text);
}
}
}
}
private boolean handleClassPath(FileObject root, String type, Env env, String p, Map<String, List<ClassPath>> classPaths) {
ClassPath cp = ClassPath.getClassPath(root, type);
if (cp == null) {
env.getErrorStream().println("Ignoring file " + p + " - no " + type + " classpath for source group: " + FileUtil.getFileDisplayName(root));
return false;
}
List<ClassPath> cps = classPaths.get(type);
if (cps == null) {
classPaths.put(type, cps = new LinkedList<ClassPath>());
}
cp = ClassPathSupport.createProxyClassPath(cp);
cps.add(cp);
return true;
}
}