EMMA Coverage Report (generated Thu Nov 26 15:54:18 CST 2009)
[all classes][org.eclipse.pde.api.tools.internal.model]

COVERAGE SUMMARY FOR SOURCE FILE [BundleApiComponent.java]

nameclass, %method, %block, %line, %
BundleApiComponent.java100% (1/1)87%  (40/46)64%  (1354/2104)64%  (319.8/496)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class BundleApiComponent100% (1/1)87%  (40/46)64%  (1354/2104)64%  (319.8/496)
extractDirectory (ZipFile, String, File): void 0%   (0/1)0%   (0/47)0%   (0/13)
getBooleanOption (Map, String, boolean): boolean 0%   (0/1)0%   (0/12)0%   (0/4)
getFileInBundle (File, String): URL 0%   (0/1)0%   (0/61)0%   (0/12)
isApiEnabled (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
readManifest (File): Manifest 0%   (0/1)0%   (0/77)0%   (0/17)
toString (): String 0%   (0/1)0%   (0/66)0%   (0/11)
getLowestEEs (): String [] 100% (1/1)12%  (32/263)18%  (9/51)
dispose (): void 100% (1/1)44%  (17/39)48%  (3.4/7)
getBundleDescription (): BundleDescription 100% (1/1)60%  (6/10)67%  (2/3)
hasFragments (): boolean 100% (1/1)62%  (10/16)59%  (1.8/3)
getExecutionEnvironments (): String [] 100% (1/1)64%  (7/11)67%  (2/3)
closingZipFileAndStream (InputStream, ZipFile): void 100% (1/1)65%  (11/17)56%  (5/9)
extractEntry (ZipFile, ZipEntry, File): File 100% (1/1)67%  (57/85)62%  (14.9/24)
createApiTypeContainer (String): IApiTypeContainer 100% (1/1)67%  (113/168)66%  (23/35)
containsSourceExtensionPoint (String): boolean 100% (1/1)73%  (35/48)53%  (9/17)
isFragment (): boolean 100% (1/1)73%  (11/15)67%  (2/3)
getManifest (): Dictionary 100% (1/1)77%  (17/22)60%  (3/5)
isSourceComponent (): boolean 100% (1/1)78%  (47/60)69%  (11/16)
init (long): void 100% (1/1)80%  (49/61)83%  (10/12)
loadManifest (File): Map 100% (1/1)81%  (72/89)73%  (14.6/20)
getHost (): IApiComponent 100% (1/1)81%  (17/21)83%  (5/6)
readFileContents (String, File): String 100% (1/1)81%  (73/90)73%  (14.6/20)
getErrors (): ResolverError [] 100% (1/1)81%  (22/27)78%  (7/9)
createApiTypeContainers (): List 100% (1/1)87%  (142/164)86%  (36/42)
hasApiDescription (): boolean 100% (1/1)88%  (7/8)67%  (2/3)
createLocalApiDescription (): IApiDescription 100% (1/1)88%  (36/41)78%  (7/9)
getRequiredComponents (): IRequiredComponentDescription [] 100% (1/1)91%  (42/46)91%  (10/11)
loadApiDescription (File): String 100% (1/1)92%  (78/85)88%  (17.6/20)
<static initializer> 100% (1/1)100% (20/20)100% (6/6)
BundleApiComponent (IApiBaseline, String): void 100% (1/1)100% (16/16)100% (6/6)
addSuppliedPackages (Set, List, ExportPackageDescription []): void 100% (1/1)100% (30/30)100% (8/8)
annotateExportedPackages (IApiDescription, ExportPackageDescription []): void 100% (1/1)100% (76/76)100% (20/20)
baselineDisposed (IApiBaseline): void 100% (1/1)100% (15/15)100% (7/7)
createApiDescription (): IApiDescription 100% (1/1)100% (52/52)100% (10/10)
createApiFilterStore (): IApiFilterStore 100% (1/1)100% (2/2)100% (1/1)
doManifestCompaction (): void 100% (1/1)100% (35/35)100% (8/8)
getClasspathEntries (Dictionary): String [] 100% (1/1)100% (41/41)100% (8/8)
getId (): String 100% (1/1)100% (3/3)100% (1/1)
getLocalPackageNames (): Set 100% (1/1)100% (53/53)100% (10/10)
getLocation (): String 100% (1/1)100% (3/3)100% (1/1)
getVersion (): String 100% (1/1)100% (4/4)100% (1/1)
initializeApiDescription (IApiDescription, BundleDescription, Set): void 100% (1/1)100% (78/78)100% (17/17)
isBinaryBundle (): boolean 100% (1/1)100% (2/2)100% (1/1)
isSystemComponent (): boolean 100% (1/1)100% (2/2)100% (1/1)
isValidBundle (): boolean 100% (1/1)100% (17/17)100% (2/2)
setHasApiDescription (boolean): void 100% (1/1)100% (4/4)100% (2/2)

1/*******************************************************************************
2 * Copyright (c) 2007, 2009 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *     IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.pde.api.tools.internal.model;
12 
13import java.io.BufferedReader;
14import java.io.File;
15import java.io.FileInputStream;
16import java.io.FileOutputStream;
17import java.io.IOException;
18import java.io.InputStream;
19import java.io.StringReader;
20import java.net.MalformedURLException;
21import java.net.URL;
22import java.util.ArrayList;
23import java.util.Dictionary;
24import java.util.Enumeration;
25import java.util.HashSet;
26import java.util.Hashtable;
27import java.util.Iterator;
28import java.util.List;
29import java.util.Map;
30import java.util.Set;
31import java.util.jar.JarFile;
32import java.util.jar.Manifest;
33import java.util.zip.ZipEntry;
34import java.util.zip.ZipFile;
35 
36import javax.xml.parsers.FactoryConfigurationError;
37import javax.xml.parsers.ParserConfigurationException;
38import javax.xml.parsers.SAXParser;
39import javax.xml.parsers.SAXParserFactory;
40 
41import org.eclipse.core.runtime.CoreException;
42import org.eclipse.core.runtime.IStatus;
43import org.eclipse.core.runtime.Path;
44import org.eclipse.core.runtime.Status;
45import org.eclipse.osgi.service.resolver.BundleDescription;
46import org.eclipse.osgi.service.resolver.BundleSpecification;
47import org.eclipse.osgi.service.resolver.ExportPackageDescription;
48import org.eclipse.osgi.service.resolver.HostSpecification;
49import org.eclipse.osgi.service.resolver.ResolverError;
50import org.eclipse.osgi.service.resolver.StateObjectFactory;
51import org.eclipse.osgi.util.ManifestElement;
52import org.eclipse.osgi.util.NLS;
53import org.eclipse.pde.api.tools.internal.ApiBaselineManager;
54import org.eclipse.pde.api.tools.internal.ApiDescription;
55import org.eclipse.pde.api.tools.internal.ApiDescriptionProcessor;
56import org.eclipse.pde.api.tools.internal.BundleVersionRange;
57import org.eclipse.pde.api.tools.internal.CompositeApiDescription;
58import org.eclipse.pde.api.tools.internal.IApiCoreConstants;
59import org.eclipse.pde.api.tools.internal.RequiredComponentDescription;
60import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
61import org.eclipse.pde.api.tools.internal.provisional.Factory;
62import org.eclipse.pde.api.tools.internal.provisional.IApiAccess;
63import org.eclipse.pde.api.tools.internal.provisional.IApiDescription;
64import org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore;
65import org.eclipse.pde.api.tools.internal.provisional.IRequiredComponentDescription;
66import org.eclipse.pde.api.tools.internal.provisional.ProfileModifiers;
67import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers;
68import org.eclipse.pde.api.tools.internal.provisional.descriptors.IPackageDescriptor;
69import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline;
70import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
71import org.eclipse.pde.api.tools.internal.provisional.model.IApiElement;
72import org.eclipse.pde.api.tools.internal.provisional.model.IApiTypeContainer;
73import org.eclipse.pde.api.tools.internal.util.FileManager;
74import org.eclipse.pde.api.tools.internal.util.SourceDefaultHandler;
75import org.eclipse.pde.api.tools.internal.util.Util;
76import org.eclipse.pde.internal.core.TargetWeaver;
77import org.osgi.framework.BundleException;
78import org.osgi.framework.Constants;
79import org.osgi.framework.Version;
80import org.xml.sax.InputSource;
81import org.xml.sax.SAXException;
82 
83/**
84 * Implementation of an API component based on a bundle in the file system.
85 * 
86 * @since 1.0.0
87 */
88public class BundleApiComponent extends AbstractApiComponent {
89        
90        static final String TMP_API_FILE_PREFIX = "api"; //$NON-NLS-1$
91        static final String TMP_API_FILE_POSTFIX = "tmp"; //$NON-NLS-1$
92        
93        /**
94         * Dictionary parsed from MANIFEST.MF
95         */
96        private Dictionary fManifest;
97        
98        /**
99         * Manifest headers that are maintained after {@link BundleDescription} creation.
100         * Only these headers are maintained in the manifest dictionary to reduce footprint.  
101         */
102        private static final String[] MANIFEST_HEADERS = new String[] {
103                IApiCoreConstants.ECLIPSE_SOURCE_BUNDLE,
104                Constants.BUNDLE_CLASSPATH,
105                Constants.BUNDLE_NAME,
106                Constants.BUNDLE_VERSION
107        };
108        
109        /**
110         * Whether there is an underlying .api_description file
111         */
112        private boolean fHasApiDescription = false;
113        
114        /**
115         * Root location of component in the file system
116         */
117        private String fLocation;
118        
119        /**
120         * Underlying bundle description (OSGi model of a bundle)
121         */
122        private BundleDescription fBundleDescription;
123        
124        /**
125         * Symbolic name of this bundle
126         */
127        private String fSymbolicName = null;
128        
129        /**
130         * Bundle version
131         */
132        private Version fVersion = null;
133        
134        /**
135         * Cached value for the lowest EEs
136         */
137        private String[] lowestEEs;
138 
139        /**
140         * Constructs a new API component from the specified location in the file system
141         * in the given profile.
142         * 
143         * @param profile owning profile
144         * @param location directory or jar file
145         * @exception CoreException if unable to create a component from the specified location
146         */
147        public BundleApiComponent(IApiBaseline profile, String location) throws CoreException {
148                super(profile);
149                fLocation = location;
150        }
151        
152        /* (non-Javadoc)
153         * @see org.eclipse.pde.api.tools.internal.descriptors.AbstractApiComponent#dispose()
154         */
155        public void dispose() {
156                try {
157                        super.dispose();
158                } finally {
159                        synchronized(this) {
160                                fManifest = null;
161                                fBundleDescription = null;
162                        }
163                }
164        }
165        
166        /**
167         * Returns this bundle's manifest as a dictionary.
168         * 
169         * @return manifest dictionary
170         * @exception CoreException if something goes terribly wrong
171         */
172        protected synchronized Dictionary getManifest() throws CoreException {
173                if(fManifest == null) {
174                        try {
175                                fManifest = (Dictionary) loadManifest(new File(fLocation));
176                        } catch (IOException e) {
177                                abort("Unable to load manifest due to IO error", e); //$NON-NLS-1$
178                        }
179                }
180                return fManifest;
181        }
182 
183        /**
184         * Reduce the manifest to only contain required headers after {@link BundleDescription} creation.
185         */
186        protected synchronized void doManifestCompaction() throws CoreException {
187                Dictionary temp = fManifest;
188                fManifest = new Hashtable(MANIFEST_HEADERS.length);
189                for (int i = 0; i < MANIFEST_HEADERS.length; i++) {
190                        String header = MANIFEST_HEADERS[i];
191                        Object value = temp.get(header);
192                        if (value != null) {
193                                fManifest.put(header, value);
194                        }
195                }
196        }
197        
198        /**
199         * Returns if the bundle at the specified location is a valid bundle or not.
200         * Validity is determined via the existence of a readable manifest file
201         * @param location
202         * @return true if the bundle at the given location is valid false otherwise
203         * @throws IOException
204         */
205        public boolean isValidBundle() throws CoreException {
206                Dictionary manifest = getManifest();
207                return manifest != null && (manifest.get(Constants.BUNDLE_NAME) != null && manifest.get(Constants.BUNDLE_VERSION) != null);
208        }
209        
210        /**
211         * Initializes component state from the underlying bundle for the given
212         * state.
213         * 
214         * @param state PDE state
215         * @throws CoreException on failure
216         */
217        protected synchronized void init(long bundleId) throws CoreException {
218                try {
219                        Dictionary manifest = getManifest();
220                        if (isBinaryBundle() && ApiBaselineManager.WORKSPACE_API_BASELINE_ID.equals(getBaseline().getName())) {
221                                // must account for bundles in development mode - look for class files in output
222                                // folders rather than jars
223                                TargetWeaver.weaveManifest(manifest);
224                        }
225                        StateObjectFactory factory = StateObjectFactory.defaultFactory;
226                        fBundleDescription = factory.createBundleDescription(((ApiBaseline)getBaseline()).getState(), manifest, fLocation, bundleId);
227                        fSymbolicName = fBundleDescription.getSymbolicName();
228                        fVersion = fBundleDescription.getVersion();
229                        setName((String)getManifest().get(Constants.BUNDLE_NAME));
230                } catch (BundleException e) {
231                        abort("Unable to create API component from specified location: " + fLocation, e); //$NON-NLS-1$
232                }
233                // compact manifest after initialization - only keep used headers
234                doManifestCompaction();
235        }
236        
237        /**
238         * Returns whether this API component represents a binary bundle versus a project bundle.
239         * 
240         * @return whether this API component represents a binary bundle
241         */
242        protected boolean isBinaryBundle() {
243                return true;
244        }
245        
246        /* (non-Javadoc)
247         * @see org.eclipse.pde.api.tools.internal.AbstractApiComponent#createApiDescription()
248         */
249        protected IApiDescription createApiDescription() throws CoreException {
250                BundleDescription[] fragments = getBundleDescription().getFragments();
251                if (fragments.length == 0) {
252                        return createLocalApiDescription();
253                }
254                // build a composite description
255                IApiDescription[] descriptions = new IApiDescription[fragments.length + 1];
256                for (int i = 0; i < fragments.length; i++) {
257                        BundleDescription fragment = fragments[i];
258                        BundleApiComponent component = (BundleApiComponent) getBaseline().getApiComponent(fragment.getSymbolicName());
259                        descriptions[i + 1] = component.getApiDescription();
260                }
261                descriptions[0] = createLocalApiDescription();
262                return new CompositeApiDescription(descriptions);
263        }
264 
265        /**
266         * Creates and returns this component's API description based on packages
267         * supplied by this component, exported packages, and associated directives.
268         * 
269         * @return API description
270         * @throws CoreException if unable to initialize 
271         */
272        protected IApiDescription createLocalApiDescription() throws CoreException {
273                IApiDescription apiDesc = new ApiDescription(getId());
274                // first mark all packages as internal
275                initializeApiDescription(apiDesc, getBundleDescription(), getLocalPackageNames());
276                try {
277                        String xml = loadApiDescription(new File(fLocation));
278                        setHasApiDescription(xml != null);
279                        if (xml != null) {
280                                ApiDescriptionProcessor.annotateApiSettings(null, apiDesc, xml);
281                        }
282                } catch (IOException e) {
283                        abort("Unable to load .api_description file ", e); //$NON-NLS-1$
284                }
285                return apiDesc;
286        }
287        
288        /**
289         * Returns the names of all packages that originate from this bundle.
290         * Does not include packages that originate from fragments or a host.
291         * 
292         * @return local package names
293         * @throws CoreException
294         */
295        protected Set getLocalPackageNames() throws CoreException {
296                Set names = new HashSet();
297                IApiTypeContainer[] containers = getApiTypeContainers();
298                IApiComponent comp = null;
299                for (int i = 0; i < containers.length; i++) {
300                        comp = (IApiComponent) containers[i].getAncestor(IApiElement.COMPONENT);
301                        if (comp != null && comp.getId().equals(getId())) {
302                                String[] packageNames = containers[i].getPackageNames();
303                                for (int j = 0; j < packageNames.length; j++) {
304                                        names.add(packageNames[j]);
305                                }
306                        }
307                }
308                return names;
309        }        
310        
311 
312        /**
313         * Initializes the given API description based on package exports in the manifest.
314         * The API description for a bundle only contains packages that originate from
315         * this bundle (so a host will not contain API descriptions for packages that
316         * originate from fragments). However, a host's API description will be represented
317         * by a proxy that delegates to the host and all of its fragments to provide
318         * a complete description of the host.
319         * 
320         * @param apiDesc API description to initialize
321         * @param bundle the bundle to load from
322         * @param packages the complete set of packages names originating from the backing
323         *                 component
324         * @throws CoreException if an error occurs
325         */
326        public static void initializeApiDescription(IApiDescription apiDesc, BundleDescription bundle, Set packages) throws CoreException {
327                Iterator iterator = packages.iterator();
328                while (iterator.hasNext()) {
329                        String name = (String) iterator.next();
330                        apiDesc.setVisibility(Factory.packageDescriptor(name), VisibilityModifiers.PRIVATE);
331                }
332                // then process exported packages that originate from this bundle
333                // considering host and fragment package exports
334                List supplied = new ArrayList();
335                ExportPackageDescription[] exportPackages = bundle.getExportPackages();
336                addSuppliedPackages(packages, supplied, exportPackages);
337                HostSpecification host = bundle.getHost();
338                if (host != null) {
339                        BundleDescription[] hosts = host.getHosts();
340                        for (int i = 0; i < hosts.length; i++) {
341                                addSuppliedPackages(packages, supplied, hosts[i].getExportPackages());
342                        }
343                }
344                BundleDescription[] fragments = bundle.getFragments();
345                for (int i = 0; i < fragments.length; i++) {
346                        addSuppliedPackages(packages, supplied, fragments[i].getExportPackages());
347                }
348                
349                annotateExportedPackages(apiDesc, (ExportPackageDescription[]) supplied.toArray(new ExportPackageDescription[supplied.size()]));
350        }
351 
352        /**
353         * Adds package exports to the given list if the associated package originates
354         * from this bundle.
355         *   
356         * @param packages names of packages supplied by this bundle
357         * @param supplied list to append package exports to
358         * @param exportPackages package exports to consider
359         */
360        protected static void addSuppliedPackages(Set packages, List supplied, ExportPackageDescription[] exportPackages) {
361                for (int i = 0; i < exportPackages.length; i++) {
362                        ExportPackageDescription pkg = exportPackages[i];
363                        String name = pkg.getName();
364                        if (name.equals(".")) { //$NON-NLS-1$
365                                // translate . to default package
366                                name = Util.DEFAULT_PACKAGE_NAME;
367                        }
368                        if (packages.contains(name)) {
369                                supplied.add(pkg);
370                        }
371                }
372        }
373        
374        /**
375         * Annotates the API description with exported packages.
376         * 
377         * @param apiDesc description to annotate
378         * @param exportedPackages packages that are exported
379         */
380        protected static void annotateExportedPackages(IApiDescription apiDesc, ExportPackageDescription[] exportedPackages) {
381                for(int i = 0; i < exportedPackages.length; i++) {
382                        ExportPackageDescription pkg = exportedPackages[i];
383                        boolean internal = ((Boolean) pkg.getDirective("x-internal")).booleanValue(); //$NON-NLS-1$
384                        String[] friends = (String[]) pkg.getDirective("x-friends"); //$NON-NLS-1$
385                        String pkgName = pkg.getName();
386                        if (pkgName.equals(".")) { //$NON-NLS-1$
387                                // default package
388                                pkgName = ""; //$NON-NLS-1$
389                        }
390                        IPackageDescriptor pkgDesc = Factory.packageDescriptor(pkgName);
391                        if(internal) {
392                                apiDesc.setVisibility(pkgDesc, VisibilityModifiers.PRIVATE);
393                        }
394                        if (friends != null) {
395                                apiDesc.setVisibility(pkgDesc, VisibilityModifiers.PRIVATE);
396                                for(int j = 0; j < friends.length; j++) {
397                                        //annotate the api description for x-friends access levels
398                                        apiDesc.setAccessLevel(
399                                                        Factory.componentDescriptor(friends[j]), 
400                                                        Factory.packageDescriptor(pkgName), 
401                                                        IApiAccess.FRIEND);
402                                }
403                        }
404                        if (!internal && friends == null) {
405                                //there could have been directives that have nothing to do with
406                                //visibility, so we need to add the package as API in that case
407                                apiDesc.setVisibility(pkgDesc, VisibilityModifiers.API);
408                        }
409                }
410        }
411        
412        /* (non-Javadoc)
413         * @see org.eclipse.pde.api.tools.internal.AbstractApiComponent#createApiFilterStore()
414         */
415        protected IApiFilterStore createApiFilterStore() throws CoreException {
416                //always return a new empty store since we do not support filtering from bundles
417                return null;
418        }
419        
420        /**
421         * @see org.eclipse.pde.api.tools.internal.AbstractApiTypeContainer#createApiTypeContainers()
422         */
423        protected synchronized List createApiTypeContainers() throws CoreException {
424                if (this.fBundleDescription == null) {
425                        baselineDisposed(getBaseline());
426                }
427                List containers = new ArrayList(5);
428                try {
429                        List all = new ArrayList();
430                        // build the classpath from bundle and all fragments
431                        all.add(this);
432                        boolean considerFragments = true;
433                        if (Util.ORG_ECLIPSE_SWT.equals(getId())) {
434                                // if SWT is a project to be built/analyzed don't consider its fragments
435                                considerFragments = !isApiEnabled();
436                        }
437                        if (considerFragments) { 
438                                BundleDescription[] fragments = fBundleDescription.getFragments();
439                                for (int i = 0; i < fragments.length; i++) {
440                                        BundleDescription fragment = fragments[i];
441                                        BundleApiComponent component = (BundleApiComponent) getBaseline().getApiComponent(fragment.getSymbolicName());
442                                        if (component != null) {
443                                                // force initialization of the fragment so we can retrieve its class file containers
444                                                component.getApiTypeContainers();
445                                                all.add(component);
446                                        }
447                                }
448                        }
449                        Iterator iterator = all.iterator();
450                        Set entryNames = new HashSet(5);
451                        BundleApiComponent other = null;
452                        while (iterator.hasNext()) {
453                                BundleApiComponent component = (BundleApiComponent) iterator.next();
454                                String[] paths = getClasspathEntries(component.getManifest());
455                                for (int i = 0; i < paths.length; i++) {
456                                        String path = paths[i];
457                                        // don't re-process the same entry twice (except default entries ".")
458                                        if (!(".".equals(path))) { //$NON-NLS-1$
459                                                if (entryNames.contains(path)) {
460                                                        continue;
461                                                }
462                                        }
463                                        IApiTypeContainer container = component.createApiTypeContainer(path);
464                                        if (container == null) {
465                                                for(Iterator iter = all.iterator(); iter.hasNext();) {
466                                                        other = (BundleApiComponent) iter.next();
467                                                        if (other != component) {
468                                                                container = other.createApiTypeContainer(path);
469                                                        }
470                                                }
471                                        }
472                                        if (container != null) {
473                                                containers.add(container);
474                                                if (!(".".equals(path))) { //$NON-NLS-1$
475                                                        entryNames.add(path);
476                                                }
477                                        }
478                                }
479                        }
480                } catch (BundleException e) {
481                        abort("Unable to parse bundle classpath", e); //$NON-NLS-1$
482                } catch (IOException e) {
483                        abort("Unable to initialize class file containers", e); //$NON-NLS-1$
484                }
485                return containers;
486        }
487        
488        /**
489         * Returns whether this API component is enabled for API analysis by the API builder.
490         * 
491         * @return whether this API component is enabled for API analysis by the API builder.
492         */
493        protected boolean isApiEnabled() {
494                return false;
495        }
496        
497        /**
498         * Returns classpath entries defined in the given manifest.
499         * 
500         * @param manifest
501         * @return classpath entries as bundle relative paths
502         * @throws BundleException
503         */
504        protected String[] getClasspathEntries(Dictionary manifest) throws BundleException {
505                ManifestElement[] classpath = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, (String) manifest.get(Constants.BUNDLE_CLASSPATH));
506                String elements[] = null;
507                if (classpath == null) {
508                        // default classpath is '.'
509                        elements = new String[]{"."}; //$NON-NLS-1$
510                } else {
511                        elements = new String[classpath.length];
512                        for (int i = 0; i < classpath.length; i++) {
513                                elements[i] = classpath[i].getValue();
514                        }
515                }
516                return elements;
517        }
518        
519        /**
520         * Creates and returns an {@link IApiTypeContainer} at the specified path in
521         * this bundle, or <code>null</code> if the {@link IApiTypeContainer} does not
522         * exist. The path is the name (path) of entries specified by the
523         * <code>Bundle-ClassPath:</code> header.
524         * 
525         * @param path relative path to a class file container in this bundle
526         * @return {@link IApiTypeContainer} or <code>null</code>
527         * @exception IOException
528         */
529        protected IApiTypeContainer createApiTypeContainer(String path) throws IOException, CoreException {
530                File bundle = new File(fLocation);
531                if (bundle.isDirectory()) {
532                        // bundle is folder
533                        File entry = new File(bundle, path);
534                        if (entry.exists()) {
535                                if (entry.isFile()) {
536                                        return new ArchiveApiTypeContainer(this, entry.getCanonicalPath());
537                                } else {
538                                        return new DirectoryApiTypeContainer(this, entry.getCanonicalPath());
539                                }
540                        }
541                } else {
542                        // bundle is jar'd
543                        ZipFile zip = null;
544                        try {
545                                if (path.equals(".")) { //$NON-NLS-1$
546                                        return new ArchiveApiTypeContainer(this, fLocation);
547                                } else {
548                                        //classpath element can be jar or folder
549                                        //https://bugs.eclipse.org/bugs/show_bug.cgi?id=279729
550                                        zip = new ZipFile(fLocation);
551                                        ZipEntry entry = zip.getEntry(path);
552                                        if (entry != null) {
553                                                File tmpfolder = new File(System.getProperty("java.io.tmpdir")); //$NON-NLS-1$
554                                                if(entry.isDirectory()) {
555                                                        //extract the dir and all children
556                                                        File dir = File.createTempFile(TMP_API_FILE_PREFIX, TMP_API_FILE_POSTFIX);
557                                                        dir.deleteOnExit();
558                                                        //hack to create a temp directory
559                                                        // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4735419
560                                                        if(dir.delete()) {
561                                                                dir.mkdir();
562                                                                FileManager.getManager().recordTempFileRoot(dir.getCanonicalPath());
563                                                        }
564                                                        extractDirectory(zip, entry.getName(), dir);
565                                                        if(dir.isDirectory() && dir.exists()) {
566                                                                return new DirectoryApiTypeContainer(this, dir.getCanonicalPath());
567                                                        }
568                                                }
569                                                else {
570                                                        File file = extractEntry(zip, entry, tmpfolder);
571                                                        if(Util.isArchive(file.getName())) {
572                                                                File parent = file.getParentFile();
573                                                                if(!parent.equals(tmpfolder)) {
574                                                                        FileManager.getManager().recordTempFileRoot(parent.getCanonicalPath());
575                                                                }
576                                                                else {
577                                                                        FileManager.getManager().recordTempFileRoot(file.getCanonicalPath());
578                                                                }
579                                                                return new ArchiveApiTypeContainer(this, file.getCanonicalPath());
580                                                        }
581                                                }
582                                        }
583                                }
584                        } finally {
585                                if (zip != null) {
586                                        zip.close();
587                                }
588                        }
589                }
590                return null;
591        }
592                
593        /**
594         * Extracts a directory from the archive given a path prefix for entries to retrieve.
595         * <code>null</code> can be passed in as a prefix, causing all entries to be be extracted from 
596         * the archive.
597         * 
598         * @param zip the {@link ZipFile} to extract from
599         * @param pathprefix the prefix'ing path to include for extraction
600         * @param parent the parent directory to extract to
601         * @throws IOException if the {@link ZipFile} cannot be read or extraction fails to write the file(s)
602         */
603        void extractDirectory(ZipFile zip, String pathprefix, File parent) throws IOException {
604                Enumeration entries = zip.entries();
605                String prefix = (pathprefix == null ? Util.EMPTY_STRING : pathprefix);
606                ZipEntry entry = null;
607                File file = null;
608                while (entries.hasMoreElements()) {
609                        entry = (ZipEntry) entries.nextElement();
610                        if(entry.getName().startsWith(prefix)) {
611                                file = new File(parent, entry.getName());
612                                if (entry.isDirectory()) {
613                                        file.mkdir();
614                                        continue;
615                                }
616                                extractEntry(zip, entry, parent);
617                        }
618                }
619        }
620        
621        /**
622         * Extracts a non-directory entry from a zip file and returns the File handle
623         * @param zip the zip to extract from
624         * @param entry the entry to extract
625         * @param parent the parent directory to add the extracted entry to
626         * @return the file handle to the extracted entry, <code>null</code> otherwise
627         * @throws IOException
628         */
629        File extractEntry(ZipFile zip, ZipEntry entry, File parent) throws IOException {
630                InputStream inputStream = null;
631                File file;
632                FileOutputStream outputStream = null;
633                try {
634                        inputStream = zip.getInputStream(entry);
635                        file = new File(parent, entry.getName());
636                        File lparent = file.getParentFile();
637                        if(!lparent.exists()) {
638                                lparent.mkdirs();
639                        }
640                        outputStream = new FileOutputStream(file);
641                        byte[] bytes = new byte[8096];
642                        while (inputStream.available() > 0) {
643                                int read = inputStream.read(bytes);
644                                if (read > 0) {
645                                        outputStream.write(bytes, 0, read);
646                                }
647                        }
648                } finally {
649                        if (inputStream != null) {
650                                try {
651                                        inputStream.close();
652                                } catch(IOException e) {
653                                        ApiPlugin.log(e);
654                                }
655                        }
656                        if (outputStream != null) {
657                                try {
658                                        outputStream.close();
659                                } catch(IOException e) {
660                                        ApiPlugin.log(e);
661                                }
662                        }
663                }
664                return file;
665        }
666        
667        /**
668         * Parses a bunlde's manifest into a dictionary. The bundle may be in a jar
669         * or in a directory at the specified location.
670         * 
671         * @param bundleLocation root location of the bundle
672         * @return bundle manifest dictionary or <code>null</code> if none
673         * @throws IOException if unable to parse
674         */
675        protected Map loadManifest(File bundleLocation) throws IOException {
676                ZipFile jarFile = null;
677                InputStream manifestStream = null;
678                String extension = new Path(bundleLocation.getName()).getFileExtension();
679                try {
680                        if (extension != null && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$
681                                jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
682                                ZipEntry manifestEntry = jarFile.getEntry(JarFile.MANIFEST_NAME);
683                                if (manifestEntry != null) {
684                                        manifestStream = jarFile.getInputStream(manifestEntry);
685                                }
686                        } else {
687                                File file = new File(bundleLocation, JarFile.MANIFEST_NAME);
688                                if (file.exists())
689                                        manifestStream = new FileInputStream(file);
690                        }
691                        if (manifestStream == null) {
692                                return null;
693                        }
694                        return ManifestElement.parseBundleManifest(manifestStream, new Hashtable(10));
695                } catch (BundleException e) {
696                        ApiPlugin.log(e);
697                } finally {
698                        closingZipFileAndStream(manifestStream, jarFile);
699                }
700                return null;
701        }
702        
703        /**
704         * Reads and returns this bunlde's manifest in a Manifest object.
705         * The bundle may be in a jar or in a directory at the specified location.
706         * 
707         * @param bundleLocation root location of the bundle
708         * @return manifest or <code>null</code> if not present
709         * @throws IOException if unable to parse
710         */
711        protected Manifest readManifest(File bundleLocation) throws IOException {
712                ZipFile jarFile = null;
713                InputStream manifestStream = null;
714                try {
715                        String extension = new Path(bundleLocation.getName()).getFileExtension();
716                        if (extension != null && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$
717                                jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
718                                ZipEntry manifestEntry = jarFile.getEntry(JarFile.MANIFEST_NAME);
719                                if (manifestEntry != null) {
720                                        manifestStream = jarFile.getInputStream(manifestEntry);
721                                }
722                        } else {
723                                File file = new File(bundleLocation, JarFile.MANIFEST_NAME);
724                                if (file.exists())
725                                        manifestStream = new FileInputStream(file);
726                        }
727                        if (manifestStream == null) {
728                                return null;
729                        }
730                        return new Manifest(manifestStream);
731                } finally {
732                        closingZipFileAndStream(manifestStream, jarFile);
733                }
734        }
735 
736        void closingZipFileAndStream(InputStream stream, ZipFile jarFile) {
737                try {
738                        if (stream != null) {
739                                stream.close();
740                        }
741                } catch (IOException e) {
742                        ApiPlugin.log(e);
743                }
744                try {
745                        if (jarFile != null) {
746                                jarFile.close();
747                        }
748                } catch (IOException e) {
749                        ApiPlugin.log(e);
750                }
751        }
752        
753        /**
754         * Reads and returns the file contents corresponding to the given file name.
755         * The bundle may be in a jar or in a directory at the specified location.
756         * 
757         * @param xmlFileName the given file name
758         * @param bundleLocation the root location of the bundle
759         * @return the file contents or <code>null</code> if not present
760         */
761        protected String readFileContents(String xmlFileName, File bundleLocation) {
762                ZipFile jarFile = null;
763                InputStream stream = null;
764                try {
765                        String extension = new Path(bundleLocation.getName()).getFileExtension();
766                        if (extension != null && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$
767                                jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
768                                ZipEntry manifestEntry = jarFile.getEntry(xmlFileName);
769                                if (manifestEntry != null) {
770                                        stream = jarFile.getInputStream(manifestEntry);
771                                }
772                        } else {
773                                File file = new File(bundleLocation, xmlFileName);
774                                if (file.exists()) {
775                                        stream = new FileInputStream(file);
776                                }
777                        }
778                        if (stream == null) {
779                                return null;
780                        }
781                        return new String(Util.getInputStreamAsCharArray(stream, -1, IApiCoreConstants.UTF_8));
782                } catch(IOException e) {
783                        //TODO abort
784                        ApiPlugin.log(e);
785                } finally {
786                        closingZipFileAndStream(stream, jarFile);
787                }
788                return null;
789        }
790 
791        /**
792         * Parses a bundle's .api_description XML into a string. The file may be in a jar
793         * or in a directory at the specified location.
794         * 
795         * @param bundleLocation root location of the bundle
796         * @return API description XML as a string or <code>null</code> if none
797         * @throws IOException if unable to parse
798         */
799        protected String loadApiDescription(File bundleLocation) throws IOException {
800                ZipFile jarFile = null;
801                InputStream stream = null;
802                String contents = null;
803                try {
804                        String extension = new Path(bundleLocation.getName()).getFileExtension();
805                        if (extension != null && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$
806                                jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
807                                ZipEntry manifestEntry = jarFile.getEntry(IApiCoreConstants.API_DESCRIPTION_XML_NAME);
808                                if (manifestEntry != null) {
809                                        // new file is present
810                                        stream = jarFile.getInputStream(manifestEntry);
811                                }
812                        } else {
813                                File file = new File(bundleLocation, IApiCoreConstants.API_DESCRIPTION_XML_NAME);
814                                if (file.exists()) {
815                                        // use new file
816                                        stream = new FileInputStream(file);
817                                }
818                        }
819                        if (stream == null) {
820                                return null;
821                        }
822                        char[] charArray = Util.getInputStreamAsCharArray(stream, -1, IApiCoreConstants.UTF_8);
823                        contents = new String(charArray);
824                } finally {
825                        closingZipFileAndStream(stream, jarFile);
826                }
827                return contents;
828        }
829        
830        
831        /**
832         * Returns a URL describing a file inside a bundle.
833         * 
834         * @param bundleLocation root location of the bundle. May be a
835         *  directory or a file (jar)
836         * @param filePath bundle relative path to desired file
837         * @return URL to the file
838         * @throws MalformedURLException 
839         */
840        protected URL getFileInBundle(File bundleLocation, String filePath) throws MalformedURLException {
841                String extension = new Path(bundleLocation.getName()).getFileExtension();
842                StringBuffer urlSt = new StringBuffer();
843                if (extension != null && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$
844                        urlSt.append("jar:file:"); //$NON-NLS-1$
845                        urlSt.append(bundleLocation.getAbsolutePath());
846                        urlSt.append("!/"); //$NON-NLS-1$
847                        urlSt.append(filePath);
848                } else {
849                        urlSt.append("file:"); //$NON-NLS-1$
850                        urlSt.append(bundleLocation.getAbsolutePath());
851                        urlSt.append(File.separatorChar);
852                        urlSt.append(filePath);
853                }        
854                return new URL(urlSt.toString());
855        }
856        
857        /* (non-Javadoc)
858         * @see org.eclipse.pde.api.tools.manifest.IApiComponent#getExecutionEnvironments()
859         */
860        public synchronized String[] getExecutionEnvironments() throws CoreException {
861                if (this.fBundleDescription == null) {
862                        baselineDisposed(getBaseline());
863                }
864                return fBundleDescription.getExecutionEnvironments();
865        }
866 
867        /* (non-Javadoc)
868         * @see org.eclipse.pde.api.tools.manifest.IApiComponent#getId()
869         */
870        public final String getId() {
871                return fSymbolicName;
872        }
873 
874        /* (non-Javadoc)
875         * @see org.eclipse.pde.api.tools.manifest.IApiComponent#getRequiredComponents()
876         */
877        public synchronized IRequiredComponentDescription[] getRequiredComponents() throws CoreException {
878                if (this.fBundleDescription == null) {
879                        baselineDisposed(getBaseline());
880                }
881                BundleSpecification[] requiredBundles = fBundleDescription.getRequiredBundles();
882                IRequiredComponentDescription[] req = new IRequiredComponentDescription[requiredBundles.length];
883                for (int i = 0; i < requiredBundles.length; i++) {
884                        BundleSpecification bundle = requiredBundles[i];
885                        req[i] = new RequiredComponentDescription(bundle.getName(),
886                                        new BundleVersionRange(bundle.getVersionRange()),
887                                        bundle.isOptional(),
888                                        bundle.isExported());
889                }
890                return req;
891        }
892 
893        /* (non-Javadoc)
894         * @see org.eclipse.pde.api.tools.manifest.IApiComponent#getVersion()
895         */
896        public synchronized String getVersion() {
897                return fVersion.toString();
898        }
899        
900        /**
901         * Returns this component's bundle description.
902         * 
903         * @return bundle description
904         */
905        public synchronized BundleDescription getBundleDescription() throws CoreException {
906                if (this.fBundleDescription == null) {
907                        baselineDisposed(getBaseline());
908                }
909                return fBundleDescription;
910        }
911 
912        /* (non-Javadoc)
913         * @see java.lang.Object#toString()
914         */
915        public String toString() {
916                if (fBundleDescription != null) {
917                        try {
918                                StringBuffer buffer = new StringBuffer();
919                                buffer.append(fBundleDescription.toString());
920                                buffer.append(" - "); //$NON-NLS-1$
921                                buffer.append("[fragment: ").append(isFragment()).append("] "); //$NON-NLS-1$ //$NON-NLS-2$
922                                buffer.append("[host: ").append(fBundleDescription.getFragments().length > 0).append("] "); //$NON-NLS-1$ //$NON-NLS-2$
923                                buffer.append("[system bundle: ").append(isSystemComponent()).append("] "); //$NON-NLS-1$ //$NON-NLS-2$
924                                buffer.append("[source bundle: ").append(isSourceComponent()).append("] "); //$NON-NLS-1$ //$NON-NLS-2$
925                                return buffer.toString();
926                        }
927                        catch(CoreException ce) {} 
928                }
929                return super.toString();
930        }
931 
932        /* (non-Javadoc)
933         * @see org.eclipse.pde.api.tools.model.component.IApiComponent#getLocation()
934         */
935        public String getLocation() {
936                return fLocation;
937        }
938 
939        /* (non-Javadoc)
940         * @see org.eclipse.pde.api.tools.model.component.IApiComponent#isSystemComponent()
941         */
942        public boolean isSystemComponent() {
943                return false;
944        }
945        
946        /**
947         * Returns a boolean option from the map or the default value if not present.
948         * 
949         * @param options option map
950         * @param optionName option name
951         * @param defaultValue default value for option if not present
952         * @return boolean value
953         */
954        protected boolean getBooleanOption(Map options, String optionName, boolean defaultValue) {
955                Boolean optionB = (Boolean)options.get(optionName);
956                if (optionB != null) {
957                        return optionB.booleanValue();
958                }
959                return defaultValue;
960        }
961        
962        /* (non-Javadoc)
963         * @see IApiComponent#isSourceComponent()
964         */
965        public synchronized boolean isSourceComponent() throws CoreException {
966                if (this.fManifest == null) {
967                        baselineDisposed(getBaseline());
968                }
969                ManifestElement[] sourceBundle = null;
970                try {
971                        sourceBundle = ManifestElement.parseHeader(IApiCoreConstants.ECLIPSE_SOURCE_BUNDLE, (String) fManifest.get(IApiCoreConstants.ECLIPSE_SOURCE_BUNDLE));
972                } catch (BundleException e) {
973                        // ignore
974                }
975                if (sourceBundle != null) {
976                        // this is a source bundle with the new format
977                        return true;
978                }
979                // check for the old format
980                String pluginXMLContents = readFileContents(IApiCoreConstants.PLUGIN_XML_NAME,new File(getLocation()));
981                if (pluginXMLContents != null) {
982                        if (containsSourceExtensionPoint(pluginXMLContents)) {
983                                return true;
984                        }
985                }
986                // check if it contains a fragment.xml with the appropriate extension point
987                pluginXMLContents = readFileContents(IApiCoreConstants.FRAGMENT_XML_NAME,new File(getLocation()));
988                if (pluginXMLContents != null) {
989                        if (containsSourceExtensionPoint(pluginXMLContents)) {
990                                return true;
991                        }
992                }
993                // parse XML contents to find extension points
994                return false;
995        }
996 
997        /**
998         * Check if the given source contains an source extension point.
999         * 
1000         * @param pluginXMLContents the given file contents
1001         * @return true if it contains a source extension point, false otherwise
1002         */
1003        private boolean containsSourceExtensionPoint(String pluginXMLContents) {
1004                SAXParserFactory factory = null;
1005                try {
1006                        factory = SAXParserFactory.newInstance();
1007                } catch (FactoryConfigurationError e) {
1008                        return false;
1009                }
1010                SAXParser saxParser = null;
1011                try {
1012                        saxParser = factory.newSAXParser();
1013                } catch (ParserConfigurationException e) {
1014                        // ignore
1015                } catch (SAXException e) {
1016                        // ignore
1017                }
1018 
1019                if (saxParser == null) {
1020                        return false;
1021                }
1022 
1023                // Parse
1024                InputSource inputSource = new InputSource(new BufferedReader(new StringReader(pluginXMLContents)));
1025                try {
1026                        SourceDefaultHandler defaultHandler = new SourceDefaultHandler();
1027                        saxParser.parse(inputSource, defaultHandler);
1028                        return defaultHandler.isSource();
1029                } catch (SAXException e) {
1030                        // ignore
1031                } catch (IOException e) {
1032                        // ignore
1033                }
1034                return false;
1035        }        
1036 
1037        /* (non-Javadoc)
1038         * @see org.eclipse.pde.api.tools.IApiComponent#isFragment()
1039         */
1040        public synchronized boolean isFragment() throws CoreException {
1041                if (this.fBundleDescription == null) {
1042                        baselineDisposed(getBaseline());
1043                }
1044                return fBundleDescription.getHost() != null;
1045        }
1046 
1047        /**
1048         * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent#getHost()
1049         */
1050        public synchronized IApiComponent getHost() throws CoreException {
1051                if (this.fBundleDescription == null) {
1052                        baselineDisposed(getBaseline());
1053                }
1054                HostSpecification host = fBundleDescription.getHost();
1055                if(host != null) {
1056                        return getBaseline().getApiComponent(host.getName());
1057                }
1058                return null;
1059        }
1060        
1061        /* (non-Javadoc)
1062         * @see org.eclipse.pde.api.tools.IApiComponent#hasFragments()
1063         */
1064        public synchronized boolean hasFragments() throws CoreException {
1065                if (this.fBundleDescription == null) {
1066                        baselineDisposed(getBaseline());
1067                }
1068                return fBundleDescription.getFragments().length != 0;
1069        }
1070        
1071        /**
1072         * Sets whether this bundle has an underlying API description file.
1073         * 
1074         * @param hasApiDescription whether this bundle has an underlying API description file
1075         */
1076        protected void setHasApiDescription(boolean hasApiDescription) {
1077                fHasApiDescription = hasApiDescription;
1078        }
1079        
1080        /* (non-Javadoc)
1081         * @see org.eclipse.pde.api.tools.internal.provisional.IApiComponent#hasApiDescription()
1082         */
1083        public boolean hasApiDescription() {
1084                // ensure initialized
1085                try {
1086                        getApiDescription();
1087                } catch (CoreException e) {
1088                }
1089                return fHasApiDescription;
1090        }
1091        
1092        /* (non-Javadoc)
1093         * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent#getLowestEEs()
1094         */
1095        public String[] getLowestEEs() throws CoreException {
1096                if (this.lowestEEs != null) return this.lowestEEs;
1097                String[] temp = null;
1098                String[] executionEnvironments = this.getExecutionEnvironments();
1099                int length = executionEnvironments.length;
1100                switch(length) {
1101                        case 0 :
1102                                return null;
1103                        case 1 :
1104                                temp = new String[] { executionEnvironments[0] };
1105                                break;
1106                        default :
1107                                int values = ProfileModifiers.NO_PROFILE_VALUE;
1108                                for (int i = 0; i < length; i++) {
1109                                        values |= ProfileModifiers.getValue(executionEnvironments[i]);
1110                                }
1111                                if (ProfileModifiers.isJRE(values)) {
1112                                        if (ProfileModifiers.isJRE_1_1(values)) {
1113                                                temp = new String[] { ProfileModifiers.JRE_1_1_NAME };
1114                                        } else if (ProfileModifiers.isJ2SE_1_2(values)) {
1115                                                temp = new String[] { ProfileModifiers.J2SE_1_2_NAME };
1116                                        } else if (ProfileModifiers.isJ2SE_1_3(values)) {
1117                                                temp = new String[] { ProfileModifiers.J2SE_1_3_NAME };
1118                                        } else if (ProfileModifiers.isJ2SE_1_4(values)) {
1119                                                temp = new String[] { ProfileModifiers.J2SE_1_4_NAME };
1120                                        } else if (ProfileModifiers.isJ2SE_1_5(values)) {
1121                                                temp = new String[] { ProfileModifiers.J2SE_1_5_NAME };
1122                                        } else {
1123                                                // this is 1.6
1124                                                temp = new String[] { ProfileModifiers.JAVASE_1_6_NAME };
1125                                        }
1126                                }
1127                                if (ProfileModifiers.isCDC_Foundation(values)) {
1128                                        if (ProfileModifiers.isCDC_1_0_FOUNDATION_1_0(values)) {
1129                                                if (temp != null) {
1130                                                        temp = new String[] { temp[0], ProfileModifiers.CDC_1_0_FOUNDATION_1_0_NAME };
1131                                                } else {
1132                                                        temp = new String[] { ProfileModifiers.CDC_1_0_FOUNDATION_1_0_NAME };
1133                                                }
1134                                        } else {
1135                                                if (temp != null) {
1136                                                        temp = new String[] { temp[0], ProfileModifiers.CDC_1_1_FOUNDATION_1_1_NAME };
1137                                                } else {
1138                                                        temp = new String[] { ProfileModifiers.CDC_1_1_FOUNDATION_1_1_NAME };
1139                                                }
1140                                        }
1141                                }
1142                                if (ProfileModifiers.isOSGi(values)) {
1143                                        if (ProfileModifiers.isOSGI_MINIMUM_1_0(values)) {
1144                                                if (temp != null) {
1145                                                        int tempLength = temp.length;
1146                                                        System.arraycopy(temp, 0, (temp = new String[tempLength + 1]), 0, tempLength);
1147                                                        temp[tempLength] = ProfileModifiers.OSGI_MINIMUM_1_0_NAME;
1148                                                } else {
1149                                                        temp = new String[] { ProfileModifiers.OSGI_MINIMUM_1_0_NAME };
1150                                                }
1151                                        } else if (ProfileModifiers.isOSGI_MINIMUM_1_1(values)) {
1152                                                if (temp != null) {
1153                                                        int tempLength = temp.length;
1154                                                        System.arraycopy(temp, 0, (temp = new String[tempLength + 1]), 0, tempLength);
1155                                                        temp[tempLength] = ProfileModifiers.OSGI_MINIMUM_1_1_NAME;
1156                                                } else {
1157                                                        temp = new String[] { ProfileModifiers.OSGI_MINIMUM_1_1_NAME };
1158                                                }
1159                                        } else {
1160                                                // OSGI_MINIMUM_1_2
1161                                                if (temp != null) {
1162                                                        int tempLength = temp.length;
1163                                                        System.arraycopy(temp, 0, (temp = new String[tempLength + 1]), 0, tempLength);
1164                                                        temp[tempLength] = ProfileModifiers.OSGI_MINIMUM_1_2_NAME;
1165                                                } else {
1166                                                        temp = new String[] { ProfileModifiers.OSGI_MINIMUM_1_2_NAME };
1167                                                }
1168                                        }
1169                                }
1170                }
1171                this.lowestEEs = temp;
1172                return temp;
1173        }
1174        
1175        /* (non-Javadoc)
1176         * @see org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent#getErrors()
1177         */
1178        public synchronized ResolverError[] getErrors() throws CoreException {
1179                ApiBaseline baseline = (ApiBaseline) getBaseline();
1180                if (this.fBundleDescription == null) {
1181                        baselineDisposed(baseline);
1182                }
1183                if (baseline != null) {
1184                        ResolverError[] resolverErrors = baseline.getState().getResolverErrors(this.fBundleDescription);
1185                        if (resolverErrors.length == 0) {
1186                                return null;
1187                        }
1188                        return resolverErrors;
1189                }
1190                return null;
1191        }
1192        
1193        /**
1194         * @param baseline the baseline that is disposed
1195         * @throws CoreException with the baseline disposed information
1196         */
1197        protected void baselineDisposed(IApiBaseline baseline) throws CoreException {
1198                throw new CoreException(
1199                                new Status(
1200                                                IStatus.ERROR,
1201                                                ApiPlugin.PLUGIN_ID,
1202                                                ApiPlugin.REPORT_BASELINE_IS_DISPOSED,
1203                                                NLS.bind(Messages.BundleApiComponent_baseline_disposed, baseline.getName()),
1204                                                null));
1205        }
1206}

[all classes][org.eclipse.pde.api.tools.internal.model]
EMMA 2.0.5312 EclEmma Fix 1 (C) Vladimir Roubtsov