1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.internet2.middleware.shibboleth.common.resource;
18
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23
24 import org.joda.time.DateTime;
25 import org.opensaml.util.resource.AbstractFilteredResource;
26 import org.opensaml.util.resource.ResourceException;
27 import org.opensaml.xml.util.DatatypeHelper;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30 import org.tmatesoft.svn.core.SVNDepth;
31 import org.tmatesoft.svn.core.SVNException;
32 import org.tmatesoft.svn.core.SVNURL;
33 import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
34 import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
35 import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
36 import org.tmatesoft.svn.core.wc.SVNClientManager;
37 import org.tmatesoft.svn.core.wc.SVNRevision;
38 import org.tmatesoft.svn.core.wc.SVNStatus;
39 import org.tmatesoft.svn.core.wc.SVNStatusClient;
40 import org.tmatesoft.svn.core.wc.SVNStatusType;
41 import org.tmatesoft.svn.core.wc.SVNUpdateClient;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public class SVNResource extends AbstractFilteredResource {
60
61
62 private final Logger log = LoggerFactory.getLogger(SVNResource.class);
63
64
65 private final SVNClientManager clientManager;
66
67
68 private SVNURL remoteRepository;
69
70
71 private File workingCopy;
72
73
74 private SVNRevision revision;
75
76
77 private String resourceFileName;
78
79
80
81
82
83
84
85
86
87
88 public SVNResource(SVNClientManager svnClientMgr, SVNURL repositoryUrl, File workingCopyDirectory, long revision,
89 String resourceFile) throws ResourceException {
90 DAVRepositoryFactory.setup();
91 SVNRepositoryFactoryImpl.setup();
92 FSRepositoryFactory.setup();
93 if (svnClientMgr == null) {
94 log.error("SVN client manager may not be null");
95 throw new IllegalArgumentException("SVN client manager may not be null");
96 }
97 clientManager = svnClientMgr;
98
99 if(repositoryUrl == null){
100 throw new IllegalArgumentException("SVN repository URL may not be null");
101 }
102 remoteRepository = repositoryUrl;
103
104 try {
105 checkWorkingCopyDirectory(workingCopyDirectory);
106 workingCopy = workingCopyDirectory;
107 } catch (ResourceException e) {
108 throw new IllegalArgumentException(e.getMessage());
109 }
110
111 if (revision < 0) {
112 this.revision = SVNRevision.HEAD;
113 } else {
114 this.revision = SVNRevision.create(revision);
115 }
116
117 resourceFileName = DatatypeHelper.safeTrimOrNullString(resourceFile);
118 if (resourceFileName == null) {
119 log.error("SVN working copy resource file name may not be null or empty");
120 throw new IllegalArgumentException("SVN working copy resource file name may not be null or empty");
121 }
122
123 checkoutOrUpdateResource();
124 if (!getResourceFile().exists()) {
125 log.error("Resource file " + resourceFile + " does not exist in SVN working copy directory "
126 + workingCopyDirectory.getAbsolutePath());
127 throw new ResourceException("Resource file " + resourceFile
128 + " does not exist in SVN working copy directory " + workingCopyDirectory.getAbsolutePath());
129 }
130 }
131
132
133 public boolean exists() throws ResourceException {
134 return getResourceFile().exists();
135 }
136
137
138 public InputStream getInputStream() throws ResourceException {
139 try {
140 return applyFilter(new FileInputStream(getResourceFile()));
141 } catch (IOException e) {
142 String erroMsg = "Unable to read resource file " + resourceFileName + " from local working copy "
143 + workingCopy.getAbsolutePath();
144 log.error(erroMsg, e);
145 throw new ResourceException(erroMsg, e);
146 }
147 }
148
149
150 public DateTime getLastModifiedTime() throws ResourceException {
151 SVNStatusClient client = clientManager.getStatusClient();
152 client.setIgnoreExternals(false);
153
154 try {
155 SVNStatus status = client.doStatus(getResourceFile(), false);
156 if (status.getContentsStatus() == SVNStatusType.STATUS_NORMAL) {
157 return new DateTime(status.getWorkingContentsDate());
158 } else {
159 String errMsg = "Unable to determine last modified time of resource " + resourceFileName
160 + " within working directory " + workingCopy.getAbsolutePath();
161 log.error(errMsg);
162 throw new ResourceException(errMsg);
163 }
164 } catch (SVNException e) {
165 String errMsg = "Unable to check status of resource " + resourceFileName + " within working directory "
166 + workingCopy.getAbsolutePath();
167 log.error(errMsg, e);
168 throw new ResourceException(errMsg, e);
169 }
170 }
171
172
173 public String getLocation() {
174 return remoteRepository.toDecodedString() + "/" + resourceFileName;
175 }
176
177
178
179
180
181
182
183
184 protected void checkWorkingCopyDirectory(File directory) throws ResourceException {
185 if (directory == null) {
186 log.error("SVN working copy directory may not be null");
187 throw new ResourceException("SVN working copy directory may not be null");
188 }
189
190 if (!directory.exists()) {
191 boolean created = directory.mkdirs();
192 if (!created) {
193 log.error("SVN working copy direction " + directory.getAbsolutePath()
194 + " does not exist and could not be created");
195 throw new ResourceException("SVN working copy direction " + directory.getAbsolutePath()
196 + " does not exist and could not be created");
197 }
198 }
199
200 if (!directory.isDirectory()) {
201 log.error("SVN working copy location " + directory.getAbsolutePath() + " is not a directory");
202 throw new ResourceException("SVN working copy location " + directory.getAbsolutePath()
203 + " is not a directory");
204 }
205
206 if (!directory.canRead()) {
207 log.error("SVN working copy directory " + directory.getAbsolutePath() + " can not be read by this process");
208 throw new ResourceException("SVN working copy directory " + directory.getAbsolutePath()
209 + " can not be read by this process");
210 }
211
212 if (!directory.canWrite()) {
213 log.error("SVN working copy directory " + directory.getAbsolutePath()
214 + " can not be written to by this process");
215 throw new ResourceException("SVN working copy directory " + directory.getAbsolutePath()
216 + " can not be written to by this process");
217 }
218 }
219
220
221
222
223
224
225
226
227
228 protected void checkoutOrUpdateResource() throws ResourceException {
229 SVNUpdateClient client = clientManager.getUpdateClient();
230 client.setIgnoreExternals(false);
231
232 File svnMetadataDir = new File(workingCopy, ".svn");
233 if (!svnMetadataDir.exists()) {
234 try {
235 client.doCheckout(remoteRepository, workingCopy, revision, revision, SVNDepth.INFINITY, true);
236 } catch (SVNException e) {
237 String errMsg = "Unable to check out revsion " + revision.toString() + " from remote repository "
238 + remoteRepository.toDecodedString() + " to local working directory "
239 + workingCopy.getAbsolutePath();
240 log.error(errMsg, e);
241 throw new ResourceException(errMsg, e);
242 }
243 } else {
244 try {
245 client.doUpdate(workingCopy, revision, SVNDepth.INFINITY, true, true);
246 } catch (SVNException e) {
247 String errMsg = "Unable to update working copy of resoure " + remoteRepository.toDecodedString()
248 + " in working copy " + workingCopy.getAbsolutePath() + " to revsion " + revision.toString();
249 log.error(errMsg, e);
250 throw new ResourceException(errMsg, e);
251 }
252 }
253 }
254
255
256
257
258
259
260 protected File getResourceFile() {
261 return new File(workingCopy, resourceFileName);
262 }
263 }