* Allow sigil.properties files to specify -singleton=true to cause bundles created by this project to be marked as singletons FELIX-1351
* Tidy up large methods into sub methods for readability



git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@798598 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sigil/common/core/src/org/apache/felix/sigil/bnd/BundleBuilder.java b/sigil/common/core/src/org/apache/felix/sigil/bnd/BundleBuilder.java
index 33a3a2d..806a74d 100644
--- a/sigil/common/core/src/org/apache/felix/sigil/bnd/BundleBuilder.java
+++ b/sigil/common/core/src/org/apache/felix/sigil/bnd/BundleBuilder.java
@@ -453,7 +453,9 @@
         // instructions we generate?
         spec.putAll( headers );
 
-        spec.setProperty( Constants.BUNDLE_SYMBOLICNAME, bundle.getSymbolicName() );
+        String sn = bundle.isSingleton() ? bundle.getSymbolicName() + ";singleton:=true" : bundle.getSymbolicName();
+        
+        spec.setProperty( Constants.BUNDLE_SYMBOLICNAME, sn );
         spec.setProperty( Constants.BUNDLE_VERSION, bundle.getVersion() );
 
         String activator = bundle.getActivator();
@@ -733,13 +735,50 @@
             omitUnusedImports = false;
         }
 
-        List<IPackageImport> imports = getImports( bundle );
-
         sb.setLength( 0 );
 
         // allow existing header;Package-Import to specify ignored packages
         sb.append( spec.getProperty( Constants.IMPORT_PACKAGE, "" ) );
 
+        buildImports(sb, getImports( bundle ));
+        
+        if ( sb.length() > 0 )
+        {
+            spec.setProperty( Constants.IMPORT_PACKAGE, sb.toString() );
+        }
+
+        sb.setLength( 0 );
+        
+        buildRequires(sb, bundle.getRequires());
+
+        if ( sb.length() > 0 )
+        {
+            spec.setProperty( Constants.REQUIRE_BUNDLE, sb.toString() );
+        }
+    }
+
+
+    /**
+     * @param sb
+     * @param list 
+     */
+    private void buildRequires( StringBuilder sb, List<IRequiredBundle> requires )
+    {
+        for ( IRequiredBundle rb : requires )
+        {
+            if ( sb.length() > 0 )
+                sb.append( "," );
+            sb.append( rb.getSymbolicName() );
+            addVersions( rb.getVersions(), sb );
+        }
+    }
+
+
+    /**
+     * @param sb
+     */
+    private void buildImports( StringBuilder sb, List<IPackageImport> imports )
+    {
         for ( IPackageImport pi : imports )
         {
             switch ( pi.getOSGiImport() )
@@ -789,22 +828,6 @@
                 sb.append( "," );
             sb.append( "*" );
         }
-
-        spec.setProperty( Constants.IMPORT_PACKAGE, sb.toString() );
-
-        sb.setLength( 0 );
-        for ( IRequiredBundle rb : bundle.getRequires() )
-        {
-            if ( sb.length() > 0 )
-                sb.append( "," );
-            sb.append( rb.getSymbolicName() );
-            addVersions( rb.getVersions(), sb );
-        }
-
-        if ( sb.length() > 0 )
-        {
-            spec.setProperty( Constants.REQUIRE_BUNDLE, sb.toString() );
-        }
     }
 
 
diff --git a/sigil/common/core/src/org/apache/felix/sigil/config/BldConfig.java b/sigil/common/core/src/org/apache/felix/sigil/config/BldConfig.java
index f51bdc4..08d4cca 100644
--- a/sigil/common/core/src/org/apache/felix/sigil/config/BldConfig.java
+++ b/sigil/common/core/src/org/apache/felix/sigil/config/BldConfig.java
@@ -43,11 +43,12 @@
     // string properties
     public static final String S_ACTIVATOR = "-activator";
     public static final String S_DEFAULTS = "-defaults";
+    public static final String S_SINGLETON = "-singleton";
     public static final String S_ID = "id";
     public static final String S_SYM_NAME = "name";
     public static final String S_VERSION = "version";
     public static final String[] STRING_KEYS =
-        { S_ACTIVATOR, S_DEFAULTS, S_ID, S_SYM_NAME, S_VERSION };
+        { S_ACTIVATOR, S_DEFAULTS, S_ID, S_SYM_NAME, S_VERSION, S_SINGLETON };
 
     // list properties
     public static final String L_COMPOSITES = "-composites";
diff --git a/sigil/common/core/src/org/apache/felix/sigil/config/BldConverter.java b/sigil/common/core/src/org/apache/felix/sigil/config/BldConverter.java
index 3c64efe..88a30c0 100644
--- a/sigil/common/core/src/org/apache/felix/sigil/config/BldConverter.java
+++ b/sigil/common/core/src/org/apache/felix/sigil/config/BldConverter.java
@@ -36,7 +36,6 @@
 import org.apache.felix.sigil.core.internal.model.eclipse.SigilBundle;
 import org.apache.felix.sigil.core.internal.model.osgi.BundleModelElement;
 import org.apache.felix.sigil.model.common.VersionRange;
-import org.apache.felix.sigil.model.eclipse.ISCAComposite;
 import org.apache.felix.sigil.model.eclipse.ISigilBundle;
 import org.apache.felix.sigil.model.osgi.IBundleModelElement;
 import org.apache.felix.sigil.model.osgi.IPackageExport;
@@ -272,23 +271,226 @@
     {
         IBundleModelElement info = bundle.getBundleInfo();
         String bundleVersion = config.getString( id, BldConfig.S_VERSION );
-
-        // exports
         Map<String, Map<String, String>> exports = new TreeMap<String, Map<String, String>>();
-        for ( IPackageExport export : info.getExports() )
+        
+        setSimpleHeaders(id, info);
+        setExports(id, bundleVersion, info, exports);
+        setImports(id, bundleVersion, info, exports);
+        setRequires(id, bundleVersion, info);
+        setFragments(id, info);
+        setContents(id, info, bundle);
+        setLibraries(id, info, bundle);
+        setResources(id, info, bundle);
+
+        if ( info.getSourceLocation() != null )
+        {
+            BldCore.error( "SourceLocation conversion not yet implemented." );
+        }
+
+        if ( !info.getLibraryImports().isEmpty() )
+        {
+            BldCore.error( "LibraryImports conversion not yet implemented." );
+        }
+    }
+
+
+    /**
+     * @param id
+     * @param info
+     */
+    private void setSimpleHeaders( String id, IBundleModelElement info )
+    {
+        List<String> ids = config.getList( null, BldConfig.C_BUNDLES );
+        String idBsn = id != null ? id : ids.get( 0 );
+        String oldBsn = config.getString( id, BldConfig.S_SYM_NAME );
+        String bsn = info.getSymbolicName();
+
+        if ( !bsn.equals( idBsn ) || oldBsn != null )
+            config.setString( id, BldConfig.S_SYM_NAME, bsn );
+
+        String version = info.getVersion().toString();
+        if ( version != null )
+            config.setString( id, BldConfig.S_VERSION, version );
+
+        String activator = info.getActivator();
+        if ( activator != null )
+            config.setString( id, BldConfig.S_ACTIVATOR, activator );
+
+        Properties headers = config.getProps( null, BldConfig.P_HEADER );
+
+        setHeader( headers, id, "CATEGORY", info.getCategory() );
+        setHeader( headers, id, Constants.BUNDLE_CONTACTADDRESS, info.getContactAddress() );
+        setHeader( headers, id, Constants.BUNDLE_COPYRIGHT, info.getCopyright() );
+        setHeader( headers, id, Constants.BUNDLE_DESCRIPTION, info.getDescription() );
+        setHeader( headers, id, Constants.BUNDLE_VENDOR, info.getVendor() );
+        setHeader( headers, id, Constants.BUNDLE_NAME, info.getName() );
+
+        if ( info.getDocURI() != null )
+            config.setProp( id, BldConfig.P_HEADER, Constants.BUNDLE_DOCURL, info.getDocURI().toString() );
+
+        if ( info.getLicenseURI() != null )
+            config.setProp( id, BldConfig.P_HEADER, Constants.BUNDLE_LICENSE, info.getLicenseURI().toString() );
+    }
+
+
+    /**
+     * @param id
+     * @param info
+     * @param bundle 
+     */
+    private void setResources( String id, IBundleModelElement info, ISigilBundle bundle )
+    {
+        // resources
+        ArrayList<String> resources = new ArrayList<String>();
+        for ( IPath ipath : bundle.getSourcePaths() )
+        {
+            resources.add( ipath.toString() );
+        }
+
+        if ( !resources.isEmpty() || !config.getList( id, BldConfig.L_RESOURCES ).isEmpty() )
+        {
+            Collections.sort( resources );
+            config.setList( id, BldConfig.L_RESOURCES, resources );
+        }
+    }
+
+
+    /**
+     * @param id 
+     * @param info
+     * @param bundle 
+     */
+    private void setLibraries( String id, IBundleModelElement info, ISigilBundle bundle )
+    {
+        // libs
+        Map<String, Map<String, String>> libs = new TreeMap<String, Map<String, String>>();
+        List<String> sources = new ArrayList<String>();
+
+        // classpathEntries map to -libs or -sources
+        for ( String entry : bundle.getClasspathEntrys() )
+        {
+            // <classpathentry kind="lib" path="lib/dependee.jar"/>
+            // <classpathentry kind="src" path="src"/>
+            final String regex = ".* kind=\"([^\"]+)\" path=\"([^\"]+)\".*";
+            Pattern pattern = Pattern.compile( regex );
+            Matcher matcher = pattern.matcher( entry );
+            if ( matcher.matches() )
+            {
+                String kind = matcher.group( 1 );
+                String path = matcher.group( 2 );
+                if ( kind.equals( "lib" ) )
+                {
+                    Map<String, String> map2 = new TreeMap<String, String>();
+                    map2.put( BldAttr.KIND_ATTRIBUTE, "classpath" );
+                    libs.put( path, map2 );
+                }
+                else if ( kind.equals( "src" ) )
+                {
+                    sources.add( path );
+                }
+                else
+                {
+                    BldCore.error( "unknown classpathentry kind=" + kind );
+                }
+            }
+            else
+            {
+                BldCore.error( "can't match classpathEntry in: " + entry );
+            }
+        }
+
+        if ( !libs.isEmpty() || !config.getMap( id, BldConfig.M_LIBS ).isEmpty() )
+        {
+            config.setMap( id, BldConfig.M_LIBS, libs );
+        }
+
+        if ( !sources.isEmpty() || !config.getList( id, BldConfig.L_SRC_CONTENTS ).isEmpty() )
+        {
+            config.setList( id, BldConfig.L_SRC_CONTENTS, sources );
+        }
+
+    }
+
+
+    /**
+     * @param id 
+     * @param info
+     * @param bundle 
+     */
+    private void setContents( String id, IBundleModelElement info, ISigilBundle bundle )
+    {
+        // contents
+        List<String> contents = new ArrayList<String>();
+        for ( String pkg : bundle.getPackages() )
+        {
+            contents.add( pkg );
+        }
+        if ( !contents.isEmpty() || !config.getList( id, BldConfig.L_CONTENTS ).isEmpty() )
+        {
+            config.setList( id, BldConfig.L_CONTENTS, contents );
+        }
+    }
+
+
+    /**
+     * @param id
+     * @param info
+     */
+    private void setFragments( String id, IBundleModelElement info )
+    {
+        Properties defaultBundles = config.getProps( null, BldConfig.P_BUNDLE_VERSION );
+        Map<String, Map<String, String>> fragments = new TreeMap<String, Map<String, String>>();
+        IRequiredBundle fragment = info.getFragmentHost();
+        if ( fragment != null )
         {
             Map<String, String> map2 = new TreeMap<String, String>();
-            String version = export.getVersion().toString();
-            if ( !version.equals( bundleVersion ) )
-                map2.put( BldAttr.VERSION_ATTRIBUTE, version );
-            exports.put( export.getPackageName(), map2 );
+            String name = fragment.getSymbolicName();
+            VersionRange versions = defaultVersion( fragment.getVersions(), defaultBundles.getProperty( name ) );
+            if ( versions != null )
+                map2.put( BldAttr.VERSION_ATTRIBUTE, versions.toString() );
+            fragments.put( name, map2 );
         }
-
-        if ( !exports.isEmpty() || !config.getMap( id, BldConfig.M_EXPORTS ).isEmpty() )
+        if ( !fragments.isEmpty() || !config.getMap( id, BldConfig.M_FRAGMENT ).isEmpty() )
         {
-            config.setMap( id, BldConfig.M_EXPORTS, exports );
+            config.setMap( id, BldConfig.M_FRAGMENT, fragments );
         }
+    }
 
+
+    /**
+     * @param id
+     * @param bundleVersion
+     * @param info
+     */
+    private void setRequires( String id, String bundleVersion, IBundleModelElement info )
+    {
+        // requires
+        Properties defaultBundles = config.getProps( null, BldConfig.P_BUNDLE_VERSION );
+        Map<String, Map<String, String>> requires = new TreeMap<String, Map<String, String>>();
+
+        for ( IRequiredBundle require : info.getRequiredBundles() )
+        {
+            Map<String, String> map2 = new TreeMap<String, String>();
+            String name = require.getSymbolicName();
+            VersionRange versions = defaultVersion( require.getVersions(), defaultBundles.getProperty( name ) );
+            if ( versions != null )
+                map2.put( BldAttr.VERSION_ATTRIBUTE, versions.toString() );
+            requires.put( name, map2 );
+        }
+        if ( !requires.isEmpty() || !config.getMap( id, BldConfig.M_REQUIRES ).isEmpty() )
+        {
+            config.setMap( id, BldConfig.M_REQUIRES, requires );
+        }
+    }
+
+
+    /**
+     * @param bundleVersion 
+     * @param info
+     * @param exports 
+     */
+    private void setImports( String id, String bundleVersion, IBundleModelElement info, Map<String, Map<String, String>> exports )
+    {
         // imports
         Map<String, Map<String, String>> imports = new TreeMap<String, Map<String, String>>();
 
@@ -344,182 +546,31 @@
         {
             config.setMap( id, BldConfig.M_IMPORTS, imports );
         }
+    }
 
-        // requires
-        Properties defaultBundles = config.getProps( null, BldConfig.P_BUNDLE_VERSION );
-        Map<String, Map<String, String>> requires = new TreeMap<String, Map<String, String>>();
 
-        for ( IRequiredBundle require : info.getRequiredBundles() )
+    /**
+     * @param id 
+     * @param info 
+     * @param bundleVersion 
+     * @param exports 
+     * 
+     */
+    private void setExports(String id, String bundleVersion, IBundleModelElement info, Map<String, Map<String, String>> exports)
+    {
+        for ( IPackageExport export : info.getExports() )
         {
             Map<String, String> map2 = new TreeMap<String, String>();
-            String name = require.getSymbolicName();
-            VersionRange versions = defaultVersion( require.getVersions(), defaultBundles.getProperty( name ) );
-            if ( versions != null )
-                map2.put( BldAttr.VERSION_ATTRIBUTE, versions.toString() );
-            requires.put( name, map2 );
+            String version = export.getVersion().toString();
+            if ( !version.equals( bundleVersion ) )
+                map2.put( BldAttr.VERSION_ATTRIBUTE, version );
+            exports.put( export.getPackageName(), map2 );
         }
-        if ( !requires.isEmpty() || !config.getMap( id, BldConfig.M_REQUIRES ).isEmpty() )
+
+        if ( !exports.isEmpty() || !config.getMap( id, BldConfig.M_EXPORTS ).isEmpty() )
         {
-            config.setMap( id, BldConfig.M_REQUIRES, requires );
+            config.setMap( id, BldConfig.M_EXPORTS, exports );
         }
-
-        // fragment
-        Map<String, Map<String, String>> fragments = new TreeMap<String, Map<String, String>>();
-        IRequiredBundle fragment = info.getFragmentHost();
-        if ( fragment != null )
-        {
-            Map<String, String> map2 = new TreeMap<String, String>();
-            String name = fragment.getSymbolicName();
-            VersionRange versions = defaultVersion( fragment.getVersions(), defaultBundles.getProperty( name ) );
-            if ( versions != null )
-                map2.put( BldAttr.VERSION_ATTRIBUTE, versions.toString() );
-            fragments.put( name, map2 );
-        }
-        if ( !fragments.isEmpty() || !config.getMap( id, BldConfig.M_FRAGMENT ).isEmpty() )
-        {
-            config.setMap( id, BldConfig.M_FRAGMENT, fragments );
-        }
-
-        // contents
-        List<String> contents = new ArrayList<String>();
-        for ( String pkg : bundle.getPackages() )
-        {
-            contents.add( pkg );
-        }
-        if ( !contents.isEmpty() || !config.getList( id, BldConfig.L_CONTENTS ).isEmpty() )
-        {
-            config.setList( id, BldConfig.L_CONTENTS, contents );
-        }
-
-        // dl contents
-        List<String> dlcontents = new ArrayList<String>();
-        for ( String pkg : bundle.getDownloadPackages() )
-        {
-            dlcontents.add( pkg );
-        }
-        if ( !dlcontents.isEmpty() || !config.getList( id, BldConfig.L_DL_CONTENTS ).isEmpty() )
-        {
-            config.setList( id, BldConfig.L_DL_CONTENTS, dlcontents );
-        }
-
-        // libs
-        Map<String, Map<String, String>> libs = new TreeMap<String, Map<String, String>>();
-        List<String> sources = new ArrayList<String>();
-
-        // classpathEntries map to -libs or -sources
-        for ( String entry : bundle.getClasspathEntrys() )
-        {
-            // <classpathentry kind="lib" path="lib/dependee.jar"/>
-            // <classpathentry kind="src" path="src"/>
-            final String regex = ".* kind=\"([^\"]+)\" path=\"([^\"]+)\".*";
-            Pattern pattern = Pattern.compile( regex );
-            Matcher matcher = pattern.matcher( entry );
-            if ( matcher.matches() )
-            {
-                String kind = matcher.group( 1 );
-                String path = matcher.group( 2 );
-                if ( kind.equals( "lib" ) )
-                {
-                    Map<String, String> map2 = new TreeMap<String, String>();
-                    map2.put( BldAttr.KIND_ATTRIBUTE, "classpath" );
-                    libs.put( path, map2 );
-                }
-                else if ( kind.equals( "src" ) )
-                {
-                    sources.add( path );
-                }
-                else
-                {
-                    BldCore.error( "unknown classpathentry kind=" + kind );
-                }
-            }
-            else
-            {
-                BldCore.error( "can't match classpathEntry in: " + entry );
-            }
-        }
-
-        if ( !libs.isEmpty() || !config.getMap( id, BldConfig.M_LIBS ).isEmpty() )
-        {
-            config.setMap( id, BldConfig.M_LIBS, libs );
-        }
-
-        if ( !sources.isEmpty() || !config.getList( id, BldConfig.L_SRC_CONTENTS ).isEmpty() )
-        {
-            config.setList( id, BldConfig.L_SRC_CONTENTS, sources );
-        }
-
-        // composites
-        ArrayList<String> composites = new ArrayList<String>();
-        for ( ISCAComposite composite : bundle.getComposites() )
-        {
-            String path = composite.getLocation().toString();
-            // TODO relativize
-            composites.add( path );
-        }
-
-        if ( !composites.isEmpty() || !config.getList( id, BldConfig.L_COMPOSITES ).isEmpty() )
-        {
-            Collections.sort( composites );
-            config.setList( id, BldConfig.L_COMPOSITES, composites );
-        }
-
-        // resources
-        ArrayList<String> resources = new ArrayList<String>();
-        for ( IPath ipath : bundle.getSourcePaths() )
-        {
-            resources.add( ipath.toString() );
-        }
-
-        if ( !resources.isEmpty() || !config.getList( id, BldConfig.L_RESOURCES ).isEmpty() )
-        {
-            Collections.sort( resources );
-            config.setList( id, BldConfig.L_RESOURCES, resources );
-        }
-
-        if ( info.getSourceLocation() != null )
-        {
-            BldCore.error( "SourceLocation conversion not yet implemented." );
-        }
-
-        if ( !info.getLibraryImports().isEmpty() )
-        {
-            BldCore.error( "LibraryImports conversion not yet implemented." );
-        }
-
-        ////////////////////
-        // simple headers
-
-        List<String> ids = config.getList( null, BldConfig.C_BUNDLES );
-        String idBsn = id != null ? id : ids.get( 0 );
-        String oldBsn = config.getString( id, BldConfig.S_SYM_NAME );
-        String bsn = info.getSymbolicName();
-
-        if ( !bsn.equals( idBsn ) || oldBsn != null )
-            config.setString( id, BldConfig.S_SYM_NAME, bsn );
-
-        String version = info.getVersion().toString();
-        if ( version != null )
-            config.setString( id, BldConfig.S_VERSION, version );
-
-        String activator = info.getActivator();
-        if ( activator != null )
-            config.setString( id, BldConfig.S_ACTIVATOR, activator );
-
-        Properties headers = config.getProps( null, BldConfig.P_HEADER );
-
-        setHeader( headers, id, "CATEGORY", info.getCategory() );
-        setHeader( headers, id, Constants.BUNDLE_CONTACTADDRESS, info.getContactAddress() );
-        setHeader( headers, id, Constants.BUNDLE_COPYRIGHT, info.getCopyright() );
-        setHeader( headers, id, Constants.BUNDLE_DESCRIPTION, info.getDescription() );
-        setHeader( headers, id, Constants.BUNDLE_VENDOR, info.getVendor() );
-        setHeader( headers, id, Constants.BUNDLE_NAME, info.getName() );
-
-        if ( info.getDocURI() != null )
-            config.setProp( id, BldConfig.P_HEADER, Constants.BUNDLE_DOCURL, info.getDocURI().toString() );
-
-        if ( info.getLicenseURI() != null )
-            config.setProp( id, BldConfig.P_HEADER, Constants.BUNDLE_LICENSE, info.getLicenseURI().toString() );
     }
 
 
diff --git a/sigil/common/core/src/org/apache/felix/sigil/config/BldProject.java b/sigil/common/core/src/org/apache/felix/sigil/config/BldProject.java
index f52c700..4501d7a 100644
--- a/sigil/common/core/src/org/apache/felix/sigil/config/BldProject.java
+++ b/sigil/common/core/src/org/apache/felix/sigil/config/BldProject.java
@@ -42,7 +42,6 @@
 import java.util.Properties;
 import java.util.TreeSet;
 
-import org.apache.felix.sigil.bnd.BundleBuilder;
 import org.apache.felix.sigil.core.internal.model.osgi.BundleModelElement;
 import org.apache.felix.sigil.core.internal.model.osgi.PackageExport;
 import org.apache.felix.sigil.core.internal.model.osgi.PackageImport;
@@ -53,8 +52,8 @@
 import org.apache.felix.sigil.model.osgi.IBundleModelElement;
 import org.apache.felix.sigil.model.osgi.IPackageExport;
 import org.apache.felix.sigil.model.osgi.IPackageImport;
-import org.apache.felix.sigil.model.osgi.IRequiredBundle;
 import org.apache.felix.sigil.model.osgi.IPackageImport.OSGiImport;
+import org.apache.felix.sigil.model.osgi.IRequiredBundle;
 import org.osgi.framework.Version;
 
 
@@ -182,6 +181,7 @@
                 }
 
                 Properties p = new Properties();
+                // FIXME stream not closed
                 p.load( url.openStream() );
                 dflt.merge( p );
 
@@ -430,6 +430,22 @@
         List<String> sourceContents = getSourcePkgs();
         HashSet<String> exports = new HashSet<String>();
 
+        parseExports(reqs, exports);
+        
+        parseImports(reqs, sourceContents, exports);
+        
+        parseRequires(reqs);
+        
+        return reqs;
+    }
+
+
+    /**
+     * @param reqs
+     * @param exports
+     */
+    private void parseExports( BundleModelElement reqs, HashSet<String> exports )
+    {
         for ( IBldBundle bundle : getBundles() )
         {
             for ( IPackageExport export : bundle.getExports() )
@@ -437,7 +453,62 @@
                 exports.add( export.getPackageName() );
             }
         }
+    }
 
+
+    /**
+     * @param reqs
+     * @throws IOException 
+     */
+    private void parseRequires( BundleModelElement reqs ) throws IOException
+    {
+        Map<String, Map<String, String>> requires = config.getMap( null, BldConfig.M_REQUIRES );
+        Properties bundleDefaults = config.getProps( null, BldConfig.P_BUNDLE_VERSION );
+
+        if ( requires != null )
+        {
+            for ( String name : requires.keySet() )
+            {
+                Map<String, String> attr = requires.get( name );
+                String versions = attr.containsKey( BldAttr.VERSION_ATTRIBUTE ) ? attr.get( BldAttr.VERSION_ATTRIBUTE )
+                    : bundleDefaults.getProperty( name );
+                String resolution = attr.get( BldAttr.RESOLUTION_ATTRIBUTE );
+
+                RequiredBundle rb = new RequiredBundle();
+                rb.setSymbolicName( name );
+                rb.setVersions( VersionRange.parseVersionRange( versions ) );
+
+                if ( BldAttr.RESOLUTION_OPTIONAL.equals( resolution ) )
+                {
+                    rb.setOptional( true );
+                }
+                else if ( resolution != null )
+                {
+                    throw new IOException( "Bad attribute value: " + BldAttr.RESOLUTION_ATTRIBUTE + "=" + resolution );
+                }
+
+                reqs.addRequiredBundle( rb );
+            }
+        }
+
+        for ( IBldBundle bundle : getBundles() )
+        {
+            IRequiredBundle fh = bundle.getFragmentHost();
+            if ( fh != null )
+                reqs.addRequiredBundle( fh );
+        }
+    }
+
+
+    /**
+     * @param reqs 
+     * @param exports 
+     * @param sourceContents 
+     * @throws IOException 
+     * 
+     */
+    private void parseImports(BundleModelElement reqs, List<String> sourceContents, HashSet<String> exports) throws IOException
+    {
         Map<String, Map<String, String>> imports = config.getMap( null, BldConfig.M_IMPORTS );
 
         for ( String name : imports.keySet() )
@@ -482,34 +553,6 @@
 
             reqs.addImport( pi );
         }
-
-        Map<String, Map<String, String>> requires = config.getMap( null, BldConfig.M_REQUIRES );
-        Properties bundleDefaults = config.getProps( null, BldConfig.P_BUNDLE_VERSION );
-
-        if ( requires != null )
-        {
-            for ( String name : requires.keySet() )
-            {
-                Map<String, String> attr = requires.get( name );
-                String versions = attr.containsKey( BldAttr.VERSION_ATTRIBUTE ) ? attr.get( BldAttr.VERSION_ATTRIBUTE )
-                    : bundleDefaults.getProperty( name );
-
-                RequiredBundle rb = new RequiredBundle();
-                rb.setSymbolicName( name );
-                rb.setVersions( VersionRange.parseVersionRange( versions ) );
-
-                reqs.addRequiredBundle( rb );
-            }
-        }
-
-        for ( IBldBundle bundle : getBundles() )
-        {
-            IRequiredBundle fh = bundle.getFragmentHost();
-            if ( fh != null )
-                reqs.addRequiredBundle( fh );
-        }
-
-        return reqs;
     }
 
 
@@ -809,6 +852,12 @@
         }
 
 
+        private boolean getBoolean( String key )
+        {
+            return Boolean.parseBoolean( getString( key ) );
+        }
+
+
         private List<String> getList( String key )
         {
             List<String> list = config.getList( id, key );
@@ -854,6 +903,12 @@
         }
 
 
+        public boolean isSingleton()
+        {
+            return getBoolean( BldConfig.S_SINGLETON );
+        }
+
+
         public List<IPackageExport> getExports()
         {
             ArrayList<IPackageExport> list = new ArrayList<IPackageExport>();
diff --git a/sigil/common/core/src/org/apache/felix/sigil/config/IBldProject.java b/sigil/common/core/src/org/apache/felix/sigil/config/IBldProject.java
index bc01b5a..e6cd340 100644
--- a/sigil/common/core/src/org/apache/felix/sigil/config/IBldProject.java
+++ b/sigil/common/core/src/org/apache/felix/sigil/config/IBldProject.java
@@ -233,5 +233,11 @@
          * resolves a relative path against the project file location.
          */
         File resolve( String path );
+
+
+        /**
+         * @return
+         */
+        boolean isSingleton();
     }
 }