rs.snpe.android.refactoring.core.AndroidPackageRenameParticipant.java Source code

Java tutorial

Introduction

Here is the source code for rs.snpe.android.refactoring.core.AndroidPackageRenameParticipant.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2010 SnPe Informacioni Sistemi.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     SnPe Informacioni sistemi - initial API and implementation
 *******************************************************************************/
package rs.snpe.android.refactoring.core;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.manipulation.JavaManipulation;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.internal.core.JavaModel;
import org.eclipse.jdt.internal.corext.refactoring.changes.RenamePackageChange;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.SearchUtils;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.w3c.dom.Attr;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import rs.snpe.android.refactoring.Activator;
import rs.snpe.android.refactoring.IConstants;
import rs.snpe.android.refactoring.changes.AndroidLayoutChange;
import rs.snpe.android.refactoring.changes.AndroidLayoutChangeDescription;
import rs.snpe.android.refactoring.changes.AndroidLayoutFileChanges;
import rs.snpe.android.refactoring.changes.AndroidPackageRenameChange;

import com.android.ide.eclipse.adt.AndroidConstants;
import com.android.ide.eclipse.adt.internal.project.AndroidManifestParser;

/**
 * @author Sara
 *
 */
public class AndroidPackageRenameParticipant extends AndroidRenameParticipant {

    private IPackageFragment packageFragment;
    private boolean isPackage;
    private Set<AndroidLayoutFileChanges> fileChanges = new HashSet<AndroidLayoutFileChanges>();

    /* (non-Javadoc)
     * @see org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant#createChange(org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
        if (pm.isCanceled()) {
            return null;
        }
        if (!getArguments().getUpdateReferences())
            return null;
        IPath pkgPath = packageFragment.getPath();
        IJavaProject javaProject = (IJavaProject) packageFragment.getAncestor(IJavaElement.JAVA_PROJECT);
        IProject project = javaProject.getProject();
        IPath genPath = project.getFullPath().append(IConstants.FD_GEN_SOURCES);
        if (genPath.isPrefixOf(pkgPath)) {
            Activator.logInfo(getName() + ": Cannot rename generated package.");
            return null;
        }
        CompositeChange result = new CompositeChange(getName());
        if (androidManifest.exists()) {
            if (androidElements.size() > 0 || isPackage) {
                getDocument();
                Change change = new AndroidPackageRenameChange(androidManifest, manager, document, androidElements,
                        newName, oldName, isPackage);
                if (change != null) {
                    result.add(change);
                }
            }
            if (isPackage) {
                Change genChange = getGenPackageChange(pm);
                if (genChange != null) {
                    result.add(genChange);
                }
            }
            // add layoutChange
            for (AndroidLayoutFileChanges fileChange : fileChanges) {
                IFile file = fileChange.getFile();
                ITextFileBufferManager lManager = FileBuffers.getTextFileBufferManager();
                lManager.connect(file.getFullPath(), LocationKind.NORMALIZE, new NullProgressMonitor());
                ITextFileBuffer buffer = lManager.getTextFileBuffer(file.getFullPath(), LocationKind.NORMALIZE);
                IDocument lDocument = buffer.getDocument();
                Change layoutChange = new AndroidLayoutChange(file, lDocument, lManager, fileChange.getChanges());
                if (layoutChange != null) {
                    result.add(layoutChange);
                }
            }
        }
        return (result.getChildren().length == 0) ? null : result;
    }

    public Change getGenPackageChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
        if (isPackage) {
            IPackageFragment genJavaPackageFragment = getGenPackageFragment();
            if (genJavaPackageFragment != null && genJavaPackageFragment.exists()) {
                return new RenamePackageChange(genJavaPackageFragment, newName, true);
            }
        }
        return null;
    }

    private IPackageFragment getGenPackageFragment() throws JavaModelException {
        IJavaProject javaProject = (IJavaProject) packageFragment.getAncestor(IJavaElement.JAVA_PROJECT);
        if (javaProject != null && javaProject.isOpen()) {
            IProject project = javaProject.getProject();
            IFolder genFolder = project.getFolder(IConstants.FD_GEN_SOURCES);
            if (genFolder.exists()) {
                String javaPackagePath = javaPackage.replace(".", "/");
                IPath genJavaPackagePath = genFolder.getFullPath().append(javaPackagePath);
                IPackageFragment genPackageFragment = javaProject.findPackageFragment(genJavaPackagePath);
                return genPackageFragment;
            }
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant#getName()
     */
    @Override
    public String getName() {
        return "Android Package Rename";
    }

    /* (non-Javadoc)
     * @see org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant#initialize(java.lang.Object)
     */
    @Override
    protected boolean initialize(final Object element) {
        isPackage = false;
        try {
            if (element instanceof IPackageFragment) {
                packageFragment = (IPackageFragment) element;
                if (!packageFragment.containsJavaResources())
                    return false;
                IJavaProject javaProject = (IJavaProject) packageFragment.getAncestor(IJavaElement.JAVA_PROJECT);
                IProject project = javaProject.getProject();
                IResource manifestResource = project
                        .findMember(AndroidConstants.WS_SEP + AndroidConstants.FN_ANDROID_MANIFEST);

                if (manifestResource == null || !manifestResource.exists()
                        || !(manifestResource instanceof IFile)) {
                    Activator.logInfo("Invalid or missing the " + AndroidConstants.FN_ANDROID_MANIFEST + " in the "
                            + project.getName() + " project.");
                    return false;
                }
                androidManifest = (IFile) manifestResource;
                String packageName = packageFragment.getElementName();
                AndroidManifestParser parser;
                try {
                    parser = AndroidManifestParser.parseForData(androidManifest);
                } catch (CoreException e) {
                    Activator.logInfo("Invalid or missing the " + AndroidConstants.FN_ANDROID_MANIFEST + " in the "
                            + project.getName() + " project.");
                    return false;
                }
                javaPackage = parser.getPackage();
                oldName = packageName;
                newName = getArguments().getNewName();
                if (oldName == null || newName == null) {
                    return false;
                }

                if (javaPackage != null && javaPackage.equals(packageName)) {
                    isPackage = true;
                }
                androidElements = addAndroidElements();
                try {
                    final IType type = javaProject.findType(AndroidConstants.CLASS_VIEW);
                    SearchPattern pattern = SearchPattern.createPattern("*", IJavaSearchConstants.TYPE,
                            IJavaSearchConstants.DECLARATIONS, SearchPattern.R_REGEXP_MATCH);
                    IJavaSearchScope scope = SearchEngine
                            .createJavaSearchScope(new IJavaElement[] { packageFragment });
                    final HashSet<IType> elements = new HashSet<IType>();
                    SearchRequestor requestor = new SearchRequestor() {
                        public void acceptSearchMatch(SearchMatch match) throws CoreException {
                            Object elem = match.getElement();
                            if (elem instanceof IType) {
                                IType eType = (IType) elem;
                                IType[] superTypes = JavaModelUtil.getAllSuperTypes(eType,
                                        new NullProgressMonitor());
                                for (int i = 0; i < superTypes.length; i++) {
                                    if (superTypes[i].equals(type)) {
                                        elements.add(eType);
                                        break;
                                    }
                                }
                            }

                        }
                    };
                    SearchEngine searchEngine = new SearchEngine();
                    searchEngine.search(pattern,
                            new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, scope,
                            requestor, null);
                    List<String> views = new ArrayList<String>();
                    for (IType elem : elements) {
                        views.add(elem.getFullyQualifiedName());
                    }
                    if (views.size() > 0) {
                        String[] classNames = views.toArray(new String[0]);
                        addLayoutChanges(project, classNames);
                    }
                } catch (CoreException e) {
                    Activator.log(e);
                }

                return isPackage || androidElements.size() > 0 || fileChanges.size() > 0;
            }
        } catch (JavaModelException ignore) {
        }
        return false;
    }

    /**
     * @param project 
     * @param className
     * @return 
     */
    private void addLayoutChanges(IProject project, String[] classNames) {
        try {
            IFolder resFolder = project.getFolder(IConstants.FD_RESOURCES);
            IFolder layoutFolder = resFolder.getFolder(IConstants.FD_LAYOUT);
            IResource[] members = layoutFolder.members();
            for (int i = 0; i < members.length; i++) {
                IResource member = members[i];
                if ((member instanceof IFile) && member.exists()) {
                    IFile file = (IFile) member;
                    Set<AndroidLayoutChangeDescription> changes = parse(file, classNames);
                    if (changes.size() > 0) {
                        AndroidLayoutFileChanges fileChange = new AndroidLayoutFileChanges(file);
                        fileChange.getChanges().addAll(changes);
                        fileChanges.add(fileChange);
                    }
                }
            }
        } catch (CoreException e) {
            Activator.log(e);
        }
    }

    /**
     * @param file
     * @param className
     */
    private Set<AndroidLayoutChangeDescription> parse(IFile file, String[] classNames) {
        Set<AndroidLayoutChangeDescription> changes = new HashSet<AndroidLayoutChangeDescription>();
        ITextFileBufferManager lManager = null;
        try {
            lManager = FileBuffers.getTextFileBufferManager();
            lManager.connect(file.getFullPath(), LocationKind.NORMALIZE, new NullProgressMonitor());
            ITextFileBuffer buffer = lManager.getTextFileBuffer(file.getFullPath(), LocationKind.NORMALIZE);
            IDocument lDocument = buffer.getDocument();
            IStructuredModel model = null;
            try {
                model = StructuredModelManager.getModelManager().getExistingModelForRead(lDocument);
                if (model == null) {
                    if (lDocument instanceof IStructuredDocument) {
                        IStructuredDocument structuredDocument = (IStructuredDocument) lDocument;
                        model = StructuredModelManager.getModelManager().getModelForRead(structuredDocument);
                    }
                }
                if (model != null) {
                    IDOMModel xmlModel = (IDOMModel) model;
                    IDOMDocument xmlDoc = xmlModel.getDocument();
                    NodeList nodes = xmlDoc.getElementsByTagName(IConstants.ANDROID_LAYOUT_VIEW_ELEMENT);
                    for (int i = 0; i < nodes.getLength(); i++) {
                        Node node = nodes.item(i);
                        NamedNodeMap attributes = node.getAttributes();
                        if (attributes != null) {
                            Node attributeNode = attributes.getNamedItem(IConstants.ANDROID_LAYOUT_CLASS_ARGUMENT);
                            if (attributeNode != null || attributeNode instanceof Attr) {
                                Attr attribute = (Attr) attributeNode;
                                String value = attribute.getValue();
                                if (value != null) {
                                    for (int j = 0; j < classNames.length; j++) {
                                        String className = classNames[j];
                                        if (value.equals(className)) {
                                            String newClassName = getNewClassName(className);
                                            AndroidLayoutChangeDescription layoutChange = new AndroidLayoutChangeDescription(
                                                    className, newClassName,
                                                    AndroidLayoutChangeDescription.VIEW_TYPE);
                                            changes.add(layoutChange);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    for (int j = 0; j < classNames.length; j++) {
                        String className = classNames[j];
                        nodes = xmlDoc.getElementsByTagName(className);
                        for (int i = 0; i < nodes.getLength(); i++) {
                            String newClassName = getNewClassName(className);
                            AndroidLayoutChangeDescription layoutChange = new AndroidLayoutChangeDescription(
                                    className, newClassName, AndroidLayoutChangeDescription.STANDALONE_TYPE);
                            changes.add(layoutChange);
                        }
                    }
                }
            } finally {
                if (model != null) {
                    model.releaseFromRead();
                }
            }

        } catch (CoreException ignore) {
        } finally {
            if (lManager != null) {
                try {
                    lManager.disconnect(file.getFullPath(), LocationKind.NORMALIZE, new NullProgressMonitor());
                } catch (CoreException ignore) {
                }
            }
        }
        return changes;
    }

    private String getNewClassName(String className) {
        int lastDot = className.lastIndexOf(".");
        if (lastDot < 0) {
            return newName;
        }
        String name = className.substring(lastDot, className.length());
        String newClassName = newName + name;
        return newClassName;
    }

    /**
     * @return
     * @throws CoreException 
     */
    private Map<String, String> addAndroidElements() {
        Map<String, String> androidElements = new HashMap<String, String>();

        IDocument document;
        try {
            document = getDocument();
        } catch (CoreException e) {
            Activator.log(e);
            if (manager != null) {
                try {
                    manager.disconnect(androidManifest.getFullPath(), LocationKind.NORMALIZE,
                            new NullProgressMonitor());
                } catch (CoreException e1) {
                    Activator.log(e1);
                }
            }
            document = null;
            return androidElements;
        }

        IStructuredModel model = null;
        try {
            model = StructuredModelManager.getModelManager().getExistingModelForRead(document);
            if (model == null) {
                if (document instanceof IStructuredDocument) {
                    IStructuredDocument structuredDocument = (IStructuredDocument) document;
                    model = StructuredModelManager.getModelManager().getModelForRead(structuredDocument);
                }
            }
            if (model != null) {
                IDOMModel xmlModel = (IDOMModel) model;
                IDOMDocument xmlDoc = xmlModel.getDocument();
                add(xmlDoc, androidElements, IConstants.ANDROID_ACTIVITY_ELEMENT, IConstants.ANDROID_NAME_ARGUMENT);
                add(xmlDoc, androidElements, IConstants.ANDROID_APPLICATION_ELEMENT,
                        IConstants.ANDROID_NAME_ARGUMENT);
                add(xmlDoc, androidElements, IConstants.ANDROID_PROVIDER_ELEMENT, IConstants.ANDROID_NAME_ARGUMENT);
                add(xmlDoc, androidElements, IConstants.ANDROID_RECEIVER_ELEMENT, IConstants.ANDROID_NAME_ARGUMENT);
                add(xmlDoc, androidElements, IConstants.ANDROID_SERVICE_ELEMENT, IConstants.ANDROID_NAME_ARGUMENT);
            }
        } finally {
            if (model != null) {
                model.releaseFromRead();
            }
        }

        return androidElements;
    }

    /**
     * @param xmlDoc 
     * @param androidElements
     * @param androidActivityElement
     */
    private void add(IDOMDocument xmlDoc, Map<String, String> androidElements, String element, String argument) {
        NodeList nodes = xmlDoc.getElementsByTagName(element);
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            NamedNodeMap attributes = node.getAttributes();
            if (attributes != null) {
                Node attributeNode = attributes.getNamedItem(argument);
                if (attributeNode != null || attributeNode instanceof Attr) {
                    Attr attribute = (Attr) attributeNode;
                    String value = attribute.getValue();
                    if (value != null) {
                        String fullName = Activator.combinePackageAndClassName(javaPackage, value);
                        if (fullName != null && fullName.startsWith(javaPackage)) {
                            boolean startWithDot = (value.charAt(0) == '.');
                            boolean hasDot = (value.indexOf('.') != -1);
                            if (!startWithDot && hasDot) {
                                androidElements.put(element, value);
                            }
                        }
                    }
                }
            }
        }
    }

}