001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.web.jsf.refactoring;
043:
044: import com.sun.source.tree.CompilationUnitTree;
045: import com.sun.source.tree.Tree.Kind;
046: import com.sun.source.util.TreePath;
047: import java.io.IOException;
048: import java.util.List;
049: import java.util.logging.Level;
050: import java.util.logging.Logger;
051: import javax.lang.model.element.Element;
052: import javax.lang.model.element.TypeElement;
053: import org.netbeans.api.fileinfo.NonRecursiveFolder;
054: import org.netbeans.api.java.classpath.ClassPath;
055: import org.netbeans.api.java.source.CompilationController;
056: import org.netbeans.api.java.source.CompilationInfo;
057: import org.netbeans.api.java.source.JavaSource;
058: import org.netbeans.api.java.source.Task;
059: import org.netbeans.api.java.source.TreePathHandle;
060: import org.netbeans.modules.refactoring.api.Problem;
061: import org.netbeans.modules.refactoring.api.RenameRefactoring;
062: import org.netbeans.modules.refactoring.spi.RefactoringElementsBag;
063: import org.netbeans.modules.refactoring.spi.RefactoringPlugin;
064: import org.netbeans.modules.web.api.webmodule.WebModule;
065: import org.openide.filesystems.FileObject;
066: import org.openide.filesystems.FileUtil;
067: import org.openide.text.PositionBounds;
068:
069: /**
070: *
071: * @author Petr Pisl
072: */
073:
074: public class JSFRenamePlugin implements RefactoringPlugin {
075:
076: /** This one is important creature - makes sure that cycles between plugins won't appear */
077: private static ThreadLocal semafor = new ThreadLocal();
078: private TreePathHandle treePathHandle = null;
079:
080: private static final Logger LOGGER = Logger
081: .getLogger(JSFRenamePlugin.class.getName());
082:
083: private final RenameRefactoring refactoring;
084:
085: /** Creates a new instance of WicketRenameRefactoringPlugin */
086: public JSFRenamePlugin(RenameRefactoring refactoring) {
087: this .refactoring = refactoring;
088: }
089:
090: public Problem preCheck() {
091: LOGGER.fine("preCheck() called."); //NOI18N
092: return null;
093: }
094:
095: public Problem checkParameters() {
096: LOGGER.fine("checkParameters() called."); //NOI18N
097: return null;
098: }
099:
100: public Problem fastCheckParameters() {
101: LOGGER.fine("fastCheckParameters() called."); //NOI18N
102: return null;
103: }
104:
105: public void cancelRequest() {
106: }
107:
108: @SuppressWarnings("unchecked")
109: public Problem prepare(RefactoringElementsBag refactoringElements) {
110: if (semafor.get() == null) {
111: semafor.set(new Object());
112:
113: FileObject fileObject = refactoring.getRefactoringSource()
114: .lookup(FileObject.class);
115: NonRecursiveFolder nonRecursivefolder = refactoring
116: .getRefactoringSource().lookup(
117: NonRecursiveFolder.class);
118: treePathHandle = refactoring.getRefactoringSource().lookup(
119: TreePathHandle.class);
120:
121: if (fileObject != null
122: && (JSFRefactoringUtils.isJavaFile(fileObject) || fileObject
123: .isFolder())) {
124: if (fileObject.isFolder()) {
125: // renaming folder -> recursively
126:
127: // find the old package name
128: ClassPath classPath = ClassPath.getClassPath(
129: fileObject, ClassPath.SOURCE);
130: FileObject root = classPath
131: .findOwnerRoot(fileObject);
132: String prefix = FileUtil.getRelativePath(root,
133: fileObject.getParent()).replace('/', '.');
134: String oldName = (prefix.length() == 0 ? fileObject
135: .getName() : prefix + "."
136: + fileObject.getName());
137: // the new package name
138: String newName = (prefix.length() == 0 ? refactoring
139: .getNewName()
140: : prefix + "." + refactoring.getNewName());
141:
142: JSFRefactoringUtils.renamePackage(refactoring,
143: refactoringElements, fileObject, oldName,
144: newName, true);
145: } else {
146: if (JSFRefactoringUtils.isJavaFile(fileObject)) {
147: JavaSource source = JavaSource
148: .forFileObject(fileObject);
149: // Can be null, if it is just folder.
150: if (source != null) {
151: try {
152: source
153: .runUserActionTask(
154: new Task<CompilationController>() {
155: public void run(
156: CompilationController co)
157: throws Exception {
158: co
159: .toPhase(JavaSource.Phase.RESOLVED);
160: CompilationUnitTree cut = co
161: .getCompilationUnit();
162: if (!cut
163: .getTypeDecls()
164: .isEmpty()) {
165: treePathHandle = TreePathHandle
166: .create(
167: TreePath
168: .getPath(
169: cut,
170: cut
171: .getTypeDecls()
172: .get(
173: 0)),
174: co);
175: refactoring
176: .getContext()
177: .add(
178: co);
179: }
180: }
181: }, false);
182: } catch (IllegalArgumentException ex) {
183: LOGGER.log(Level.WARNING,
184: "Exception in JSFRenamePlugin",
185: ex); //NOI18N
186: } catch (IOException ex) {
187: LOGGER.log(Level.WARNING,
188: "Exception in JSFRenamePlugin",
189: ex); //NOI18N
190: }
191: }
192: }
193: }
194: }
195: if (nonRecursivefolder != null) {
196: // non recursive package renaming
197: String oldName = JSFRefactoringUtils
198: .getPackageName(nonRecursivefolder.getFolder());
199: String newName = refactoring.getNewName();
200:
201: JSFRefactoringUtils.renamePackage(refactoring,
202: refactoringElements, nonRecursivefolder
203: .getFolder(), oldName, newName, false);
204: }
205:
206: if (treePathHandle != null
207: && treePathHandle.getKind() == Kind.CLASS) {
208: //renaming a class
209: WebModule webModule = WebModule
210: .getWebModule(treePathHandle.getFileObject());
211: if (webModule != null) {
212: CompilationInfo info = JSFRefactoringUtils
213: .getCompilationInfo(refactoring,
214: treePathHandle.getFileObject());
215: if (info != null) {
216: Element resElement = treePathHandle
217: .resolveElement(info);
218: TypeElement type = (TypeElement) resElement;
219: String oldFQN = type.getQualifiedName()
220: .toString();
221: String newFQN = renameClass(oldFQN, refactoring
222: .getNewName());
223: List<Occurrences.OccurrenceItem> items = Occurrences
224: .getAllOccurrences(webModule, oldFQN,
225: newFQN);
226: Modifications modification = new Modifications();
227: for (Occurrences.OccurrenceItem item : items) {
228: // refactoringElements.add(refactoring, new JSFConfigRenameClassElement(item));
229: PositionBounds position = item
230: .getChangePosition();
231: Modifications.Difference difference = new Modifications.Difference(
232: Modifications.Difference.Kind.CHANGE,
233: position.getBegin(), position
234: .getEnd(), oldFQN, newFQN,
235: item.getChangeMessage());
236: modification.addDifference(item
237: .getFacesConfig(), difference);
238: refactoringElements.add(refactoring,
239: new DiffElement.ChangeFQCNElement(
240: difference, item,
241: modification));
242: }
243: }
244: }
245: }
246:
247: semafor.set(null);
248: }
249: return null;
250: }
251:
252: /**
253: * @return true if given str is null or empty.
254: */
255: private static boolean isEmpty(String str) {
256: return str == null || "".equals(str.trim());
257: }
258:
259: /**
260: * Constructs new name for given class.
261: * @param originalFullyQualifiedName old fully qualified name of the class.
262: * @param newName new unqualified name of the class.
263: * @return new fully qualified name of the class.
264: */
265: private static String renameClass(
266: String originalFullyQualifiedName, String newName) {
267: if (isEmpty(originalFullyQualifiedName) || isEmpty(newName)) {
268: throw new IllegalArgumentException(
269: "Old and new name of the class must be given."); //NOI18N
270: }
271: int lastDot = originalFullyQualifiedName.lastIndexOf('.');
272: if (lastDot <= 0) {
273: // no package
274: return newName;
275: }
276: return originalFullyQualifiedName.substring(0, lastDot + 1)
277: + newName;
278: }
279:
280: }
|