1   // ========================================================================
2   // Copyright 2002-2005 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  
15  package org.mortbay.start;
16  
17  import java.io.File;
18  import java.io.IOException;
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   * @author Jan Hlavaty
31   */
32  public class Classpath {
33  
34      Vector _elements = new Vector();    
35  
36      public Classpath()
37      {}    
38  
39      public Classpath(String initial)
40      {
41          addClasspath(initial);
42      }
43          
44      public boolean addComponent(String component)
45      {
46          if ((component != null)&&(component.length()>0)) {
47              try {
48                  File f = new File(component);
49                  if (f.exists())
50                  {
51                      File key = f.getCanonicalFile();
52                      if (!_elements.contains(key))
53                      {
54                          _elements.add(key);
55                          return true;
56                      }
57                  }
58              } catch (IOException e) {}
59          }
60          return false;
61      }
62      
63      public boolean addComponent(File component)
64      {
65          if (component != null) {
66              try {
67                  if (component.exists()) {
68                      File key = component.getCanonicalFile();
69                      if (!_elements.contains(key)) {
70                          _elements.add(key);
71                          return true;
72                      }
73                  }
74              } catch (IOException e) {}
75          }
76          return false;
77      }
78  
79      public boolean addClasspath(String s)
80      {
81          boolean added=false;
82          if (s != null)
83          {
84              StringTokenizer t = new StringTokenizer(s, File.pathSeparator);
85              while (t.hasMoreTokens())
86              {
87                  added|=addComponent(t.nextToken());
88              }
89          }
90          return added;
91      }    
92      
93      public String toString()
94      {
95          StringBuffer cp = new StringBuffer(1024);
96          int cnt = _elements.size();
97          if (cnt >= 1) {
98              cp.append( ((File)(_elements.elementAt(0))).getPath() );
99          }
100         for (int i=1; i < cnt; i++) {
101             cp.append(File.pathSeparatorChar);
102             cp.append( ((File)(_elements.elementAt(i))).getPath() );
103         }
104         return cp.toString();
105     }
106     
107     public ClassLoader getClassLoader() {
108         int cnt = _elements.size();
109         URL[] urls = new URL[cnt];
110         for (int i=0; i < cnt; i++) {
111             try {
112                 String u=((File)(_elements.elementAt(i))).toURL().toString();
113                 urls[i] = new URL(encodeFileURL(u));
114             } catch (MalformedURLException e) {}
115         }
116         
117         ClassLoader parent = Thread.currentThread().getContextClassLoader();
118         if (parent == null) {
119             parent = Classpath.class.getClassLoader();
120         }
121         if (parent == null) {
122             parent = ClassLoader.getSystemClassLoader();
123         }
124         return new Loader(urls, parent);
125     }
126 
127     private class Loader extends URLClassLoader
128     {
129         String name;
130         
131         Loader(URL[] urls, ClassLoader parent)
132         {
133             super(urls, parent);
134             name = "StartLoader"+Arrays.asList(urls);
135         }
136 
137         public String toString()
138         {
139             return name;
140         }
141     }
142     
143     public static String encodeFileURL(String path)
144     {
145         byte[] bytes;
146         try 
147         { 
148             bytes=path.getBytes("utf-8");
149         } 
150         catch (UnsupportedEncodingException e) 
151         {
152             bytes=path.getBytes();
153         }
154         
155         StringBuffer buf = new StringBuffer(bytes.length*2);
156         buf.append("file:");
157         
158         synchronized(buf)
159         {
160             for (int i=5;i<bytes.length;i++)
161             {
162                 byte b=bytes[i]; 
163                 switch(b)
164                 {
165                   case '%':
166                       buf.append("%25");
167                       continue;
168                   case ' ':
169                       buf.append("%20");
170                       continue;
171                   case '/':
172                   case '.':
173                   case '-':
174                   case '_':
175                       buf.append((char)b);
176                       continue;
177                   default:
178                       // let's be over conservative here!
179                       if (Character.isJavaIdentifierPart((char)b))
180                       {
181                           if(b>='a' && b<='z' || b>='A' && b<='Z' || b>='0' && b<='9')
182                           {
183                               buf.append((char)b);
184                               continue;
185                           }
186                       }
187                       buf.append('%');
188                       buf.append(Integer.toHexString((0xf0&(int)b)>>4));
189                       buf.append(Integer.toHexString((0x0f&(int)b)));
190                       continue;
191                 }
192             }
193         }
194 
195         return buf.toString();
196     }
197 }