patches for FELIX-2576 and FELIX-2575 - tidy up empty headers in headers file and allow bsn to be different to project name


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@992256 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/model/project/SigilProject.java b/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/model/project/SigilProject.java
index 1138a84..b4a759c 100644
--- a/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/model/project/SigilProject.java
+++ b/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/internal/model/project/SigilProject.java
@@ -64,7 +64,6 @@
 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.Path;
 import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.jdt.core.ClasspathContainerInitializer;
@@ -118,8 +117,17 @@
     {
         SubMonitor progress = SubMonitor.convert(monitor, 1000);
 
-        bldProjectFile.setContents(buildContents(), IFile.KEEP_HISTORY,
-            progress.newChild(10));
+        if (bldProjectFile.getLocation().toFile().exists())
+        {
+            bldProjectFile.setContents(buildContents(), IFile.KEEP_HISTORY,
+                progress.newChild(10));
+        }
+        else
+        {
+            bldProjectFile.create(buildContents(), true /* force */,
+                progress.newChild(5));
+            project.refreshLocal(IResource.DEPTH_ONE, progress.newChild(5));
+        }
 
         if (rebuildDependencies)
         {
@@ -354,32 +362,28 @@
 
         try
         {
-            boolean newProject = false;
-
             synchronized (bldProjectFile)
             {
                 if (bundle == null)
-                {
-                    if (bldProjectFile.getLocation().toFile().exists())
+                {                   
+                    IPath loc = bldProjectFile.getLocation();
+                    if (loc == null) {
+                        // callers can protect against this by using 
+                        // checking exists()
+                        throw new IllegalStateException("Sigil project does not exist");
+                    }
+                    else if (loc.toFile().exists())
                     {
                         bundle = parseContents(bldProjectFile);
                     }
                     else
                     {
                         bundle = setupDefaults();
-                        newProject = true;
                     }
                 }
 
                 b = bundle;
             }
-
-            if (newProject)
-            {
-                NullProgressMonitor npm = new NullProgressMonitor();
-                bldProjectFile.create(buildContents(), true /* force */, npm);
-                project.refreshLocal(IResource.DEPTH_ONE, npm);
-            }
         }
         catch (CoreException e)
         {
@@ -427,7 +431,8 @@
     @Override
     public int hashCode()
     {
-        int hc = getSymbolicName().hashCode();
+        String bsn = getSymbolicName();
+        int hc = bsn == null ? 1 : bsn.hashCode();
         if (getVersion() != null)
         {
             hc *= getVersion().hashCode();
@@ -591,7 +596,6 @@
             ISigilBundle.class);
         IBundleModelElement info = ModelElementFactory.getInstance().newModelElement(
             IBundleModelElement.class);
-        info.setSymbolicName(project.getName());
         bundle.setBundleInfo(info);
         bundle.setParent(this);
         return bundle;
@@ -716,4 +720,12 @@
     {
         return SigilCore.getRepositoryManager(this);
     }
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.sigil.eclipse.model.project.ISigilProjectModel#exists()
+     */
+    public boolean exists()
+    {
+        return project.exists() && project.getFile(IBldProject.PROJECT_FILE).exists();
+    }
 }
diff --git a/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/model/project/ISigilProjectModel.java b/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/model/project/ISigilProjectModel.java
index 8fc7cba..a57f098 100644
--- a/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/model/project/ISigilProjectModel.java
+++ b/sigil/eclipse/core/src/org/apache/felix/sigil/eclipse/model/project/ISigilProjectModel.java
@@ -125,4 +125,9 @@
      * @throws CoreException 
      */
     IRepositoryManager getRepositoryManager();
+
+    /**
+     * @return
+     */
+    boolean exists();
 }
diff --git a/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/internal/classpath/SigilClassPathContainer.java b/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/internal/classpath/SigilClassPathContainer.java
index 3edab69..802e9e8 100644
--- a/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/internal/classpath/SigilClassPathContainer.java
+++ b/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/internal/classpath/SigilClassPathContainer.java
@@ -91,7 +91,9 @@
         try
         {
             IProgressMonitor monitor = ThreadProgressMonitor.getProgressMonitor();
-            entries = sigil.findExternalClasspath(monitor).toArray(new IClasspathEntry[0]);
+            if (sigil.exists()) {
+                entries = sigil.findExternalClasspath(monitor).toArray(new IClasspathEntry[0]);
+            }
         }
         catch (CoreException e)
         {
diff --git a/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/wizard/project/SigilProjectWizardFirstPage.java b/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/wizard/project/SigilProjectWizardFirstPage.java
index 19fdd13..c11ce93 100644
--- a/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/wizard/project/SigilProjectWizardFirstPage.java
+++ b/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/wizard/project/SigilProjectWizardFirstPage.java
@@ -20,7 +20,6 @@
 package org.apache.felix.sigil.eclipse.ui.wizard.project;
 
 import org.apache.felix.sigil.common.osgi.VersionTable;
-import org.apache.felix.sigil.eclipse.ui.internal.views.RepositoryViewPart;
 import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.IPath;
@@ -31,8 +30,11 @@
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.ModifyEvent;
 import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Group;
 import org.eclipse.swt.widgets.Label;
@@ -47,23 +49,27 @@
 public class SigilProjectWizardFirstPage extends WizardNewProjectCreationPage
 {
 
-    private volatile String description = "";
-    private volatile Version version = VersionTable.getVersion(1, 0, 0);
-    private volatile String vendor = "";
-    private volatile String name = "";
+    private volatile String bsn;
+    private volatile String description;
+    private volatile Version version;
+    private volatile String vendor;
+    private volatile String name;
 
+    private Button customBSN;
+    private Text txtBSN;
     private Text txtDescription;
     private Text txtVersion;
     private Text txtVendor;
     private Text txtName;
+    private boolean initialized;
 
     public SigilProjectWizardFirstPage()
     {
         super("newSigilProjectPage");
         setTitle("Sigil Project");
         setDescription("Create a new Sigil project");
-        setImageDescriptor(ImageDescriptor.createFromFile(RepositoryViewPart.class,
-            "/icons/logo64x64.gif"));
+        setImageDescriptor(ImageDescriptor.createFromFile(
+            SigilProjectWizardFirstPage.class, "/icons/logo64x64.gif"));
     }
 
     public boolean isInWorkspace()
@@ -85,15 +91,27 @@
     @Override
     public void createControl(Composite parent)
     {
-        FieldDecoration infoDecor = FieldDecorationRegistry.getDefault().getFieldDecoration(
-            FieldDecorationRegistry.DEC_INFORMATION);
-
         // Create controls
         super.createControl(parent);
         Composite control = (Composite) getControl();
 
+        Group grpProjectSettings = buildComponents(control);
+        setDefaultValues();
+        initListeners();
+        doLayout(control, grpProjectSettings);
+        initialized = true;
+    }
+
+    private Group buildComponents(Composite control)
+    {
         Group grpProjectSettings = new Group(control, SWT.NONE);
-        grpProjectSettings.setText("Project Settings");
+        grpProjectSettings.setText("OSGi Bundle Settings");
+
+        new Label(grpProjectSettings, SWT.NONE).setText("Symbolic Name:");
+        txtBSN = new Text(grpProjectSettings, SWT.BORDER);
+        txtBSN.setEnabled(false);
+        customBSN = new Button(grpProjectSettings, SWT.CHECK | SWT.RIGHT);
+        customBSN.setText("Custom");
 
         new Label(grpProjectSettings, SWT.NONE).setText("Version:");
         txtVersion = new Text(grpProjectSettings, SWT.BORDER);
@@ -101,76 +119,149 @@
         new Label(grpProjectSettings, SWT.NONE).setText("Name:");
         txtName = new Text(grpProjectSettings, SWT.BORDER);
 
+        new Label(grpProjectSettings, SWT.NONE).setText("Description:");
+        txtDescription = new Text(grpProjectSettings, SWT.BORDER);
+
+        new Label(grpProjectSettings, SWT.NONE).setText("Provider:");
+        txtVendor = new Text(grpProjectSettings, SWT.BORDER);
+
+        decorateComponents();
+        
+        return grpProjectSettings;
+    }
+
+    /**
+     * 
+     */
+    private void decorateComponents()
+    {
+        FieldDecoration infoDecor = FieldDecorationRegistry.getDefault().getFieldDecoration(
+            FieldDecorationRegistry.DEC_INFORMATION);
+
+        ControlDecoration txtBSNDecor = new ControlDecoration(txtBSN, SWT.LEFT
+            | SWT.CENTER);
+        txtBSNDecor.setImage(infoDecor.getImage());
+        txtBSNDecor.setDescriptionText("The unique name of this bundle - should follow reverse domain name pattern");
+        
+        ControlDecoration txtVersionDecor = new ControlDecoration(txtVersion, SWT.LEFT
+            | SWT.CENTER);
+        txtVersionDecor.setImage(infoDecor.getImage());
+        txtVersionDecor.setDescriptionText("The version of this bundle");
+        
         ControlDecoration txtNameDecor = new ControlDecoration(txtName, SWT.LEFT
             | SWT.CENTER);
         txtNameDecor.setImage(infoDecor.getImage());
         txtNameDecor.setDescriptionText("Defines a human-readable name for the bundle");
 
-        new Label(grpProjectSettings, SWT.NONE).setText("Description:");
-        txtDescription = new Text(grpProjectSettings, SWT.BORDER);
-
         ControlDecoration txtDescDecor = new ControlDecoration(txtDescription, SWT.LEFT
             | SWT.CENTER);
         txtDescDecor.setImage(infoDecor.getImage());
         txtDescDecor.setDescriptionText("Defines a short human-readable description for the bundle");
 
-        new Label(grpProjectSettings, SWT.NONE).setText("Provider:");
-        txtVendor = new Text(grpProjectSettings, SWT.BORDER);
-
         ControlDecoration txtVendorDecor = new ControlDecoration(txtVendor, SWT.LEFT
             | SWT.CENTER);
         txtVendorDecor.setImage(infoDecor.getImage());
         txtVendorDecor.setDescriptionText("The name of the company, organisation or individual providing the bundle");
+    }
 
-        // Set values
-        txtDescription.setText(description);
+    private void setDefaultValues()
+    {
+        version = VersionTable.getVersion(1, 0, 0);
         txtVersion.setText(version.toString());
-        txtVendor.setText(vendor);
-        txtName.setText(name);
+    }
 
+    private void initListeners()
+    {
         // Add listeners
         ModifyListener txtModListener = new ModifyListener()
         {
             public void modifyText(ModifyEvent e)
             {
-                description = txtDescription.getText();
-                vendor = txtVendor.getText();
-                name = txtName.getText();
-
-                validateSettings();
+                validatePage();
             }
         };
+
+        customBSN.addSelectionListener(new SelectionAdapter()
+        {
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                txtBSN.setEnabled(customBSN.getSelection());
+                validatePage();
+            }
+        });
+        
+        txtBSN.addModifyListener(txtModListener);
         txtDescription.addModifyListener(txtModListener);
         txtVersion.addModifyListener(txtModListener);
         txtVendor.addModifyListener(txtModListener);
         txtName.addModifyListener(txtModListener);
-
-        // Layout
-        control.setLayout(new GridLayout());
-        grpProjectSettings.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-        grpProjectSettings.setLayout(new GridLayout(2, false));
-        txtDescription.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-        txtVersion.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-        txtVendor.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-        txtName.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
     }
 
-    private void validateSettings()
+    private void doLayout(Composite control, Group grpProjectSettings)
     {
-        try
-        {
-            version = VersionTable.getVersion(txtVersion.getText());
-        }
-        catch (IllegalArgumentException e)
-        {
-            version = null;
-            setErrorMessage("Invalid version");
-            setPageComplete(false);
-            return;
-        }
+        control.setLayout(new GridLayout());
+        grpProjectSettings.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+        grpProjectSettings.setLayout(new GridLayout(3, false));
+        txtBSN.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+        customBSN.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
+        txtDescription.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+        txtVersion.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+        txtVendor.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+        txtName.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+    }
 
-        setErrorMessage(null);
-        setPageComplete(true);
+    @Override
+    protected boolean validatePage()
+    {
+        readValues();
+        if ( super.validatePage() ) {
+            if (getBundleSymbolicName() == null)
+            {
+                setErrorMessage("Invalid bundle symbolic name");
+                setPageComplete(false);
+                return false;
+            }
+    
+            if (getVersion() == null)
+            {
+                setErrorMessage("Invalid version");
+                setPageComplete(false);
+                return false;
+            }
+    
+            // ok all must be fine...
+            setErrorMessage(null);
+            setPageComplete(true);
+        }
+        
+        return true;
+    }
+
+    private static final ThreadLocal<Object> reentrant = new ThreadLocal<Object>();
+    private static final Object REENTRANCE = new Object();
+    
+    /**
+     * 
+     */
+    private void readValues()
+    {
+        if ( initialized && reentrant.get() != REENTRANCE ) {
+            if ( customBSN.getSelection() ) {
+                bsn = nullIfEmpty(txtBSN.getText());
+            }
+            else {
+                bsn = getProjectName();
+                reentrant.set(REENTRANCE);
+                txtBSN.setText(bsn);
+                reentrant.set(null);
+            }
+            
+            description = nullIfEmpty(txtDescription.getText());
+            name = nullIfEmpty(txtName.getText());
+            vendor = nullIfEmpty(txtVendor.getText());
+            version = nullIfInvalidVersion(txtVersion.getText());
+        }
     }
 
     public Version getVersion()
@@ -188,8 +279,39 @@
         return description;
     }
 
+    public String getBundleSymbolicName()
+    {
+        return bsn;
+    }
+
     public String getName()
     {
         return name;
     }
+
+    // utility methods
+    private static String nullIfEmpty(String str)
+    {
+        return str == null ? null : (str.trim().length() == 0 ? null : str.trim());
+    }
+
+    private static Version nullIfInvalidVersion(String text)
+    {
+        Version version = null;
+        try
+        {
+            String v = nullIfEmpty(text);
+            if (v != null)
+            {
+                version = VersionTable.getVersion(v);
+            }
+        }
+        catch (IllegalArgumentException e)
+        {
+            // fine version is invalid - handled by validateSettings
+        }
+
+        return version;
+    }
+
 }
diff --git a/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/wizard/project/SigilProjectWizardSecondPage.java b/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/wizard/project/SigilProjectWizardSecondPage.java
index 90c434a..e451213 100644
--- a/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/wizard/project/SigilProjectWizardSecondPage.java
+++ b/sigil/eclipse/ui/src/org/apache/felix/sigil/eclipse/ui/wizard/project/SigilProjectWizardSecondPage.java
@@ -87,12 +87,16 @@
     protected void performFinish(IProgressMonitor monitor) throws CoreException,
         InterruptedException
     {
-        changeToNewProject();
-        updateProject(monitor);
+        boolean updated = changeToNewProject();
+        if (!updated)
+        {
+            updateProject(monitor);
+        }
     }
 
-    private void changeToNewProject()
+    private boolean changeToNewProject()
     {
+        boolean updated = false;
         if (!created)
         {
             IWorkspace workspace = ResourcesPlugin.getWorkspace();
@@ -114,16 +118,20 @@
 
             try
             {
-                workspace.run(op, Job.getJobManager().createProgressGroup());
+                workspace.run(op, workspace.getRoot(), IWorkspace.AVOID_UPDATE,
+                    Job.getJobManager().createProgressGroup());
                 setErrorMessage(null);
                 setPageComplete(true);
                 created = true;
+                updated = true;
             }
             catch (CoreException e)
             {
                 SigilCore.error("Failed to run workspace job", e);
             }
         }
+
+        return updated;
     }
 
     private void removeProject()
@@ -163,6 +171,7 @@
         currentProject = firstPage.getProjectHandle();
         currentProjectLocation = getProjectLocationURI();
 
+        String bsn = firstPage.getBundleSymbolicName();
         String description = firstPage.getDescription();
         Version projectVersion = firstPage.getVersion();
         String vendor = firstPage.getVendor();
@@ -187,8 +196,8 @@
 
         configureJavaProject(new SubProgressMonitor(monitor, 3));
 
-        configureSigilProject(currentProject, description, projectVersion, vendor, name,
-            src, monitor);
+        configureSigilProject(currentProject, bsn, description, projectVersion, vendor,
+            name, src, monitor);
     }
 
     private IPath createSourcePath() throws CoreException
@@ -262,10 +271,16 @@
         return defaultJRELibrary;
     }
 
-    private void configureSigilProject(IProject project, String description,
+    private void configureSigilProject(IProject project, String bsn, String description,
         Version projectVersion, String vendorName, String bundleName, IPath src,
         IProgressMonitor monitor) throws CoreException
     {
+        if (bsn == null)
+        {
+            throw SigilCore.newCoreException("Expected bundle symbolic name to be set",
+                null);
+        }
+        
         ISigilProjectModel sigil = SigilCore.create(project);
         IClasspathEntry cp = JavaCore.newSourceEntry(src);
         String encodedClasspath = sigil.getJavaModel().encodeClasspathEntry(cp);
@@ -273,6 +288,8 @@
         ISigilBundle bundle = sigil.getBundle();
         bundle.addClasspathEntry(encodedClasspath);
 
+        // fine set up other values
+        bundle.getBundleInfo().setSymbolicName(bsn);
         if (description != null)
         {
             bundle.getBundleInfo().setDescription(description);