1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.environment.internal

File AbstractEnvironment.java

 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

24
45
9
1
252
116
26
0.58
5
9
2.89

Classes

Class Line # Actions
AbstractEnvironment 39 45 0% 26 6
0.923076992.3%
 

Contributing tests

This file is covered by 76 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.environment.internal;
21   
22    import java.io.File;
23    import java.io.IOException;
24    import java.nio.file.Files;
25   
26    import javax.inject.Inject;
27    import javax.inject.Provider;
28   
29    import org.apache.commons.io.FileUtils;
30    import org.slf4j.Logger;
31    import org.xwiki.environment.Environment;
32   
33    /**
34    * Makes it easy to implement {@link org.xwiki.environment.Environment}.
35    *
36    * @version $Id: 767c59c449788477d2e6f2ff3d3f6592ee0e93c3 $
37    * @since 3.5M1
38    */
 
39    public abstract class AbstractEnvironment implements Environment
40    {
41    /**
42    * Default temporary directory to use when none has been specified.
43    */
44    private static final String DEFAULT_TMP_DIRECTORY = System.getProperty("java.io.tmpdir");
45   
46    /**
47    * The name of the temporary directory which will be cleaned at every restart.
48    */
49    private static final String TEMP_NAME = "xwiki-temp";
50   
51    @Inject
52    protected Logger logger;
53   
54    /**
55    * Environment configuration data. We load it lazily to avoid a cyclic runtime dependency between the Environment
56    * implementation (which requires a Configuration Source) and the Configuration Source implementation (which
57    * requires an Environment).
58    */
59    @Inject
60    private Provider<EnvironmentConfiguration> configurationProvider;
61   
62    /**
63    * @see #getTemporaryDirectory()
64    */
65    private File temporaryDirectory;
66   
67    /**
68    * @see #getPermanentDirectory()
69    */
70    private File permanentDirectory;
71   
72    /**
73    * @param permanentDirectory see {@link #getPermanentDirectory()}
74    */
 
75  213 toggle public void setPermanentDirectory(File permanentDirectory)
76    {
77  213 this.permanentDirectory = permanentDirectory;
78    }
79   
80    /**
81    * @param temporaryDirectory see {@link #getTemporaryDirectory()}
82    */
 
83  211 toggle public void setTemporaryDirectory(File temporaryDirectory)
84    {
85  211 this.temporaryDirectory = temporaryDirectory;
86    }
87   
88    /**
89    * {@inheritDoc}
90    * <p>
91    * Rather than overriding this, it is safer to override {@link #getPermanentDirectoryName()} if you need to change
92    * the default behavior. This is because this method does a number of checks to make sure the directory exists, is a
93    * directory (not a file) and the XWiki process has permission to write to it. If the directory doesn't exist it is
94    * created and if it cannot be written to, an error is printed in the log and it is passed over for the default
95    * permanent directory. Thus by overriding {@link #getPermanentDirectoryName()} you'll still benefit from all those
96    * checks.
97    * </p>
98    */
 
99  409 toggle @Override
100    public File getPermanentDirectory()
101    {
102    // Note: We're initializing the permanent directory here instead of in an Initializable.initialize() method
103    // since otherwise we get a cyclic dependency with the Configuration Source implementation used to get the
104    // Environment configuration property for the permanent directory location (since that Source require the
105    // Environment for finding the configuration resource in the executing Environment).
106  409 if (this.permanentDirectory == null) {
107  78 String systemProperty = System.getProperty("xwiki.data.dir");
108  78 final String classSpecified = getPermanentDirectoryName();
109  78 final String configured = this.configurationProvider.get().getPermanentDirectoryPath();
110   
111  78 final String[] locations =
112    new String[] { systemProperty, classSpecified, configured, getTemporaryDirectoryName(),
113    DEFAULT_TMP_DIRECTORY };
114  77 this.permanentDirectory = initializeDirectory(locations, false);
115   
116  77 if (systemProperty == null && classSpecified == null && configured == null) {
117    // There's no defined permanent directory, fall back to the temporary directory but issue a warning
118  35 this.logger.warn("No permanent directory configured. Using temporary directory [{}].",
119    this.permanentDirectory);
120    }
121    }
122   
123  408 return this.permanentDirectory;
124    }
125   
126    /**
127    * Get the name of the permanent directory to use. This name will be preferred when choosing the permanent directory
128    * and if it is not able to be written to, this class will fail over to the default directory after printing an
129    * error in the log file.
130    *
131    * @return the permanent directory as specified
132    */
 
133  78 toggle protected String getPermanentDirectoryName()
134    {
135  78 return null;
136    }
137   
138    /**
139    * {@inheritDoc}
140    * <p>
141    * Rather than overriding this, it is safer to override {@link #getTemporaryDirectoryName()} This is
142    * because this function does a number of checks to make sure the directory exists, is a directory (not a file) and
143    * the XWiki process has permission to write to it. If the directory doesn't exist it is created and if it cannot be
144    * written to, an erroris printed in the log and it is passed over for the default temporary directory.
145    * </p>
146    *
147    * @see Environment#getTemporaryDirectory()
148    */
 
149  806 toggle @Override
150    public File getTemporaryDirectory()
151    {
152  806 if (this.temporaryDirectory == null) {
153  68 final String[] locations = new String[] { getTemporaryDirectoryName(), DEFAULT_TMP_DIRECTORY };
154  68 this.temporaryDirectory = initializeDirectory(locations, true);
155    }
156   
157  804 return this.temporaryDirectory;
158    }
159   
160    /**
161    * Get the name of the temporary directory to use. The path given name will be preferred when choosing the temporary
162    * directory and if it is not able to be written to, this class will fail over to the default directory after
163    * printing an error in the log file.
164    *
165    * @return the temporary directory as specified
166    */
 
167  146 toggle protected String getTemporaryDirectoryName()
168    {
169  146 return null;
170    }
171   
172    /**
173    * @param locations the names of the directories to try to initialize ordered from best to worst. If none of these
174    * can be initialized, the system will be halted.
175    * @param isTemp true if the directory is a temporary directory.
176    * @return the initialized directory as a {@link File} or null if the directory doesn't exist, cannot be created or
177    * the passed name was null
178    */
 
179  145 toggle private File initializeDirectory(final String[] locations, final boolean isTemp)
180    {
181  145 final String tempOrPermanent = (isTemp) ? "temporary" : "permanent";
182  145 boolean first = true;
183  145 for (final String location : locations) {
184  328 if (location == null) {
185  183 continue;
186    }
187  145 if (!first) {
188  0 this.logger.warn("Falling back on [{}] as the {} directory.", location, tempOrPermanent);
189    }
190  145 first = false;
191  145 final File dir = initializeDirectory(location, isTemp, tempOrPermanent);
192  145 if (dir != null) {
193  144 return dir;
194    }
195    }
196   
197  1 throw new RuntimeException(String.format(
198    "Could not find a writable %s directory. Check the server logs for more information.", tempOrPermanent));
199    }
200   
201    /**
202    * @param directoryName the name of the directory to initialize (ensure it exists, create the directory)
203    * @param isTemp true if we are initializing a temporary directory.
204    * @param tempOrPermanent a string describing the type of directory, namely "temporary" or "permanent", to aid
205    * logging.
206    * @return the initialized directory as a {@link File} or null if the directory doesn't exist and cannot be created
207    * or if the process doesn't have permission to write to it.
208    */
 
209  145 toggle private File initializeDirectory(final String directoryName, final boolean isTemp, final String tempOrPermanent)
210    {
211  145 final File dir = (isTemp) ? new File(directoryName, TEMP_NAME) : new File(directoryName);
212   
213  145 if (dir.exists()) {
214  108 if (dir.isDirectory() && dir.canWrite()) {
215  107 return initDir(dir, isTemp);
216    }
217   
218    // Not a directory or can't write to it, lets log an error here.
219  1 this.logger.error("Configured {} directory [{}] is {}.", tempOrPermanent, dir.getAbsolutePath(),
220  1 (dir.isDirectory()) ? "not writable" : "not a directory");
221   
222  1 return null;
223   
224    }
225   
226  37 try {
227  37 Files.createDirectories(dir.toPath());
228   
229  37 return initDir(dir, isTemp);
230    } catch (IOException e) {
231  0 this.logger.error("Configured {} directory [{}] could not be created.", tempOrPermanent,
232    dir.getAbsolutePath(), e);
233    }
234   
235  0 return null;
236    }
237   
 
238  144 toggle private File initDir(final File directory, final boolean isTemp)
239    {
240  144 if (isTemp) {
241  67 try {
242  67 FileUtils.cleanDirectory(directory);
243    } catch (IOException e) {
244  0 throw new RuntimeException(String.format("Failed to empty the temporary directory [%s]. "
245    + "Are there files inside of it which XWiki " + "does not have permission to delete?",
246    directory.getAbsolutePath()), e);
247    }
248    }
249   
250  144 return directory;
251    }
252    }