/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-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]" * * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun * Microsystems, Inc. All Rights Reserved. * * 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. */ package org.netbeans.modules.refactoring.ruby.plugins; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.csl.spi.support.ModificationResult; import org.netbeans.modules.parsing.api.Embedding; import org.netbeans.modules.parsing.api.ParserManager; import org.netbeans.modules.parsing.api.ResultIterator; import org.netbeans.modules.parsing.api.Source; import org.netbeans.modules.parsing.api.UserTask; import org.netbeans.modules.parsing.spi.ParseException; import org.netbeans.modules.refactoring.spi.*; import org.netbeans.modules.refactoring.api.*; import org.netbeans.modules.ruby.AstUtilities; import org.netbeans.modules.ruby.RubyUtils; import org.openide.filesystems.FileObject; /** * * @author Jan Becicka */ public abstract class RubyRefactoringPlugin extends ProgressProviderAdapter implements RefactoringPlugin { // protected enum Phase {PRECHECK, FASTCHECKPARAMETERS, CHECKPARAMETERS, PREPARE, DEFAULT}; // private Phase whatRun = Phase.DEFAULT; // private Problem problem; // protected volatile boolean cancelRequest; // private volatile CancellableTask currentTask; protected boolean cancelled; // protected abstract Problem preCheck(CompilationController javac) throws IOException; // protected abstract Problem checkParameters(CompilationController javac) throws IOException; // protected abstract Problem fastCheckParameters(CompilationController javac) throws IOException; // // protected abstract Source getRubySource(Phase p); // // public void cancel() { // } // // public final void run(CompilationController javac) throws Exception { // switch(whatRun) { // case PRECHECK: // this.problem = preCheck(javac); // break; // case CHECKPARAMETERS: // this.problem = checkParameters(javac); // break; // case FASTCHECKPARAMETERS: // this.problem = fastCheckParameters(javac); // break; // default: // throw new IllegalStateException(); // } // } protected final boolean isCancelled() { synchronized (this) { return cancelled; } } public final void cancelRequest() { synchronized (this) { cancelled = true; } } // protected ClasspathInfo getClasspathInfo(AbstractRefactoring refactoring) { // ClasspathInfo cpInfo = refactoring.getContext().lookup(ClasspathInfo.class); // if (cpInfo==null) { // Logger.getLogger(getClass().getName()).log(Level.INFO, "Missing scope (ClasspathInfo), using default scope (all open projects)"); // cpInfo = RetoucheUtils.getClasspathInfoFor((FileObject)null); // if (cpInfo != null) { // refactoring.getContext().add(cpInfo); // } // } // return cpInfo; // } protected static final Problem createProblem(Problem result, boolean isFatal, String message) { Problem problem = new Problem(isFatal, message); if (result == null) { return problem; } else if (isFatal) { problem.setNext(result); return problem; } else { //problem.setNext(result.getNext()); //result.setNext(problem); // [TODO] performance Problem p = result; while (p.getNext() != null) p = p.getNext(); p.setNext(problem); return result; } } // private Iterable<? extends List<FileObject>> groupByRoot (Iterable<? extends FileObject> data) { // Map<FileObject,List<FileObject>> result = new HashMap<FileObject,List<FileObject>> (); // for (FileObject file : data) { // ClassPath cp = ClassPath.getClassPath(file, ClassPath.SOURCE); // if (cp != null) { // FileObject root = cp.findOwnerRoot(file); // if (root != null) { // List<FileObject> subr = result.get (root); // if (subr == null) { // subr = new LinkedList<FileObject>(); // result.put (root,subr); // } // subr.add (file); // } // } // } // return result.values(); // } protected final Collection<ModificationResult> processFiles(Set<FileObject> files, TransformTask task) { // Process Ruby files and RHTML files separately - and OTHER files separately // TODO - now that I don't need separate RHTML models any more, can // I just do a single pass? Set<Source> rubyFiles = new HashSet<Source>(2 * files.size()); Set<Source> rhtmlFiles = new HashSet<Source>(2 * files.size()); for (FileObject file : files) { if (RubyUtils.isRubyFile(file)) { rubyFiles.add(Source.create(file)); } else if (RubyUtils.isRhtmlOrYamlFile(file)) { // Avoid opening HUGE Yaml files - they may be containing primarily data if (file.getSize() > 512 * 1024) { continue; } rhtmlFiles.add(Source.create(file)); } } Set<Source> sources = new HashSet<Source>(rubyFiles.size() + rhtmlFiles.size()); sources.addAll(rubyFiles); sources.addAll(rhtmlFiles); try { ParserManager.parse(sources, task); return task.results; } catch (ParseException e) { throw new RuntimeException(e); } //// //// Iterable<? extends List<FileObject>> work = groupByRoot(rubyFiles); //// for (List<FileObject> fos : work) { //// final Source source = Source.create(ClasspathInfo.create(fos.get(0)), fos); //// try { //// results.add(source.runModificationTask(task)); //// } catch (IOException ex) { //// throw (RuntimeException) new RuntimeException().initCause(ex); //// } //// } //// work = groupByRoot(rhtmlFiles); //// for (List<FileObject> fos : work) { //// final Source source = Source.create(ClasspathInfo.create(fos.get(0)), fos); //// try { //// results.add(source.runModificationTask(task)); //// } catch (IOException ex) { //// throw (RuntimeException) new RuntimeException().initCause(ex); //// } //// } // return results; } protected abstract class TransformTask extends UserTask { private final Collection<ModificationResult> results = new ArrayList<ModificationResult>(); public final void run(ResultIterator resultIterator) throws ParseException { visit(resultIterator); fireProgressListenerStep(); } protected abstract Collection<ModificationResult> process(ParserResult jspr); private void visit(ResultIterator resultIterator) throws ParseException { if (resultIterator.getSnapshot().getMimeType().equals(RubyUtils.RUBY_MIME_TYPE)) { ParserResult pr = AstUtilities.getParseResult(resultIterator.getParserResult()); if (pr != null) { Collection<ModificationResult> r = process(pr); results.addAll(r); } } for (Embedding e : resultIterator.getEmbeddings()) { visit(resultIterator.getResultIterator(e)); } } } }