1 /**
2 * Copyright 2005-2006 the original author or authors.
3 *
4 * Licensed under the Gnu General Pubic License, Version 2.0 (the
5 * "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/gpl-license.php
9 *
10 * This program 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.
13 * See the Gnu General Public License for more details.
14 */
15 package org.figure8.join.services.repository;
16
17 import org.figure8.join.businessobjects.artifact.Artifact;
18 import org.figure8.join.util.LogUtil;
19
20 import org.apache.commons.vfs.VFS;
21 import org.apache.commons.vfs.FileType;
22 import org.apache.commons.vfs.FileObject;
23 import org.apache.commons.vfs.FileSelector;
24 import org.apache.commons.vfs.FileSelectInfo;
25 import org.apache.commons.vfs.FileSystemManager;
26 import org.apache.commons.vfs.FileSystemException;
27 import org.apache.commons.logging.Log;
28
29 import java.io.File;
30 import java.io.InputStream;
31 import java.io.OutputStream;
32 import java.io.FileInputStream;
33 /**
34 * This is an implementation of {@link Repository} using Jakarta VFS Commons.
35 * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
36 * @version $Revision: 1.2 $
37 */
38 public class VFSRepository extends AbstractStructuredRepository{
39
40
41
42 /** Get a commons logger. */
43 private static final Log log = LogUtil.getLog(VFSRepository.class);
44
45
46
47
48 /** String representation of the repository base url */
49 private String baseUrl = null;
50
51
52
53
54 /** Creates a new instance of VFSRepository. */
55 public VFSRepository(){
56 }
57
58
59
60
61 /**
62 * Get the base url (string representation) of the physical repository to access
63 * @return The base url of the repository
64 */
65 public String getBaseUrl(){
66 return baseUrl;
67 }
68 /**
69 * Set the base url (string representation) of the physical repository to access
70 * @param baseUrl The base url of the repository
71 */
72 public void setBaseUrl(String baseUrl){
73 if (!baseUrl.endsWith("/"))
74 baseUrl += "/";
75 this.baseUrl = baseUrl;
76 }
77
78
79
80
81 /**
82 * Retrieve the input stream corresponding to a given Artifact. This
83 * method can be used for artifact content downloading or retrieval.
84 * @param artifact The domain object representing artifact to retrieve
85 * @return An {@code InputStream} on artifact content
86 * @throws ConnectionException if physical repository cannot be connected
87 * @throws TransferException if something wrong occur after connection, during transfer
88 */
89 public InputStream getArtifact(Artifact artifact) throws ConnectionException, TransferException{
90 log.info("Retrieving stream of artifact with id: " + artifact.getUniqueId());
91
92 String structurePath = getStructurePath(artifact);
93 if (!structurePath.endsWith("/"))
94 structurePath += "/";
95
96
97 String target = baseUrl + structurePath;
98
99 FileObject[] files = null;
100 try{
101 FileSystemManager fsManager = VFS.getManager();
102 FileObject parentDir = fsManager.resolveFile(structurePath);
103 parentDir.findFiles(getArtifactFileSelector(artifact));
104 }
105 catch (FileSystemException fse){
106
107 log.error("Exception while resolving the file into repository: " + target);
108 throw new ConnectionException("Exception while resolving target file into repository", fse);
109 }
110
111 if (files == null || files.length == 0){
112 log.error("There's no file coresponding to artifact " + artifact.getUniqueId());
113 throw new ConnectionException("Repository is in an unsafe state",
114 new IllegalStateException("No file available for artifact"));
115 }
116 FileObject artifactFile = files[0];
117 try{
118
119 if (!artifactFile.getType().equals(FileType.FILE)){
120 log.error("ArtifactFile is not a valid file: " + artifactFile.getName().toString());
121 throw new ConnectionException("Repository is in an unsafe state",
122 new IllegalStateException("No valid file for artifact"));
123 }
124
125 if (!artifactFile.isReadable()){
126 log.error("ArtifactFile is not a readable file: " + artifactFile.getName().toString());
127 throw new ConnectionException("Repository is in an unsafe state",
128 new IllegalStateException("File for artifact not readable"));
129 }
130 }
131 catch (FileSystemException fse){
132
133 log.error("Exception while accessing the properties of file: " + artifactFile.getName().toString());
134 throw new ConnectionException("Exception while accessing the properties of artifact file", fse);
135 }
136 try{
137
138 return artifactFile.getContent().getInputStream();
139 }
140 catch (Exception e){
141
142 log.error("Exception while creating input stream onto file " + artifactFile.getName().toString());
143 throw new TransferException("Exception while creating input stream on artifact", e);
144 }
145 }
146
147 /**
148 * Store the content of a given Artifact within repository datastore.
149 * @param artifact The domain object representing artifact to store
150 * @param content File representing artifact content (may be a directory)
151 * @throws ConnectionException if physical repository cannot be connected
152 * @throws TransferException if something wrong occur after connection, during transfer
153 */
154 public void storeArtifact(Artifact artifact, File content) throws ConnectionException, TransferException{
155 log.info("Storing file of artifact with id: " + artifact.getUniqueId());
156
157 String structurePath = getStructurePath(artifact);
158 if (!structurePath.endsWith("/"))
159 structurePath += "/";
160
161
162 String target = baseUrl + structurePath;
163 if (content.getName().lastIndexOf(".") != -1){
164
165 target += artifact.getUniqueId() + content.getName().substring(content.getName().lastIndexOf("."));
166 log.debug("Content has an extension. Target path is " + target);
167 }
168 else{
169
170 target += artifact.getUniqueId();
171 log.debug("Content has no extension. Target path is " + target);
172 }
173
174
175 FileObject dest = null;
176 try{
177 FileSystemManager fsManager = VFS.getManager();
178 dest = fsManager.resolveFile(target);
179 }
180 catch (FileSystemException fse){
181
182 log.error("Exception while resolving the file into repository: " + target);
183 throw new ConnectionException("Exception while resolving target file into repository", fse);
184 }
185
186
187 OutputStream os = null;
188 FileInputStream contentFis = null;
189 try{
190 os = dest.getContent().getOutputStream();
191 contentFis = new FileInputStream(content);
192 }
193 catch (Exception e){
194 e.printStackTrace();
195
196 log.error("Exception while opening copy streams into repository for: " + target);
197 throw new ConnectionException("Exception while opening copy streams into repository", e);
198 }
199 writeStream(contentFis, os);
200 }
201
202 /**
203 * Store the content of a given Artifact within repository datastore using an input stream.
204 * @param artifact The domain object representing artifact to store
205 * @param is InputStream on artifact content
206 * @throws ConnectionException if physical repository cannot be connected
207 * @throws TransferException if something wrong occur after connection, during transfer
208 */
209 public void storeArtifact(Artifact artifact, InputStream is) throws ConnectionException, TransferException{
210 log.info("Storing stream of artifact with id: " + artifact.getUniqueId());
211
212 String structurePath = getStructurePath(artifact);
213 if (!structurePath.endsWith("/"))
214 structurePath += "/";
215
216
217 String target = baseUrl + structurePath + artifact.getUniqueId();
218 log.debug("Content is an InputStream. Target file path is " + target);
219
220
221 FileObject dest = null;
222 try{
223 FileSystemManager fsManager = VFS.getManager();
224 dest = fsManager.resolveFile(target);
225 }
226 catch (FileSystemException fse){
227
228 log.error("Exception while resolving the file into repository: " + target);
229 throw new ConnectionException("Exception while resolving target file into repository", fse);
230 }
231
232
233 OutputStream os = null;
234 try {os = dest.getContent().getOutputStream();}
235 catch (Exception e){
236
237 log.error("Exception while opening copy streams into repository for: " + target);
238 throw new ConnectionException("Exception while opening copy streams into repository", e);
239 }
240 writeStream(is, os);
241 }
242
243
244
245
246 /**
247 * Write an input stream content to a target output stream. This method closes
248 * the input and output streams at the end of write operation.
249 * @param is The input stream to use for getting data
250 * @param os The output stream to use for writing data
251 * @throws TransferException if an IOException occurs during writing output
252 */
253 private void writeStream(InputStream is, OutputStream os) throws TransferException{
254 try{
255
256 int bytes = 0;
257 byte[] buffer = new byte[8192];
258 while ((bytes = is.read(buffer, 0, 8192)) != -1)
259 os.write(buffer, 0, bytes);
260 }
261 catch (Exception e){
262
263 log.error("IOException while writing into stream: " + os);
264 throw new TransferException("IOException while writing into target stream", e);
265 }
266 finally{
267 try {is.close();}
268 catch (Exception e) {
269 try {os.close();}
270 catch (Exception e) {
271 }
272 }
273
274 /**
275 * Get a FileSelector implementation for filtering files
276 * corresponding to artifact.
277 * @return A FileSelector for artifact
278 */
279 private FileSelector getArtifactFileSelector(final Artifact artifact){
280 return new FileSelector(){
281 public boolean includeFile(FileSelectInfo info){
282 return info.getFile().getName().getBaseName().startsWith(artifact.getUniqueId());
283 }
284 public boolean traverseDescendents(FileSelectInfo info){
285 return false;
286 }
287 };
288 }
289 }