KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > framework > internal > core > BundleNativeCode


1 /*******************************************************************************
2  * Copyright (c) 2003, 2007 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  *******************************************************************************/

11 package org.eclipse.osgi.framework.internal.core;
12
13 import java.util.Enumeration JavaDoc;
14 import java.util.Vector JavaDoc;
15 import org.eclipse.osgi.service.resolver.VersionRange;
16 import org.eclipse.osgi.util.ManifestElement;
17 import org.osgi.framework.*;
18 import org.osgi.framework.Constants;
19
20 /**
21  * This class represents a description of native code.
22  *
23  * Native Code dependencies
24  *
25  * The Bundle-NativeCode header allows a bundle to carry the native code it
26  * needs, and make use of it when it is installed. The bundle must have
27  * RuntimePermission in order to run native code in the Framework. The value of
28  * the header must conform to the following syntax:
29  *
30  *
31  * Bundle-NativeCode: nativecode-clause ( , nativecode-clause)*
32  * nativecode-clause: nativepaths ( ; env-parameter )* nativepaths: nativepath ( ;
33  * nativepath )* env-parameter: ( processordef | osnamedef | osversiondef |
34  * languagedef ) processordef: <I>processor= </I>token osnamedef: <I>osname=
35  * </I>token osversiondef: <I>osversion= </I>token languagedef: <I>language=
36  * </I>token
37  *
38  * For example:
39  *
40  * Bundle-NativeCode: http.dll ; osname=Win95; processor=x86; language=en,
41  * libhttp.so; osname=Solaris; processor=sparc
42  *
43  * The Bundle-NativeCode header allows a bundle programmer to specify an
44  * environment, and to declare what native code libraries it carries for that
45  * specific environment. The environment is characterized by the following
46  * properties:
47  *
48  * <UL>
49  * <LI><CODE>processor</CODE> The processor on which the hosting the
50  * Framework is running. It is compared against <CODE>
51  * org.osgi.framework.processor</CODE>.
52  * <LI><CODE>osname</CODE> The operating system name. It is compared against
53  * <CODE>org.osgi.framework.os.name</CODE>.
54  * <LI><CODE>selection-filter</CODE> An optional filter that can be used to
55  * match against system properties. If the filter does not match then the
56  * native code clause will not be selected.
57  * <LI><CODE>osversion</CODE> The version of the operating system. It is
58  * compared against <CODE>org.osgi.framework.os.version</CODE>.
59  * <LI><CODE>language</CODE> The language. It is compared against <CODE>
60  * org.osgi.framework.language</CODE>.
61  * </UL>
62  *
63  * These properties should follow the conventions and values defined in the
64  * "Open Software Description" specification.
65  *
66  * The Framework uses the following algorithm to find the "best" matching
67  * native code clause:
68  *
69  * <ol>
70  * <li>Pick the clauses with a matching processor and operating system with
71  * the one the Framework runs on. If no clause matches both the required
72  * processor and operating system, the bundle installation/activation fails. If
73  * only one clause matches, it can be used, otherwise, remaining steps are
74  * executed.</li>
75  * <li>Pick the clauses that best match the operating system version. If they
76  * match each other exactly, that clause is considered the best match. If there
77  * is only one clause with an exact match, it can be used. If there are more
78  * than one clause that matches the property, these clauses will be picked to
79  * perform the next step. Operating system versions are taken to be backward
80  * compatible. If there is no exact match in the clauses, clauses with
81  * operating system versions lower than the value specified in
82  * org.osgi.framework.osversion will be picked. If there is only one clause
83  * which has a compatible operating system version, it can be used. Otherwise,
84  * all clauses with compatible operating system versions will go through the
85  * next step. If no clause has a matching or compatible operating system
86  * version, pick the clause that does not have operating system version
87  * specified. If that is not possible, the bundle installation fails.</li>
88  * <li>Pick the clause that best matches the language. If more than one clause
89  * remains at that point, then the Framework is free to pick amongst them
90  * randomly. If no clauses have the exact match with the value of the property,
91  * pick the clause that does not have language specified. If that is not
92  * possible, the bundle installation fails.</li>
93  * </ol>
94  *
95  */

96 public class BundleNativeCode {
97     /**
98      * The Native Code paths for the Native Code entry
99      */

100     private Attribute nativepaths;
101     /**
102      * The processor attribute for this Native Code entry
103      */

104     private Attribute processor;
105     /**
106      * The osname attribute for this Native Code entry
107      */

108     private Attribute osname;
109     /**
110      * The language attribute for this Native Code entry
111      */

112     private Attribute language;
113     /**
114      * The osversion attribute for this Native Code entry
115      */

116     private Attribute osversion;
117     /**
118      * The filter attribute for this Native Code entry
119      */

120     private String JavaDoc filterString;
121     /**
122      * The Framework for this BundleNativeCode
123      */

124     private AbstractBundle bundle;
125
126     /**
127      * The AliasMapper used to alias OS Names.
128      */

129     private static AliasMapper aliasMapper = Framework.aliasMapper;
130
131     /**
132      * Constructor for BundleNativeCode. It reads bundle native code data from
133      * the manifest file.
134      *
135      */

136     protected BundleNativeCode(ManifestElement element, AbstractBundle bundle) {
137         this.bundle = bundle;
138         String JavaDoc[] nativePaths = element.getValueComponents();
139         for (int i = 0; i < nativePaths.length; i++) {
140             addPath(nativePaths[i]);
141         }
142         setAttribute(element, Constants.BUNDLE_NATIVECODE_OSNAME);
143         setAttribute(element, Constants.BUNDLE_NATIVECODE_PROCESSOR);
144         setAttribute(element, Constants.BUNDLE_NATIVECODE_OSVERSION);
145         setAttribute(element, Constants.BUNDLE_NATIVECODE_LANGUAGE);
146         setAttribute(element, Constants.SELECTION_FILTER_ATTRIBUTE);
147     }
148
149     private void setAttribute(ManifestElement element, String JavaDoc attribute) {
150         String JavaDoc[] attrValues = element.getAttributes(attribute);
151         if (attrValues != null) {
152             for (int i = 0; i < attrValues.length; i++) {
153                 addAttribute(attribute, attrValues[i]);
154             }
155         }
156     }
157
158     /**
159      * Returns the native code paths.
160      *
161      * @return Vector of String code paths.
162      */

163     public String JavaDoc[] getPaths() {
164         if (nativepaths == null) {
165             return null;
166         }
167         String JavaDoc[] paths = new String JavaDoc[nativepaths.size()];
168         nativepaths.toArray(paths);
169         return (paths);
170     }
171
172     /**
173      * addPath is used to add a new element to the list of native files.
174      *
175      * @param nativepath
176      * new native file
177      */

178     protected void addPath(String JavaDoc nativepath) {
179         if (nativepaths == null) {
180             nativepaths = new Attribute();
181         }
182         nativepaths.addElement(nativepath);
183     }
184
185     /**
186      * addAttribute is used to add the specification-version string to the
187      * package description. It is the only key supported at this time.
188      *
189      * @param key
190      * attribute key name
191      * @param value
192      * attribute value name
193      */

194     protected synchronized void addAttribute(String JavaDoc key, String JavaDoc value) {
195         if (key.equals(Constants.BUNDLE_NATIVECODE_PROCESSOR)) {
196             if (processor == null) {
197                 processor = new Attribute();
198             }
199             processor.addElement(aliasMapper.aliasProcessor(value));
200             return;
201         }
202         if (key.equals(Constants.BUNDLE_NATIVECODE_OSNAME)) {
203             if (osname == null) {
204                 osname = new Attribute();
205             }
206             osname.addElement(aliasMapper.aliasOSName(value));
207             return;
208         }
209         if (key.equals(Constants.BUNDLE_NATIVECODE_OSVERSION)) {
210             if (osversion == null) {
211                 osversion = new Attribute();
212             }
213             osversion.addElement(new VersionRange(value));
214             return;
215         }
216         if (key.equals(Constants.SELECTION_FILTER_ATTRIBUTE)) {
217             if (filterString == null) {
218                 filterString = value;
219             }
220             return;
221         }
222         if (key.equals(Constants.BUNDLE_NATIVECODE_LANGUAGE)) {
223             if (language == null) {
224                 language = new Attribute();
225             }
226             language.addElement(value.toLowerCase());
227             return;
228         }
229     }
230
231     /**
232      * Override toString. Return a String representation of this object
233      *
234      * @return String representation of the object
235      */

236     public String JavaDoc toString() {
237         int size = nativepaths.size();
238         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(50 * size);
239         for (int i = 0; i < size; i++) {
240             if (i > 0) {
241                 sb.append(';');
242             }
243             sb.append(nativepaths.elementAt(i).toString());
244         }
245         if (processor != null) {
246             size = processor.size();
247             for (int i = 0; i < size; i++) {
248                 sb.append(';');
249                 sb.append(Constants.BUNDLE_NATIVECODE_PROCESSOR);
250                 sb.append('=');
251                 sb.append(processor.elementAt(i).toString());
252             }
253         }
254         if (osname != null) {
255             size = osname.size();
256             for (int i = 0; i < size; i++) {
257                 sb.append(';');
258                 sb.append(Constants.BUNDLE_NATIVECODE_OSNAME);
259                 sb.append('=');
260                 sb.append(osname.elementAt(i).toString());
261             }
262         }
263         if (osversion != null) {
264             size = osversion.size();
265             for (int i = 0; i < size; i++) {
266                 sb.append(';');
267                 sb.append(Constants.BUNDLE_NATIVECODE_OSVERSION);
268                 sb.append('=');
269                 sb.append(osversion.elementAt(i).toString());
270             }
271         }
272         if (language != null) {
273             size = language.size();
274             for (int i = 0; i < size; i++) {
275                 sb.append(';');
276                 sb.append(Constants.BUNDLE_NATIVECODE_LANGUAGE);
277                 sb.append('=');
278                 sb.append(language.elementAt(i).toString());
279             }
280         }
281         return (sb.toString());
282     }
283
284     /**
285      * Return the match value for the given processor and os name. A higher
286      * value indicates a better match.
287      *
288      * @param processor
289      * processor name to match against.
290      * @param osname
291      * os name to match against.
292      * @return match value
293      */

294     public int matchProcessorOSNameFilter(String JavaDoc processor, String JavaDoc osname) {
295         if ((this.processor == null) || (this.osname == null)) {
296             return (0);
297         }
298         String JavaDoc otherProcessor = aliasMapper.aliasProcessor(processor);
299         String JavaDoc otherOSName = (String JavaDoc) aliasMapper.aliasOSName(osname);
300         if (this.processor.equals(otherProcessor) && this.osname.equals(otherOSName) && matchFilter()) {
301             return (1);
302         }
303         return (0);
304     }
305
306     /**
307      * Return the higest matching value for the given os version that is less
308      * than or equal to the given os version.
309      *
310      * @param version
311      * os version to match against.
312      * @return version or null if no match.
313      */

314     public Version matchOSVersion(Version version) {
315         if (this.osversion == null)
316             return Version.emptyVersion;
317         Version result = null;
318         int size = this.osversion.size();
319         for (int i = 0; i < size; i++) {
320             // find a matching range and save the highest result
321
VersionRange range = (VersionRange) this.osversion.elementAt(i);
322             if (range.isIncluded(version) && (result == null || (range.getMinimum().compareTo(result) > 0)))
323                 result = range.getMinimum();
324         }
325         return result;
326     }
327
328     /**
329      * Return the match value for the given language. A higher value indicates
330      * a better match.
331      *
332      * @param language
333      * language name to match against.
334      * @return match value
335      */

336     public int matchLanguage(String JavaDoc language) {
337         if (this.language == null) {
338             return (1);
339         }
340         if (this.language.equals(language.toLowerCase())) {
341             return (2);
342         }
343         return (0);
344     }
345
346     public boolean matchFilter() {
347         if (filterString == null) {
348             return true;
349         }
350         FilterImpl filter;
351         try {
352             filter = new FilterImpl(filterString);
353         } catch (InvalidSyntaxException e) {
354             BundleException be = new BundleException(Msg.BUNDLE_NATIVECODE_INVALID_FILTER, e);
355             bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, be);
356             return false;
357         }
358         try {
359             return filter.match(FrameworkProperties.getProperties());
360         } catch (IllegalArgumentException JavaDoc e) {
361             return filter.matchCase(FrameworkProperties.getProperties());
362         }
363     }
364
365     /**
366      * Extension of Vector for attributes.
367      */

368     static class Attribute extends Vector JavaDoc {
369         private static final long serialVersionUID = 3257005440914174512L;
370
371         /**
372          * Attribute constructor.
373          *
374          */

375         Attribute() {
376             super(10, 10);
377         }
378
379         /**
380          * Perform an "OR" operation on equals.
381          *
382          * @param obj
383          * Object to test against.
384          * @return true if at least one attribute is equal; false otherwise.
385          */

386         public synchronized boolean equals(Object JavaDoc obj) {
387             for (int i = 0; i < elementCount; i++) {
388                 Object JavaDoc data = elementData[i];
389                 if (data instanceof String JavaDoc) {
390                     if (elementData[i].equals(obj)) {
391                         return (true);
392                     }
393                 } else {
394                     Enumeration JavaDoc e = ((Vector JavaDoc) data).elements();
395                     while (e.hasMoreElements()) {
396                         if (((String JavaDoc) e.nextElement()).equals(obj)) {
397                             return true;
398                         }
399                     }
400                 }
401             }
402             return (false);
403         }
404
405         /**
406          * Add the object if it is not already in the vector.
407          *
408          * @param obj
409          * Object to add to the vector.
410          */

411         public synchronized void addElement(Object JavaDoc obj) {
412             if (!contains(obj)) {
413                 super.addElement(obj);
414             }
415         }
416     }
417 }
418
Popular Tags