View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
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    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.argeo.slc.core.execution;
17  
18  import java.io.File;
19  import java.io.FileOutputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.OutputStream;
23  import java.text.SimpleDateFormat;
24  import java.util.Date;
25  
26  import org.apache.commons.io.IOUtils;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.argeo.slc.SlcException;
30  import org.argeo.slc.execution.ExecutionContext;
31  import org.springframework.core.io.FileSystemResource;
32  import org.springframework.core.io.Resource;
33  import org.springframework.util.Assert;
34  
35  /** Implements write access to resources based on standard Java {@link File} */
36  public class FileExecutionResources implements ExecutionResources {
37  	private final static Log log = LogFactory
38  			.getLog(FileExecutionResources.class);
39  	protected final static String DEFAULT_EXECUTION_RESOURCES_DIRNAME = "executionResources";
40  	public final static String DEFAULT_EXECUTION_RESOURCES_TMP_PATH = System
41  			.getProperty("java.io.tmpdir")
42  			+ File.separator
43  			+ System.getProperty("user.name")
44  			+ File.separator
45  			+ "slc"
46  			+ File.separator + DEFAULT_EXECUTION_RESOURCES_DIRNAME;
47  
48  	private File baseDir;
49  	private ExecutionContext executionContext;
50  	private String prefixDatePattern = "yyMMdd_HHmmss_SSS";
51  	private SimpleDateFormat sdf = null;
52  
53  	private Boolean withExecutionSubdirectory = true;
54  
55  	public FileExecutionResources() {
56  		// Default base directory
57  		String osgiInstanceArea = System.getProperty("osgi.instance.area");
58  		String osgiInstanceAreaDefault = System
59  				.getProperty("osgi.instance.area.default");
60  
61  		if (osgiInstanceArea != null) {
62  			// within OSGi with -data specified
63  			osgiInstanceArea = removeFilePrefix(osgiInstanceArea);
64  			baseDir = new File(osgiInstanceArea + File.separator
65  					+ DEFAULT_EXECUTION_RESOURCES_DIRNAME);
66  		} else if (osgiInstanceAreaDefault != null) {
67  			// within OSGi without -data specified
68  			osgiInstanceAreaDefault = removeFilePrefix(osgiInstanceAreaDefault);
69  			baseDir = new File(osgiInstanceAreaDefault + File.separator
70  					+ DEFAULT_EXECUTION_RESOURCES_DIRNAME);
71  		} else {// outside OSGi
72  			baseDir = new File(DEFAULT_EXECUTION_RESOURCES_TMP_PATH);
73  		}
74  	}
75  
76  	protected SimpleDateFormat sdf() {
77  		// Lazy init in case prefix has been externally set
78  		if (sdf == null)
79  			sdf = new SimpleDateFormat(prefixDatePattern);
80  		return sdf;
81  	}
82  
83  	public Resource getWritableResource(String relativePath) {
84  		File file = getFile(relativePath);
85  		File parentDir = file.getParentFile();
86  
87  		if (!parentDir.exists()) {
88  			// Creates if necessary
89  			if (log.isTraceEnabled())
90  				log.trace("Creating parent directory " + parentDir);
91  			parentDir.mkdirs();
92  		}
93  		Resource resource = new FileSystemResource(file);
94  
95  		if (log.isTraceEnabled())
96  			log.trace("Returns writable resource " + resource);
97  		return resource;
98  	}
99  
100 	public String getWritableOsPath(String relativePath) {
101 		try {
102 			return getFile(relativePath).getCanonicalPath();
103 		} catch (IOException e) {
104 			throw new SlcException("Cannot find canonical path", e);
105 		}
106 	}
107 
108 	public File getWritableOsFile(String relativePath) {
109 		return getFile(relativePath);
110 	}
111 
112 	public String getAsOsPath(Resource resource, Boolean overwrite) {
113 		File file = fileFromResource(resource);
114 		if (file != null)
115 			try {
116 				if (log.isTraceEnabled())
117 					log.debug("Directly interpret " + resource + " as OS file "
118 							+ file);
119 				return file.getCanonicalPath();
120 			} catch (IOException e1) {
121 				// silent
122 			}
123 
124 		if (log.isTraceEnabled())
125 			log.trace("Resource " + resource
126 					+ " is not available on the file system. Retrieving it...");
127 
128 		InputStream in = null;
129 		OutputStream out = null;
130 		try {
131 			String path = resource.getURL().getPath();
132 			file = getFile(path);
133 			if (file.exists() && !overwrite)
134 				return file.getCanonicalPath();
135 
136 			file.getParentFile().mkdirs();
137 			in = resource.getInputStream();
138 			out = new FileOutputStream(file);
139 			IOUtils.copy(in, out);
140 			if (log.isDebugEnabled())
141 				log.debug("Retrieved " + resource + " to OS file " + file);
142 			return file.getCanonicalPath();
143 		} catch (IOException e) {
144 			throw new SlcException("Could not make resource " + resource
145 					+ " an OS file.", e);
146 		} finally {
147 			IOUtils.closeQuietly(in);
148 			IOUtils.closeQuietly(out);
149 		}
150 	}
151 
152 	/**
153 	 * Extract the underlying file from the resource.
154 	 * 
155 	 * @return the file or null if no files support this resource.
156 	 */
157 	protected File fileFromResource(Resource resource) {
158 		try {
159 			return resource.getFile();
160 		} catch (IOException e) {
161 			return null;
162 		}
163 
164 	}
165 
166 	protected File getFile(String relativePath) {
167 		File writableBaseDir = getWritableBaseDir();
168 		return new File(writableBaseDir.getPath() + File.separator
169 				+ relativePath.replace('/', File.separatorChar));
170 	}
171 
172 	public File getWritableBaseDir() {
173 		if (withExecutionSubdirectory) {
174 			Date executionContextCreationDate = (Date) executionContext
175 					.getVariable(ExecutionContext.VAR_EXECUTION_CONTEXT_CREATION_DATE);
176 			Assert.notNull(executionContext, "execution context is null");
177 			String path = baseDir.getPath() + File.separator
178 					+ sdf().format(executionContextCreationDate);
179 			// TODO write execution id somewhere? like in a txt file
180 			return new File(path);
181 		} else {
182 			return baseDir;
183 		}
184 	}
185 
186 	protected String removeFilePrefix(String url) {
187 		if (url.startsWith("file:"))
188 			return url.substring("file:".length());
189 		else if (url.startsWith("reference:file:"))
190 			return url.substring("reference:file:".length());
191 		else
192 			return url;
193 	}
194 
195 	public void setBaseDir(File baseDir) {
196 		this.baseDir = baseDir;
197 	}
198 
199 	public void setExecutionContext(ExecutionContext executionContext) {
200 		this.executionContext = executionContext;
201 	}
202 
203 	public void setPrefixDatePattern(String prefixDatePattern) {
204 		this.prefixDatePattern = prefixDatePattern;
205 	}
206 
207 	public File getBaseDir() {
208 		return baseDir;
209 	}
210 
211 	public ExecutionContext getExecutionContext() {
212 		return executionContext;
213 	}
214 
215 	public String getPrefixDatePattern() {
216 		return prefixDatePattern;
217 	}
218 
219 	/** Default is true. */
220 	public void setWithExecutionSubdirectory(Boolean withExecutionSubdirectory) {
221 		this.withExecutionSubdirectory = withExecutionSubdirectory;
222 	}
223 
224 }