Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/eclipse/osgi/framework/internal/core/BundleNativeCode.java


1   /*******************************************************************************
2    * Copyright (c) 2003, 2004 IBM Corporation and others.
3    * All rights reserved. This program and the accompanying materials 
4    * are made available under the terms of the Common Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/cpl-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;
14  import java.util.Vector;
15  import org.eclipse.osgi.service.resolver.Version;
16  import org.eclipse.osgi.util.ManifestElement;
17  import org.osgi.framework.*;
18  import org.osgi.framework.Constants;
19  import org.osgi.framework.InvalidSyntaxException;
20  
21  /**
22   * This class represents a description of native code.
23   * 
24   * Native Code dependencies
25   * 
26   * The Bundle-NativeCode header allows a bundle to carry the native code it
27   * needs, and make use of it when it is installed. The bundle must have
28   * RuntimePermission in order to run native code in the Framework. The value of
29   * the header must conform to the following syntax:
30   * 
31   * 
32   * Bundle-NativeCode: nativecode-clause ( , nativecode-clause)*
33   * nativecode-clause: nativepaths ( ; env-parameter )* nativepaths: nativepath ( ;
34   * nativepath )* env-parameter: ( processordef | osnamedef | osversiondef |
35   * languagedef ) processordef: <I>processor= </I>token osnamedef: <I>osname=
36   * </I>token osversiondef: <I>osversion= </I>token languagedef: <I>language=
37   * </I>token
38   * 
39   * For example:
40   * 
41   * Bundle-NativeCode: http.dll ; osname=Win95; processor=x86; language=en,
42   * libhttp.so; osname=Solaris; processor=sparc
43   * 
44   * The Bundle-NativeCode header allows a bundle programmer to specify an
45   * environment, and to declare what native code libraries it carries for that
46   * specific environment. The environment is characterized by the following
47   * properties:
48   * 
49   * <UL>
50   * <LI><CODE>processor</CODE> The processor on which the hosting the
51   * Framework is running. It is compared against <CODE>
52   * org.osgi.framework.processor</CODE>.
53   * <LI><CODE>osname</CODE> The operating system name. It is compared against
54   * <CODE>org.osgi.framework.os.name</CODE>.
55   * <LI><CODE>selection-filter</CODE> An optional filter that can be used to
56   * match against system properties. If the filter does not match then the
57   * native code clause will not be selected.
58   * <LI><CODE>osversion</CODE> The version of the operating system. It is
59   * compared against <CODE>org.osgi.framework.os.version</CODE>.
60   * <LI><CODE>language</CODE> The language. It is compared against <CODE>
61   * org.osgi.framework.language</CODE>.
62   * </UL>
63   * 
64   * These properties should follow the conventions and values defined in the
65   * "Open Software Description" specification.
66   * 
67   * The Framework uses the following algorithm to find the "best" matching
68   * native code clause:
69   * 
70   * <ol>
71   * <li>Pick the clauses with a matching processor and operating system with
72   * the one the Framework runs on. If no clause matches both the required
73   * processor and operating system, the bundle installation/activation fails. If
74   * only one clause matches, it can be used, otherwise, remaining steps are
75   * executed.</li>
76   * <li>Pick the clauses that best match the operating system version. If they
77   * match each other exactly, that clause is considered the best match. If there
78   * is only one clause with an exact match, it can be used. If there are more
79   * than one clause that matches the property, these clauses will be picked to
80   * perform the next step. Operating system versions are taken to be backward
81   * compatible. If there is no exact match in the clauses, clauses with
82   * operating system versions lower than the value specified in
83   * org.osgi.framework.osversion will be picked. If there is only one clause
84   * which has a compatible operating system version, it can be used. Otherwise,
85   * all clauses with compatible operating system versions will go through the
86   * next step. If no clause has a matching or compatible operating system
87   * version, pick the clause that does not have operating system version
88   * specified. If that is not possible, the bundle installation fails.</li>
89   * <li>Pick the clause that best matches the language. If more than one clause
90   * remains at that point, then the Framework is free to pick amongst them
91   * randomly. If no clauses have the exact match with the value of the property,
92   * pick the clause that does not have language specified. If that is not
93   * possible, the bundle installation fails.</li>
94   * </ol>
95   *  
96   */
97  public class BundleNativeCode {
98    /**
99     * The Native Code paths for the Native Code entry
100    */
101   private Attribute nativepaths;
102   /**
103    * The processor attribute for this Native Code entry
104    */
105   private Attribute processor;
106   /**
107    * The osname attribute for this Native Code entry
108    */
109   private Attribute osname;
110   /**
111    * The language attribute for this Native Code entry
112    */
113   private Attribute language;
114   /**
115    * The osversion attribute for this Native Code entry
116    */
117   private Attribute osversion;
118   /**
119    * The filter attribute for this Native Code entry
120    */
121   private String filterString;
122   /**
123    * The Framework for this BundleNativeCode
124    */
125   private AbstractBundle bundle;
126 
127   /**
128    * The AliasMapper used to alias OS Names.
129    */
130   private static AliasMapper aliasMapper = Framework.aliasMapper;
131 
132   /**
133    * Constructor for BundleNativeCode. It reads bundle native code data from
134    * the manifest file.
135    *  
136    */
137   protected BundleNativeCode(ManifestElement element, AbstractBundle bundle) {
138     this.bundle = bundle;
139     String[] nativePaths = element.getValueComponents();
140     for (int i = 0; i < nativePaths.length; i++) {
141       addPath(nativePaths[i]);
142     }
143     setAttribute(element, Constants.BUNDLE_NATIVECODE_OSNAME);
144     setAttribute(element, Constants.BUNDLE_NATIVECODE_PROCESSOR);
145     setAttribute(element, Constants.BUNDLE_NATIVECODE_OSVERSION);
146     setAttribute(element, Constants.BUNDLE_NATIVECODE_LANGUAGE);
147     setAttribute(element, Constants.SELECTION_FILTER_ATTRIBUTE);
148   }
149 
150   private void setAttribute(ManifestElement element, String attribute) {
151     String[] attrValues = element.getAttributes(attribute);
152     if (attrValues != null) {
153       for (int i = 0; i < attrValues.length; i++) {
154         addAttribute(attribute, attrValues[i]);
155       }
156     }
157   }
158 
159   /**
160    * Returns the native code paths.
161    * 
162    * @return Vector of String code paths.
163    */
164   public String[] getPaths() {
165     if (nativepaths == null) {
166       return null;
167     }
168     String[] paths = new String[nativepaths.size()];
169     nativepaths.toArray(paths);
170     return (paths);
171   }
172 
173   /**
174    * addPath is used to add a new element to the list of native files.
175    * 
176    * @param nativepath
177    *            new native file
178    */
179   protected void addPath(String nativepath) {
180     if (nativepaths == null) {
181       nativepaths = new Attribute();
182     }
183     nativepaths.addElement(nativepath);
184   }
185 
186   /**
187    * addAttribute is used to add the specification-version string to the
188    * package description. It is the only key supported at this time.
189    * 
190    * @param key
191    *            attribute key name
192    * @param value
193    *            attribute value name
194    */
195   protected synchronized void addAttribute(String key, String value) {
196     if (key.equals(Constants.BUNDLE_NATIVECODE_PROCESSOR)) {
197       if (processor == null) {
198         processor = new Attribute();
199       }
200       processor.addElement(aliasMapper.aliasProcessor(value));
201       return;
202     }
203     if (key.equals(Constants.BUNDLE_NATIVECODE_OSNAME)) {
204       if (osname == null) {
205         osname = new Attribute();
206       }
207       osname.addElement(aliasMapper.aliasOSName(value));
208       return;
209     }
210     if (key.equals(Constants.BUNDLE_NATIVECODE_OSVERSION)) {
211       if (osversion == null) {
212         osversion = new Attribute();
213       }
214       osversion.addElement(new Version(value));
215       return;
216     }
217     if (key.equals(Constants.SELECTION_FILTER_ATTRIBUTE)) {
218       if (filterString == null) {
219         filterString = value;
220       }
221       return;
222     }
223     if (key.equals(Constants.BUNDLE_NATIVECODE_LANGUAGE)) {
224       if (language == null) {
225         language = new Attribute();
226       }
227       language.addElement(value.toLowerCase());
228       return;
229     }
230   }
231 
232   /**
233    * Override toString. Return a String representation of this object
234    * 
235    * @return String representation of the object
236    */
237   public String toString() {
238     int size = nativepaths.size();
239     StringBuffer sb = new StringBuffer(50 * size);
240     for (int i = 0; i < size; i++) {
241       if (i > 0) {
242         sb.append(';');
243       }
244       sb.append(nativepaths.elementAt(i).toString());
245     }
246     if (processor != null) {
247       size = processor.size();
248       for (int i = 0; i < size; i++) {
249         sb.append(';');
250         sb.append(Constants.BUNDLE_NATIVECODE_PROCESSOR);
251         sb.append('=');
252         sb.append(processor.elementAt(i).toString());
253       }
254     }
255     if (osname != null) {
256       size = osname.size();
257       for (int i = 0; i < size; i++) {
258         sb.append(';');
259         sb.append(Constants.BUNDLE_NATIVECODE_OSNAME);
260         sb.append('=');
261         sb.append(osname.elementAt(i).toString());
262       }
263     }
264     if (osversion != null) {
265       size = osversion.size();
266       for (int i = 0; i < size; i++) {
267         sb.append(';');
268         sb.append(Constants.BUNDLE_NATIVECODE_OSVERSION);
269         sb.append('=');
270         sb.append(osversion.elementAt(i).toString());
271       }
272     }
273     if (language != null) {
274       size = language.size();
275       for (int i = 0; i < size; i++) {
276         sb.append(';');
277         sb.append(Constants.BUNDLE_NATIVECODE_LANGUAGE);
278         sb.append('=');
279         sb.append(language.elementAt(i).toString());
280       }
281     }
282     return (sb.toString());
283   }
284 
285   /**
286    * Return the match value for the given processor and os name. A higher
287    * value indicates a better match.
288    * 
289    * @param processor
290    *            processor name to match against.
291    * @param osname
292    *            os name to match against.
293    * @return match value
294    */
295   public int matchProcessorOSNameFilter(String processor, String osname) {
296     if ((this.processor == null) || (this.osname == null)) {
297       return (0);
298     }
299     String otherProcessor = aliasMapper.aliasProcessor(processor);
300     String otherOSName = (String) aliasMapper.aliasOSName(osname);
301     if (this.processor.equals(otherProcessor) && this.osname.equals(otherOSName) && matchFilter()) {
302       return (1);
303     }
304     return (0);
305   }
306 
307   /**
308    * Return the higest matching value for the given os version that is less
309    * than or equal to the given os version.
310    * 
311    * @param version
312    *            os version to match against.
313    * @return version or null if no match.
314    */
315   public Version matchOSVersion(Version version) {
316     if (this.osversion == null) {
317       return Version.emptyVersion;
318     }
319     Version result = null;
320     int size = this.osversion.size();
321     for (int i = 0; i < size; i++) {
322       Version ver = (Version) this.osversion.elementAt(i);
323       int compare = ver.compareTo(version);
324       if (compare == 0) /* versions are equal; best possible match */{
325         return ver;
326       }
327       if (compare < 0) /* requested version < current OS version */{
328         if ((result == null) || (ver.compareTo(result) > 0)) {
329           result = ver; /*
330            * remember the highest version less than
331            * osversion
332            */
333         }
334       }
335     }
336     return result;
337   }
338 
339   /**
340    * Return the match value for the given language. A higher value indicates
341    * a better match.
342    * 
343    * @param language
344    *            language name to match against.
345    * @return match value
346    */
347   public int matchLanguage(String language) {
348     if (this.language == null) {
349       return (1);
350     }
351     if (this.language.equals(language.toLowerCase())) {
352       return (2);
353     }
354     return (0);
355   }
356 
357   public boolean matchFilter() {
358     if (filterString == null) {
359       return true;
360     }
361     FilterImpl filter;
362     try {
363       filter = new FilterImpl(filterString);
364     } catch (InvalidSyntaxException e) {
365       BundleException be = new BundleException(Msg.formatter.getString("BUNDLE_NATIVECODE_INVALID_FILTER"), e); //$NON-NLS-1$
366       bundle.framework.publishFrameworkEvent(FrameworkEvent.ERROR, bundle, be);
367       return false;
368     }
369     return filter.match(System.getProperties());
370   }
371 
372   /**
373    * Extension of Vector for attributes.
374    */
375   static class Attribute extends Vector {
376     /**
377      * Attribute constructor.
378      *  
379      */
380     Attribute() {
381       super(10, 10);
382     }
383 
384     /**
385      * Perform an "OR" operation on equals.
386      * 
387      * @param obj
388      *            Object to test against.
389      * @return true if at least one attribute is equal; false otherwise.
390      */
391     public synchronized boolean equals(Object obj) {
392       for (int i = 0; i < elementCount; i++) {
393         Object data = elementData[i];
394         if (data instanceof String) {
395           if (elementData[i].equals(obj)) {
396             return (true);
397           }
398         } else {
399           Enumeration e = ((Vector) data).elements();
400           while (e.hasMoreElements()) {
401             if (((String) e.nextElement()).equals(obj)) {
402               return true;
403             }
404           }
405         }
406       }
407       return (false);
408     }
409 
410     /**
411      * Add the object if it is not already in the vector.
412      * 
413      * @param obj
414      *            Object to add to the vector.
415      */
416     public synchronized void addElement(Object obj) {
417       if (!contains(obj)) {
418         super.addElement(obj);
419       }
420     }
421   }
422 }