add support for migration of imports/exports based on Move package refactoring (FELIX-1346)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@966638 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/ExportPackageChange.java b/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/ExportPackageChange.java
index 96b8c2e..b32ae68 100644
--- a/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/ExportPackageChange.java
+++ b/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/ExportPackageChange.java
@@ -60,8 +60,13 @@
     @Override
     public Change perform(IProgressMonitor progress) throws CoreException
     {   
-        sigil.getBundle().getBundleInfo().removeChild(oldExport);
-        sigil.getBundle().getBundleInfo().addExport(newExport);
+        if (oldExport != null) {
+            sigil.getBundle().getBundleInfo().removeChild(oldExport);
+        }
+        
+        if (newExport != null) {
+            sigil.getBundle().getBundleInfo().addExport(newExport);
+        }
         
         sigil.save(progress);
         
diff --git a/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/ImportPackageChange.java b/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/ImportPackageChange.java
index 289a2ac..53fbdce 100644
--- a/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/ImportPackageChange.java
+++ b/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/ImportPackageChange.java
@@ -53,8 +53,13 @@
     @Override
     public Change perform(IProgressMonitor progress) throws CoreException
     {
-        sigil.getBundle().getBundleInfo().removeImport(oldImport);
-        sigil.getBundle().getBundleInfo().addImport(newImport);
+        if (oldImport!=null) {
+            sigil.getBundle().getBundleInfo().removeImport(oldImport);
+        }
+        
+        if (newImport != null) {
+            sigil.getBundle().getBundleInfo().addImport(newImport);
+        }
         
         sigil.save(progress);
         
diff --git a/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/MovePackageParticipant.java b/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/MovePackageParticipant.java
new file mode 100644
index 0000000..bb98253
--- /dev/null
+++ b/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/MovePackageParticipant.java
@@ -0,0 +1,149 @@
+package org.apache.felix.sigil.ui.eclipse.refactor;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.sigil.eclipse.SigilCore;
+import org.apache.felix.sigil.eclipse.model.project.ISigilProjectModel;
+import org.apache.felix.sigil.eclipse.model.util.JavaHelper;
+import org.apache.felix.sigil.eclipse.model.util.ModelHelper;
+import org.apache.felix.sigil.model.ModelElementFactory;
+import org.apache.felix.sigil.model.osgi.IPackageExport;
+import org.apache.felix.sigil.model.osgi.IPackageImport;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.CompositeChange;
+import org.eclipse.ltk.core.refactoring.NullChange;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
+import org.eclipse.ltk.core.refactoring.participants.MoveParticipant;
+
+public class MovePackageParticipant extends MoveParticipant
+{
+    private IPackageFragment packageFragment;
+    private List<Change> changes = new LinkedList<Change>();
+
+    @Override
+    public RefactoringStatus checkConditions(IProgressMonitor monitor,
+        CheckConditionsContext context) throws OperationCanceledException
+    {
+        if (getArguments().getUpdateReferences()) {
+            try
+            {
+                ISigilProjectModel sourceProject = SigilCore.create(packageFragment.getJavaProject().getProject());
+                IPackageFragmentRoot dest = (IPackageFragmentRoot) getArguments().getDestination();
+                ISigilProjectModel destProject = SigilCore.create(dest.getJavaProject().getProject());
+                
+                RefactoringStatus status = new RefactoringStatus();
+                if ( !sourceProject.equals(destProject) ) {                    
+                    final String packageName = packageFragment.getElementName();
+                    IPackageExport oldExport = ModelHelper.findExport(sourceProject, packageName);
+                    
+                    if (oldExport != null) {
+                        IPackageExport newExport = ModelElementFactory.getInstance().newModelElement(IPackageExport.class);
+                        
+                        newExport.setPackageName(oldExport.getPackageName());
+                        newExport.setVersion(oldExport.getRawVersion());
+                        
+                        changes.add(new ExportPackageChange(destProject,null, newExport));
+                        changes.add(new ExportPackageChange(sourceProject, oldExport, null));
+                        
+                        status.addWarning("Package " + packageName + " is exported from " + sourceProject.getSymbolicName() + ", this may effect client bundles that use require bundle");
+                    }
+                    else {
+                        SubMonitor sub = SubMonitor.convert(monitor);
+                        
+                        Set<String> users = JavaHelper.findLocalPackageUsers(sourceProject, packageName, sub.newChild(100));
+                        Set<String> dependencies = JavaHelper.findLocalPackageDependencies(sourceProject, packageName, sub.newChild(100));
+
+                        if (users.size() > 0 && dependencies.size() > 0) {
+                            status.addWarning("Package " + packageName + " is coupled to " + users + " and " + dependencies + " this may cause a cyclical dependency");
+                        }
+                        
+                        if (users.size() > 0) { // attempt to move an API package
+                            IPackageExport newExport = createNewExport(status, destProject, packageName);
+                            createNewImport(status, sourceProject, newExport);
+                        }
+                        
+                        if (dependencies.size() > 0){ // moved an impl package
+                            for (String dep : dependencies) {
+                                IPackageExport newExport = createNewExport(status, sourceProject, dep);
+                                createNewImport(status, destProject, newExport);
+                            }
+                        }
+                    }
+                }
+                return status;
+            }
+            catch (CoreException e)
+            {
+                SigilCore.warn("Failed to create move refactor conditions", e);
+                throw new OperationCanceledException(e.getMessage());
+            }
+        }
+        else {
+            return new RefactoringStatus();
+        }
+    }
+
+    private void createNewImport(RefactoringStatus status,
+        ISigilProjectModel project, IPackageExport export)
+    {
+        IPackageImport newImport = ModelElementFactory.getInstance().newModelElement(IPackageImport.class);
+        newImport.setPackageName(export.getPackageName());
+        newImport.setVersions(ModelHelper.getDefaultRange(export.getVersion()));
+        
+        status.addInfo("Creating new import in " + project.getSymbolicName());
+        changes.add( new ImportPackageChange(project, null, newImport));                            
+    }
+
+    private IPackageExport createNewExport(RefactoringStatus status,
+        ISigilProjectModel project, String packageName)
+    {
+        IPackageExport newExport = ModelElementFactory.getInstance().newModelElement(IPackageExport.class);                            
+        newExport.setPackageName(packageName);                            
+        // new export inherits project version by default
+        newExport.setVersion(project.getVersion());
+        
+        status.addInfo("Creating new export " + packageName + " in " + project.getSymbolicName());
+        changes.add( new ExportPackageChange(project, null, newExport));
+        return newExport;
+    }
+
+    @Override
+    public Change createChange(IProgressMonitor monitor) throws CoreException,
+        OperationCanceledException
+    {
+        if (changes.isEmpty()) {
+            return new NullChange();
+        }
+        else 
+        {
+            CompositeChange ret = new CompositeChange("Export-Package update");
+            
+            ret.addAll(changes.toArray(new Change[changes.size()]));
+            
+            return ret;
+        }
+    }
+
+    @Override
+    public String getName()
+    {
+        return "Sigil package move participant";
+    }
+
+    @Override
+    protected boolean initialize(Object element)
+    {
+        this.packageFragment = (IPackageFragment) element;
+        return true;
+    }
+
+}
diff --git a/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/RenamePackageParticipant.java b/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/RenamePackageParticipant.java
index 43ff150..dbe39c7 100644
--- a/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/RenamePackageParticipant.java
+++ b/sigil/eclipse/ui/src/org/apache/felix/sigil/ui/eclipse/refactor/RenamePackageParticipant.java
@@ -6,6 +6,7 @@
 
 import org.apache.felix.sigil.eclipse.SigilCore;
 import org.apache.felix.sigil.eclipse.model.project.ISigilProjectModel;
+import org.apache.felix.sigil.eclipse.model.util.ModelHelper;
 import org.apache.felix.sigil.model.IModelElement;
 import org.apache.felix.sigil.model.IModelWalker;
 import org.apache.felix.sigil.model.ModelElementFactory;
@@ -37,57 +38,44 @@
     {   
         RefactoringStatus status = new RefactoringStatus();
         
-        try
-        {
-            ISigilProjectModel sigil = SigilCore.create(packageFragment.getJavaProject().getProject());
-            final String packageName = packageFragment.getElementName();
-            
-            SigilCore.log("Rename checkConditions " + packageName);
-            
-            final IPackageExport[] found = new IPackageExport[1];
-            sigil.visit(new IModelWalker()
-            {            
-                public boolean visit(IModelElement element)
-                {
-                    if (element instanceof IPackageExport) {
-                        IPackageExport pe = (IPackageExport) element;
-                        if (pe.getPackageName().equals(packageName)) {
-                            found[0] = pe;
+        if (getArguments().getUpdateReferences()) {
+            try
+            {
+                ISigilProjectModel sigil = SigilCore.create(packageFragment.getJavaProject().getProject());
+                final String packageName = packageFragment.getElementName();
+                
+                SigilCore.log("Rename checkConditions " + packageName);
+                
+                IPackageExport oldExport = ModelHelper.findExport(sigil, packageName);
+                
+                if (oldExport != null) {
+                    // record change to check if out of sync...
+                    touch(context, sigil);
+                                
+                    status = RefactoringStatus.createWarningStatus("Package " + packageName + " is exported. Renaming this package may effect bundles outside of this workspace");
+                    SigilCore.log("Export Package " + packageName + " renamed to " + getArguments().getNewName());
+    
+                    IPackageExport newExport = ModelElementFactory.getInstance().newModelElement(IPackageExport.class);
+                    newExport.setPackageName(getArguments().getNewName());
+                    newExport.setVersion(oldExport.getVersion());
+    
+                    changes.add(new ExportPackageChange(sigil, oldExport, newExport));                    
+    
+                    for ( ISigilProjectModel other : SigilCore.getRoot().getProjects() ) {
+                        if ( !sigil.equals(other) ) {
+                            // record change to check if out of sync...
+                            touch(context, other);
                         }
+                        changes.add(createImportChange(status, other, oldExport, newExport));
                     }
-                    return found[0] == null;
-                }
-            });
-            
-            if (found[0] != null) {
-                // record change to check if out of sync...
-                touch(context, sigil);
-                            
-                status = RefactoringStatus.createWarningStatus("Package " + packageName + " is exported. Renaming this package may effect bundles outside of this workspace");
-                SigilCore.log("Export Package " + packageName + " renamed to " + getArguments().getNewName());
-
-                IPackageExport oldExport = found[0];
-                IPackageExport newExport = ModelElementFactory.getInstance().newModelElement(IPackageExport.class);
-                newExport.setPackageName(getArguments().getNewName());
-                newExport.setVersion(oldExport.getVersion());
-
-                changes.add(new ExportPackageChange(sigil, oldExport, newExport));                    
-
-                for ( ISigilProjectModel other : SigilCore.getRoot().getProjects() ) {
-                    if ( !sigil.equals(other) ) {
-                        // record change to check if out of sync...
-                        touch(context, other);
-                    }
-                    changes.add(createImportChange(status, other, oldExport, newExport));
                 }
             }
-        }
-        catch (CoreException e)
-        {
-            SigilCore.warn("Failed to create export package refactor", e);
-            throw new OperationCanceledException("Failed to create export package refactor");
-        }
-        
+            catch (CoreException e)
+            {
+                SigilCore.warn("Failed to create export package refactor", e);
+                throw new OperationCanceledException("Failed to create export package refactor");
+            }
+        }        
         return status;
     }