View Javadoc

1   // ========================================================================
2   // Copyright (c) 2002-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.start;
15  
16  import java.io.File;
17  import java.io.IOException;
18  import java.io.PrintStream;
19  import java.io.UnsupportedEncodingException;
20  import java.net.MalformedURLException;
21  import java.net.URL;
22  import java.net.URLClassLoader;
23  import java.util.Arrays;
24  import java.util.StringTokenizer;
25  import java.util.Vector;
26  
27  
28  /**
29   * Class to handle CLASSPATH construction
30   */
31  public class Classpath {
32  
33      private final Vector<File> _elements = new Vector<File>();    
34  
35      public Classpath()
36      {}    
37  
38      public Classpath(String initial)
39      {
40          addClasspath(initial);
41      }
42      
43      public File[] getElements()
44      {
45          return _elements.toArray(new File[_elements.size()]);
46      }
47      
48      public int count()
49      {
50          return _elements.size();
51      }
52          
53      public boolean addComponent(String component)
54      {
55          if ((component != null)&&(component.length()>0)) {
56              try {
57                  File f = new File(component);
58                  if (f.exists())
59                  {
60                      File key = f.getCanonicalFile();
61                      if (!_elements.contains(key))
62                      {
63                          _elements.add(key);
64                          return true;
65                      }
66                  }
67              } catch (IOException e) {}
68          }
69          return false;
70      }
71      
72      public boolean addComponent(File component)
73      {
74          if (component != null) {
75              try {
76                  if (component.exists()) {
77                      File key = component.getCanonicalFile();
78                      if (!_elements.contains(key)) {
79                          _elements.add(key);
80                          return true;
81                      }
82                  }
83              } catch (IOException e) {}
84          }
85          return false;
86      }
87  
88      public boolean addClasspath(String s)
89      {
90          boolean added=false;
91          if (s != null)
92          {
93              StringTokenizer t = new StringTokenizer(s, File.pathSeparator);
94              while (t.hasMoreTokens())
95              {
96                  added|=addComponent(t.nextToken());
97              }
98          }
99          return added;
100     }
101 
102     public void dump(PrintStream out)
103     {
104         int i = 0;
105         for (File element : _elements)
106         {
107             out.printf("%2d: %s\n",i++,element.getAbsolutePath());
108         }
109     }
110     
111     @Override
112     public String toString()
113     {
114         StringBuffer cp = new StringBuffer(1024);
115         int cnt = _elements.size();
116         if (cnt >= 1) {
117             cp.append( ((_elements.elementAt(0))).getPath() );
118         }
119         for (int i=1; i < cnt; i++) {
120             cp.append(File.pathSeparatorChar);
121             cp.append( ((_elements.elementAt(i))).getPath() );
122         }
123         return cp.toString();
124     }
125     
126     public ClassLoader getClassLoader() {
127         int cnt = _elements.size();
128         URL[] urls = new URL[cnt];
129         for (int i=0; i < cnt; i++) {
130             try {
131                 String u=((_elements.elementAt(i))).toURL().toString();
132                 urls[i] = new URL(encodeFileURL(u));
133             } catch (MalformedURLException e) {}
134         }
135         
136         ClassLoader parent = Thread.currentThread().getContextClassLoader();
137         if (parent == null) {
138             parent = Classpath.class.getClassLoader();
139         }
140         if (parent == null) {
141             parent = ClassLoader.getSystemClassLoader();
142         }
143         return new Loader(urls, parent);
144     }
145 
146     private static class Loader extends URLClassLoader
147     {
148         String name;
149         
150         Loader(URL[] urls, ClassLoader parent)
151         {
152             super(urls, parent);
153             name = "StartLoader"+Arrays.asList(urls);
154         }
155 
156         @Override
157         public String toString()
158         {
159             return name;
160         }
161     }
162     
163     public static String encodeFileURL(String path)
164     {
165         byte[] bytes;
166         try 
167         { 
168             bytes=path.getBytes("utf-8");
169         } 
170         catch (UnsupportedEncodingException e) 
171         {
172             bytes=path.getBytes();
173         }
174         
175         StringBuffer buf = new StringBuffer(bytes.length*2);
176         buf.append("file:");
177         
178         synchronized(buf)
179         {
180             for (int i=5;i<bytes.length;i++)
181             {
182                 byte b=bytes[i]; 
183                 switch(b)
184                 {
185                   case '%':
186                       buf.append("%25");
187                       continue;
188                   case ' ':
189                       buf.append("%20");
190                       continue;
191                   case '/':
192                   case '.':
193                   case '-':
194                   case '_':
195                       buf.append((char)b);
196                       continue;
197                   default:
198                       // let's be over conservative here!
199                       if (Character.isJavaIdentifierPart((char)b))
200                       {
201                           if(b>='a' && b<='z' || b>='A' && b<='Z' || b>='0' && b<='9')
202                           {
203                               buf.append((char)b);
204                               continue;
205                           }
206                       }
207                       buf.append('%');
208                       buf.append(Integer.toHexString((0xf0&b)>>4));
209                       buf.append(Integer.toHexString((0x0f&b)));
210                       continue;
211                 }
212             }
213         }
214 
215         return buf.toString();
216     }
217 
218     /**
219      * Overlay another classpath, copying its elements into place on this Classpath, while eliminating duplicate entries
220      * on the classpath.
221      * 
222      * @param cpOther
223      *            the other classpath to overlay
224      */
225     public void overlay(Classpath cpOther)
226     {
227         for (File otherElement : cpOther._elements)
228         {
229             if (this._elements.contains(otherElement))
230             {
231                 // Skip duplicate entries
232                 continue;
233             }
234             this._elements.add(otherElement);
235         }
236     }
237 
238     public boolean isEmpty()
239     {
240         return (_elements == null) || (_elements.isEmpty());
241     }
242 }