View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.start;
20  
21  import java.io.File;
22  import java.io.FileFilter;
23  import java.io.IOException;
24  import java.net.URI;
25  import java.net.URISyntaxException;
26  import java.net.URL;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.Collections;
30  import java.util.List;
31  import java.util.Objects;
32  import java.util.regex.Matcher;
33  import java.util.regex.Pattern;
34  
35  /**
36   * File access for <code>${jetty.home}</code>, <code>${jetty.base}</code>, directories.
37   * <p>
38   * By default, both <code>${jetty.home}</code> and <code>${jetty.base}</code> are the same directory, but they can point at different directories.
39   * <p>
40   * The <code>${jetty.home}</code> directory is where the main Jetty binaries and default configuration is housed.
41   * <p>
42   * The <code>${jetty.base}</code> directory is where the execution specific configuration and webapps are obtained from.
43   */
44  public class BaseHome
45  {
46      private File homeDir;
47      private File baseDir;
48  
49      public BaseHome()
50      {
51          try
52          {
53              this.baseDir = new File(System.getProperty("jetty.base",System.getProperty("user.dir",".")));
54              URL jarfile = this.getClass().getClassLoader().getResource("org/eclipse/jetty/start/BaseHome.class");
55              if (jarfile != null)
56              {
57                  Matcher m = Pattern.compile("jar:(file:.*)!/org/eclipse/jetty/start/BaseHome.class").matcher(jarfile.toString());
58                  if (m.matches())
59                  {
60                      homeDir = new File(new URI(m.group(1))).getParentFile();
61                  }
62              }
63              homeDir = new File(System.getProperty("jetty.home",(homeDir == null?baseDir:homeDir).getAbsolutePath()));
64  
65              baseDir = baseDir.getAbsoluteFile().getCanonicalFile();
66              homeDir = homeDir.getAbsoluteFile().getCanonicalFile();
67          }
68          catch (IOException | URISyntaxException e)
69          {
70              throw new RuntimeException(e);
71          }
72      }
73  
74      public BaseHome(File homeDir, File baseDir)
75      {
76          try
77          {
78              this.homeDir = homeDir.getCanonicalFile();
79              this.baseDir = baseDir == null?this.homeDir:baseDir.getCanonicalFile();
80          }
81          catch (IOException e)
82          {
83              throw new RuntimeException(e);
84          }
85      }
86  
87      public String getBase()
88      {
89          if (baseDir == null)
90          {
91              return null;
92          }
93          return baseDir.getAbsolutePath();
94      }
95  
96      public File getBaseDir()
97      {
98          return baseDir;
99      }
100 
101     /**
102      * Create a file reference to some content in <code>"${jetty.base}"</code>
103      * 
104      * @param path
105      *            the path to reference
106      * @return the file reference
107      */
108     public File getBaseFile(String path)
109     {
110         return new File(baseDir,FS.separators(path));
111     }
112 
113     /**
114      * Get a specific file reference.
115      * <p>
116      * File references go through 3 possibly scenarios.
117      * <ol>
118      * <li>If exists relative to <code>${jetty.base}</code>, return that reference</li>
119      * <li>If exists relative to <code>${jetty.home}</code>, return that reference</li>
120      * <li>Otherwise return absolute path reference</li>
121      * </ol>
122      * 
123      * @param path
124      *            the path to get.
125      * @return the file reference.
126      */
127     public File getFile(String path)
128     {
129         String rpath = FS.separators(path);
130 
131         // Relative to Base Directory First
132         if (isBaseDifferent())
133         {
134             File file = new File(baseDir,rpath);
135             if (file.exists())
136             {
137                 return file;
138             }
139         }
140 
141         // Then relative to Home Directory
142         File file = new File(homeDir,rpath);
143         if (file.exists())
144         {
145             return file;
146         }
147 
148         // Finally, as an absolute path
149         return new File(rpath);
150     }
151 
152     public String getHome()
153     {
154         return homeDir.getAbsolutePath();
155     }
156 
157     public File getHomeDir()
158     {
159         return homeDir;
160     }
161 
162     public void initialize(StartArgs args)
163     {
164         Pattern jetty_home = Pattern.compile("(-D)?jetty.home=(.*)");
165         Pattern jetty_base = Pattern.compile("(-D)?jetty.base=(.*)");
166 
167         File homePath = null;
168         File basePath = null;
169 
170         for (String arg : args.getCommandLine())
171         {
172             Matcher home_match = jetty_home.matcher(arg);
173             if (home_match.matches())
174             {
175                 homePath = new File(home_match.group(2));
176             }
177             Matcher base_match = jetty_base.matcher(arg);
178             if (base_match.matches())
179             {
180                 basePath = new File(base_match.group(2));
181             }
182         }
183 
184         if (homePath != null)
185         {
186             // logic if home is specified
187             this.homeDir = homePath;
188             this.baseDir = basePath == null?homePath:basePath;
189         }
190         else if (basePath != null)
191         {
192             // logic if home is undeclared
193             this.baseDir = basePath;
194         }
195     }
196 
197     public boolean isBaseDifferent()
198     {
199         return homeDir.compareTo(baseDir) != 0;
200     }
201 
202     /**
203      * Get all of the files that are in a specific relative directory.
204      * <p>
205      * If the same found path exists in both <code>${jetty.base}</code> and <code>${jetty.home}</code>, then the one in <code>${jetty.base}</code> is returned
206      * (it overrides the one in ${jetty.home})
207      * 
208      * @param relPathToDirectory
209      *            the relative path to the directory
210      * @return the list of files found.
211      */
212     public List<File> listFiles(String relPathToDirectory)
213     {
214         return listFiles(relPathToDirectory,FS.AllFilter.INSTANCE);
215     }
216 
217     /**
218      * Get all of the files that are in a specific relative directory, with applied {@link FileFilter}
219      * <p>
220      * If the same found path exists in both <code>${jetty.base}</code> and <code>${jetty.home}</code>, then the one in <code>${jetty.base}</code> is returned
221      * (it overrides the one in ${jetty.home})
222      * 
223      * @param relPathToDirectory
224      *            the relative path to the directory
225      * @param filter
226      *            the filter to use
227      * @return the list of files found.
228      */
229     public List<File> listFiles(String relPathToDirectory, FileFilter filter)
230     {
231         Objects.requireNonNull(filter,"FileFilter cannot be null");
232 
233         File homePath = new File(homeDir,FS.separators(relPathToDirectory));
234         List<File> homeFiles = new ArrayList<>();
235         if (FS.canReadDirectory(homePath))
236         {
237             homeFiles.addAll(Arrays.asList(homePath.listFiles(filter)));
238         }
239 
240         if (isBaseDifferent())
241         {
242             // merge
243             File basePath = new File(baseDir,FS.separators(relPathToDirectory));
244             List<File> ret = new ArrayList<>();
245             if (FS.canReadDirectory(basePath))
246             {
247                 File baseFiles[] = basePath.listFiles(filter);
248 
249                 if (baseFiles != null)
250                 {
251                     for (File base : baseFiles)
252                     {
253                         String relpath = toRelativePath(baseDir,base);
254                         File home = new File(homeDir,FS.separators(relpath));
255                         if (home.exists())
256                         {
257                             homeFiles.remove(home);
258                         }
259                         ret.add(base);
260                     }
261                 }
262             }
263 
264             // add any remaining home files.
265             ret.addAll(homeFiles);
266 
267             Collections.sort(ret,new NaturalSort.Files());
268             return ret;
269         }
270         else
271         {
272             // simple return
273             Collections.sort(homeFiles,new NaturalSort.Files());
274             return homeFiles;
275         }
276     }
277 
278     /**
279      * Collect the list of files in both <code>${jetty.base}</code> and <code>${jetty.home}</code>, with , even if the same file shows up in both places.
280      */
281     public List<File> rawListFiles(String relPathToDirectory, FileFilter filter)
282     {
283         Objects.requireNonNull(filter,"FileFilter cannot be null");
284 
285         List<File> ret = new ArrayList<>();
286 
287         // Home Dir
288         File homePath = new File(homeDir,FS.separators(relPathToDirectory));
289         ret.addAll(Arrays.asList(homePath.listFiles(filter)));
290 
291         if (isBaseDifferent())
292         {
293             // Base Dir
294             File basePath = new File(baseDir,FS.separators(relPathToDirectory));
295             ret.addAll(Arrays.asList(basePath.listFiles(filter)));
296         }
297 
298         // Sort
299         Collections.sort(ret,new NaturalSort.Files());
300         return ret;
301     }
302 
303     public void setBaseDir(File dir)
304     {
305         try
306         {
307             this.baseDir = dir.getCanonicalFile();
308             System.setProperty("jetty.base",dir.getCanonicalPath());
309         }
310         catch (IOException e)
311         {
312             e.printStackTrace(System.err);
313         }
314     }
315 
316     public void setHomeDir(File dir)
317     {
318         try
319         {
320             this.homeDir = dir.getCanonicalFile();
321             System.setProperty("jetty.home",dir.getCanonicalPath());
322         }
323         catch (IOException e)
324         {
325             e.printStackTrace(System.err);
326         }
327     }
328 
329     private String toRelativePath(File dir, File path)
330     {
331         return dir.toURI().relativize(path.toURI()).toASCIIString();
332     }
333 
334     /**
335      * Convenience method for <code>toShortForm(file.getCanonicalPath())</code>
336      */
337     public String toShortForm(File path)
338     {
339         try
340         {
341             return toShortForm(path.getCanonicalPath());
342         }
343         catch (IOException ignore)
344         {
345             /* ignore */
346         }
347         return toShortForm(path.getAbsolutePath());
348     }
349 
350     /**
351      * Replace/Shorten arbitrary path with property strings <code>"${jetty.home}"</code> or <code>"${jetty.base}"</code> where appropriate.
352      * 
353      * @param path
354      *            the path to shorten
355      * @return the potentially shortened path
356      */
357     public String toShortForm(String path)
358     {
359         if (path == null)
360         {
361             return path;
362         }
363 
364         String value;
365 
366         if (isBaseDifferent())
367         {
368             value = baseDir.getAbsolutePath();
369             if (path.startsWith(value))
370             {
371                 return "${jetty.base}" + path.substring(value.length());
372             }
373         }
374 
375         value = homeDir.getAbsolutePath();
376 
377         if (path.startsWith(value))
378         {
379             return "${jetty.home}" + path.substring(value.length());
380         }
381 
382         return path;
383     }
384 
385 }