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 java.util.ArrayList;
045: import java.util.Collection;
046: import java.util.Iterator;
047: import java.util.List;
048: import java.util.logging.Level;
049: import java.util.logging.Logger;
050: import javax.swing.text.BadLocationException;
051: import javax.swing.text.Position.Bias;
052: import org.netbeans.editor.BaseDocument;
053: import org.netbeans.modules.web.api.webmodule.WebModule;
054: import org.netbeans.modules.web.jsf.JSFConfigDataObject;
055: import org.netbeans.modules.web.jsf.api.ConfigurationUtils;
056: import org.netbeans.modules.web.jsf.api.facesmodel.Converter;
057: import org.netbeans.modules.web.jsf.editor.JSFEditorUtilities;
058: import org.netbeans.modules.web.jsf.api.facesmodel.FacesConfig;
059: import org.netbeans.modules.web.jsf.api.facesmodel.ManagedBean;
060: import org.openide.filesystems.FileObject;
061: import org.openide.loaders.DataObject;
062: import org.openide.loaders.DataObjectNotFoundException;
063: import org.openide.text.CloneableEditorSupport;
064: import org.openide.text.PositionBounds;
065: import org.openide.text.PositionRef;
066: import org.openide.util.NbBundle;
067: import org.w3c.dom.NodeList;
068:
069: /**
070: * These classes represents an occurence in a faces configuration file.
071: * @author Petr Pisl
072: */
073: public class Occurrences {
074:
075: private static final Logger LOGGER = Logger
076: .getLogger(Occurrences.class.getName());
077:
078: public static abstract class OccurrenceItem {
079: // the faces configuration file
080: protected FileObject config;
081:
082: protected String oldValue;
083:
084: protected String newValue;
085:
086: public OccurrenceItem(FileObject config, String newValue,
087: String oldValue) {
088: this .config = config;
089: this .newValue = newValue;
090: this .oldValue = oldValue;
091: }
092:
093: public String getNewValue() {
094: return newValue;
095: }
096:
097: public String getOldValue() {
098: return oldValue;
099: }
100:
101: public FileObject getFacesConfig() {
102: return config;
103: }
104:
105: public String getElementText() {
106: StringBuffer stringBuffer = new StringBuffer();
107: stringBuffer.append("<font color=\"#0000FF\">"); //NOI18N
108: stringBuffer.append("<").append(getXMLElementName())
109: .append("></font><b>"); //NOI18N
110: stringBuffer.append(oldValue).append(
111: "</b><font color=\"#0000FF\"></").append(
112: getXMLElementName()); //NOI18N
113: stringBuffer.append("></font>"); //NOI18N
114: return stringBuffer.toString();
115: }
116:
117: protected abstract String getXMLElementName();
118:
119: //for changes like rename, move, change package...
120: public abstract void performChange();
121:
122: public abstract void undoChange();
123:
124: public abstract String getChangeMessage();
125:
126: public String getRenamePackageMessage() {
127: return NbBundle.getMessage(Occurrences.class,
128: "MSG_Package_Rename", //NOI18N
129: new Object[] { getElementText() });
130: }
131:
132: // save delete
133: public abstract void performSafeDelete();
134:
135: public abstract void undoSafeDelete();
136:
137: public abstract String getSafeDeleteMessage();
138:
139: // usages
140: public abstract String getWhereUsedMessage();
141:
142: protected PositionBounds createPosition(int startOffset,
143: int endOffset) {
144: try {
145: DataObject dataObject = DataObject.find(config);
146: if (dataObject instanceof JSFConfigDataObject) {
147: CloneableEditorSupport editor = JSFEditorUtilities
148: .findCloneableEditorSupport((JSFConfigDataObject) dataObject);
149: if (editor != null) {
150: PositionRef start = editor.createPositionRef(
151: startOffset, Bias.Forward);
152: PositionRef end = editor.createPositionRef(
153: endOffset, Bias.Backward);
154: return new PositionBounds(start, end);
155: }
156: }
157: } catch (DataObjectNotFoundException ex) {
158: LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
159: }
160: return null;
161: }
162:
163: public abstract PositionBounds getChangePosition();
164:
165: }
166:
167: /**
168: * Implementation for ManagedBean
169: */
170: public static class ManagedBeanClassItem extends OccurrenceItem {
171: private final ManagedBean bean;
172: // needed for undo
173: private final ManagedBean copy;
174:
175: public ManagedBeanClassItem(FileObject config,
176: ManagedBean bean, String newValue) {
177: super (config, newValue, bean.getManagedBeanClass());
178: this .bean = bean;
179: this .copy = (ManagedBean) bean.copy(bean.getParent());
180: }
181:
182: protected String getXMLElementName() {
183: return "managed-bean-class"; //NOI18N
184: }
185:
186: public void performChange() {
187: changeBeanClass(newValue);
188: }
189:
190: public void undoChange() {
191: changeBeanClass(oldValue);
192: }
193:
194: public String getWhereUsedMessage() {
195: return NbBundle.getMessage(Occurrences.class,
196: "MSG_ManagedBeanClass_WhereUsed", //NOI18N
197: new Object[] { bean.getManagedBeanName(),
198: getElementText() });
199: }
200:
201: public String getChangeMessage() {
202: return NbBundle.getMessage(Occurrences.class,
203: "MSG_ManagedBeanClass_Rename", //NOI18N
204: new Object[] { bean.getManagedBeanName(),
205: getElementText() });
206: }
207:
208: public void performSafeDelete() {
209: FacesConfig faces = ConfigurationUtils.getConfigModel(
210: config, true).getRootComponent();
211: Collection<ManagedBean> beans = faces.getManagedBeans();
212: for (Iterator<ManagedBean> it = beans.iterator(); it
213: .hasNext();) {
214: ManagedBean managedBean = it.next();
215: if (bean.getManagedBeanName().equals(
216: managedBean.getManagedBeanName())) {
217: faces.getModel().startTransaction();
218: faces.removeManagedBean(managedBean);
219: faces.getModel().endTransaction();
220: break;
221: }
222: }
223: }
224:
225: public void undoSafeDelete() {
226: FacesConfig facesConfig = ConfigurationUtils
227: .getConfigModel(config, true).getRootComponent();
228: facesConfig.getModel().startTransaction();
229: facesConfig.addManagedBean(copy);
230: facesConfig.getModel().endTransaction();
231: }
232:
233: public String getSafeDeleteMessage() {
234: return NbBundle.getMessage(Occurrences.class,
235: "MSG_ManagedBeanClass_SafeDelete", //NOI18N
236: new Object[] { bean.getManagedBeanName(),
237: getElementText() });
238: }
239:
240: private void changeBeanClass(String className) {
241: FacesConfig facesConfig = ConfigurationUtils
242: .getConfigModel(config, true).getRootComponent();
243: List<ManagedBean> beans = facesConfig.getManagedBeans();
244: for (Iterator<ManagedBean> it = beans.iterator(); it
245: .hasNext();) {
246: ManagedBean managedBean = it.next();
247: if (bean.getManagedBeanName().equals(
248: managedBean.getManagedBeanName())) {
249: facesConfig.getModel().startTransaction();
250: managedBean.setManagedBeanClass(className);
251: facesConfig.getModel().endTransaction();
252: continue;
253: }
254:
255: }
256: }
257:
258: public PositionBounds getChangePosition() {
259: PositionBounds position = null;
260: try {
261: DataObject dataObject = DataObject.find(config);
262: BaseDocument document = JSFEditorUtilities
263: .getBaseDocument(dataObject);
264: int[] offsets = JSFEditorUtilities
265: .getManagedBeanDefinition(document, bean
266: .getManagedBeanName());
267: String text = document.getText(offsets);
268: int offset = offsets[0] + text.indexOf(oldValue);
269: position = createPosition(offset, offset
270: + oldValue.length());
271: } catch (BadLocationException exception) {
272: LOGGER.log(Level.SEVERE, exception.getMessage(),
273: exception);
274: } catch (DataObjectNotFoundException exception) {
275: LOGGER.log(Level.SEVERE, exception.getMessage(),
276: exception);
277: }
278: return position;
279: };
280:
281: }
282:
283: public static class ConverterClassItem extends OccurrenceItem {
284: private final Converter converter;
285: // needed for undo
286: private final Converter copy;
287:
288: public ConverterClassItem(FileObject config,
289: Converter converter, String newValue) {
290: super (config, newValue, converter.getConverterClass());
291: this .converter = converter;
292: this .copy = (Converter) converter.copy(converter
293: .getParent());
294: }
295:
296: protected String getXMLElementName() {
297: return "converter-class"; //NOI18N
298: }
299:
300: public void performChange() {
301: changeConverterClass(oldValue, newValue);
302: }
303:
304: public void undoChange() {
305: changeConverterClass(newValue, oldValue);
306: }
307:
308: public String getWhereUsedMessage() {
309: return NbBundle.getMessage(Occurrences.class,
310: "MSG_ConverterClass_WhereUsed", getElementText()); //NOI18N
311: }
312:
313: public String getChangeMessage() {
314: return NbBundle.getMessage(Occurrences.class,
315: "MSG_ConverterClass_Rename", getElementText()); //NOI18N
316: }
317:
318: public void performSafeDelete() {
319: FacesConfig facesConfig = ConfigurationUtils
320: .getConfigModel(config, true).getRootComponent();
321: List<Converter> converters = facesConfig.getConverters();
322: for (Iterator<Converter> it = converters.iterator(); it
323: .hasNext();) {
324: Converter converter = it.next();
325: if (oldValue.equals(converter.getConverterClass())) {
326: facesConfig.getModel().startTransaction();
327: facesConfig.removeConverter(converter);
328: facesConfig.getModel().endTransaction();
329: break;
330: }
331: }
332: }
333:
334: public void undoSafeDelete() {
335: FacesConfig facesConfig = ConfigurationUtils
336: .getConfigModel(config, true).getRootComponent();
337: facesConfig.getModel().startTransaction();
338: facesConfig.addConverter(copy);
339: facesConfig.getModel().endTransaction();
340: }
341:
342: public String getSafeDeleteMessage() {
343: return NbBundle.getMessage(Occurrences.class,
344: "MSG_Converter_SafeDelete", //NOI18N
345: new Object[] { getElementText() });
346: }
347:
348: private void changeConverterClass(String oldClass,
349: String newClass) {
350: FacesConfig facesConfig = ConfigurationUtils
351: .getConfigModel(config, true).getRootComponent();
352: List<Converter> converters = facesConfig.getConverters();
353: for (Iterator<Converter> it = converters.iterator(); it
354: .hasNext();) {
355: Converter converter = it.next();
356: if (oldClass.equals(converter.getConverterClass())) {
357: converter.getModel().startTransaction();
358: converter.setConverterClass(newClass);
359: converter.getModel().endTransaction();
360: break;
361: }
362: }
363: }
364:
365: public PositionBounds getChangePosition() {
366: PositionBounds position = null;
367: try {
368: DataObject dataObject = DataObject.find(config);
369: BaseDocument document = JSFEditorUtilities
370: .getBaseDocument(dataObject);
371: int[] offsets = JSFEditorUtilities
372: .getConverterDefinition(document,
373: "converter-class", converter
374: .getConverterClass()); //NOI18N
375:
376: String text = document.getText(offsets);
377: int offset = offsets[0] + text.indexOf(oldValue);
378: position = createPosition(offset, offset
379: + oldValue.length());
380: } catch (BadLocationException exception) {
381: LOGGER.log(Level.SEVERE, exception.getMessage(),
382: exception);
383: } catch (DataObjectNotFoundException exception) {
384: LOGGER.log(Level.SEVERE, exception.getMessage(),
385: exception);
386: }
387: return position;
388: };
389:
390: }
391:
392: public static class ConverterForClassItem extends OccurrenceItem {
393: private final Converter converter;
394: //needed for undo
395: private final Converter copy;
396:
397: public ConverterForClassItem(FileObject config,
398: Converter converter, String newValue) {
399: super (config, newValue, converter.getConverterForClass());
400: this .converter = converter;
401: this .copy = (Converter) converter.copy(converter
402: .getParent());
403:
404: }
405:
406: protected String getXMLElementName() {
407: return "converter-for-class"; //NOI18N
408: }
409:
410: public void performChange() {
411: changeConverterForClass(oldValue, newValue);
412: }
413:
414: public void undoChange() {
415: changeConverterForClass(newValue, oldValue);
416: }
417:
418: public String getWhereUsedMessage() {
419: return NbBundle
420: .getMessage(Occurrences.class,
421: "MSG_ConverterForClass_WhereUsed",
422: getElementText()); //NOI18N
423: }
424:
425: public String getChangeMessage() {
426: return NbBundle.getMessage(Occurrences.class,
427: "MSG_ConverterForClass_Rename", getElementText()); //NOI18N
428: }
429:
430: public void performSafeDelete() {
431: FacesConfig facesConfig = ConfigurationUtils
432: .getConfigModel(config, true).getRootComponent();
433: List<Converter> converters = facesConfig.getConverters();
434: for (Iterator<Converter> it = converters.iterator(); it
435: .hasNext();) {
436: Converter converter = it.next();
437: if (oldValue.equals(converter.getConverterClass())) {
438: facesConfig.getModel().startTransaction();
439: facesConfig.removeConverter(converter);
440: facesConfig.getModel().endTransaction();
441: break;
442: }
443: }
444: }
445:
446: public void undoSafeDelete() {
447: FacesConfig facesConfig = ConfigurationUtils
448: .getConfigModel(config, true).getRootComponent();
449: facesConfig.getModel().startTransaction();
450: facesConfig.addConverter(copy);
451: // XXX why this is twice here?
452: //facesConfig.addConverter(converter);
453: facesConfig.getModel().endTransaction();
454: }
455:
456: public String getSafeDeleteMessage() {
457: return NbBundle.getMessage(Occurrences.class,
458: "MSG_Converter_SafeDelete", //NOI18N
459: new Object[] { getElementText() });
460: }
461:
462: private void changeConverterForClass(String oldClass,
463: String newClass) {
464: FacesConfig facesConfig = ConfigurationUtils
465: .getConfigModel(config, true).getRootComponent();
466: List<Converter> converters = facesConfig.getConverters();
467: for (Iterator<Converter> it = converters.iterator(); it
468: .hasNext();) {
469: Converter converter = it.next();
470: if (oldClass.equals(converter.getConverterForClass())) {
471: converter.getModel().startTransaction();
472: converter.setConverterForClass(newClass);
473: converter.getModel().endTransaction();
474: break;
475: }
476: }
477: }
478:
479: public PositionBounds getChangePosition() {
480: PositionBounds position = null;
481: try {
482: DataObject dataObject = DataObject.find(config);
483: BaseDocument document = JSFEditorUtilities
484: .getBaseDocument(dataObject);
485: int[] offsets = JSFEditorUtilities
486: .getConverterDefinition(document,
487: "converter-for-class", converter
488: .getConverterForClass());
489: String text = document.getText(offsets);
490: int offset = offsets[0] + text.indexOf(oldValue);
491: position = createPosition(offset, offset
492: + oldValue.length());
493: } catch (BadLocationException exception) {
494: LOGGER.log(Level.SEVERE, exception.getMessage(),
495: exception);
496: } catch (DataObjectNotFoundException exception) {
497: LOGGER.log(Level.SEVERE, exception.getMessage(),
498: exception);
499: }
500: return position;
501: };
502: }
503:
504: public static List<OccurrenceItem> getAllOccurrences(
505: WebModule webModule, String oldName, String newName) {
506: List result = new ArrayList();
507: assert webModule != null;
508: assert oldName != null;
509:
510: LOGGER.fine("getAllOccurences("
511: + webModule.getDocumentBase().getPath() + ", "
512: + oldName + ", " + newName + ")"); //NOI18N
513: if (webModule != null) {
514: // find all jsf configuration files in the web module
515: FileObject[] configs = ConfigurationUtils
516: .getFacesConfigFiles(webModule);
517:
518: if (configs != null) {
519: for (int i = 0; i < configs.length; i++) {
520: FacesConfig facesConfig = ConfigurationUtils
521: .getConfigModel(configs[i], true)
522: .getRootComponent();
523: List<Converter> converters = facesConfig
524: .getConverters();
525: for (Iterator<Converter> it = converters.iterator(); it
526: .hasNext();) {
527: Converter converter = it.next();
528: if (oldName.equals(converter
529: .getConverterClass()))
530: result.add(new ConverterClassItem(
531: configs[i], converter, newName));
532: else if (oldName.equals(converter
533: .getConverterForClass()))
534: result.add(new ConverterForClassItem(
535: configs[i], converter, newName));
536: }
537: List<ManagedBean> managedBeans = facesConfig
538: .getManagedBeans();
539: for (Iterator<ManagedBean> it = managedBeans
540: .iterator(); it.hasNext();) {
541: ManagedBean managedBean = it.next();
542: if (oldName.equals(managedBean
543: .getManagedBeanClass()))
544: result.add(new ManagedBeanClassItem(
545: configs[i], managedBean, newName));
546:
547: }
548:
549: }
550: }
551: }
552: return result;
553: }
554:
555: public static List<OccurrenceItem> getPackageOccurrences(
556: WebModule webModule, String oldPackageName,
557: String newPackageName, boolean renameSubpackages) {
558: List result = new ArrayList();
559: assert webModule != null;
560: assert oldPackageName != null;
561:
562: if (webModule != null) {
563: // find all jsf configuration files in the web module
564: FileObject[] configs = ConfigurationUtils
565: .getFacesConfigFiles(webModule);
566:
567: if (configs != null) {
568: for (int i = 0; i < configs.length; i++) {
569: FacesConfig facesConfig = ConfigurationUtils
570: .getConfigModel(configs[i], true)
571: .getRootComponent();
572: List<Converter> converters = facesConfig
573: .getConverters();
574: for (Iterator<Converter> it = converters.iterator(); it
575: .hasNext();) {
576: Converter converter = it.next();
577: if (JSFRefactoringUtils
578: .containsRenamingPackage(converter
579: .getConverterClass(),
580: oldPackageName,
581: renameSubpackages))
582: result
583: .add(new ConverterClassItem(
584: configs[i],
585: converter,
586: getNewFQCN(
587: newPackageName,
588: oldPackageName,
589: converter
590: .getConverterClass())));
591: if (JSFRefactoringUtils
592: .containsRenamingPackage(converter
593: .getConverterForClass(),
594: oldPackageName,
595: renameSubpackages))
596: result
597: .add(new ConverterForClassItem(
598: configs[i],
599: converter,
600: getNewFQCN(
601: newPackageName,
602: oldPackageName,
603: converter
604: .getConverterForClass())));
605: }
606: List<ManagedBean> managedBeans = facesConfig
607: .getManagedBeans();
608: for (Iterator<ManagedBean> it = managedBeans
609: .iterator(); it.hasNext();) {
610: ManagedBean managedBean = it.next();
611: if (JSFRefactoringUtils
612: .containsRenamingPackage(managedBean
613: .getManagedBeanClass(),
614: oldPackageName,
615: renameSubpackages))
616: result
617: .add(new ManagedBeanClassItem(
618: configs[i],
619: managedBean,
620: getNewFQCN(
621: newPackageName,
622: oldPackageName,
623: managedBean
624: .getManagedBeanClass())));
625: }
626:
627: }
628: }
629: }
630: return result;
631:
632: }
633:
634: /**
635: * A helper method, which is used for obtaining new FQCN, when a package is renamed.
636: * @param newPackageName the new package name. It must to be always full qualified package name.
637: * @param oldPackageName the old package name. It must to be always full qualified package name.
638: * @param oldFQCN the full qualified class name
639: * @param folderRename Indicates whether the changing package is based on the
640: * renaming package or renaming folder.
641: * @returns new FQCN for the class.
642: */
643: public static String getNewFQCN(String newPackageName,
644: String oldPackageName, String oldFQCN) {
645: String value = oldFQCN;
646:
647: if (oldPackageName.length() == 0) {
648: value = newPackageName + '.' + oldFQCN;
649: } else {
650: if (oldFQCN.startsWith(oldPackageName)) {
651: value = value.substring(oldPackageName.length());
652: if (newPackageName.length() > 0) {
653: value = newPackageName + value;
654: }
655: if (value.charAt(0) == '.') {
656: value = value.substring(1);
657: }
658: }
659: }
660: return value;
661: }
662: }
|