View Javadoc

1   /**
2    * Copyright 2010-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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.kuali.common.util.sync;
17  
18  import java.io.File;
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.List;
22  
23  import org.kuali.common.util.CollectionUtils;
24  import org.kuali.common.util.FileSystemUtils;
25  import org.kuali.common.util.SyncResult;
26  import org.kuali.common.util.execute.CopyFileRequest;
27  import org.kuali.common.util.execute.CopyFileResult;
28  import org.kuali.common.util.file.DirDiff;
29  import org.kuali.common.util.file.DirRequest;
30  import org.kuali.common.util.file.MD5Result;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  public class DefaultSyncService implements SyncService {
35  
36  	private static final Logger logger = LoggerFactory.getLogger(DefaultSyncService.class);
37  
38  	@Override
39  	public DirDiff getDiff(DirRequest request) {
40  		List<DirRequest> requests = Arrays.asList(request);
41  		List<DirDiff> results = getDiffs(requests);
42  		return results.get(0);
43  	}
44  
45  	@Override
46  	public List<DirDiff> getDiffs(List<DirRequest> requests) {
47  		List<DirDiff> diffs = new ArrayList<DirDiff>();
48  		for (DirRequest request : requests) {
49  			DirDiff diff = FileSystemUtils.getMD5Diff(request);
50  			diffs.add(diff);
51  		}
52  		return diffs;
53  	}
54  
55  	@Override
56  	public SyncResult sync(DirRequest request) {
57  		List<DirRequest> requests = Arrays.asList(request);
58  		List<SyncResult> results = sync(requests);
59  		return results.get(0);
60  	}
61  
62  	@Override
63  	public List<SyncResult> sync(List<DirRequest> requests) {
64  
65  		logger.info("Synchronizing {} directories", requests.size());
66  		for (DirRequest request : requests) {
67  			String src = FileSystemUtils.getRelativePathQuietly(request.getRelativeDir(), request.getSourceDir());
68  			String dst = FileSystemUtils.getRelativePathQuietly(request.getRelativeDir(), request.getTargetDir());
69  			logger.info("  [{}] -> [{}]", src, dst);
70  		}
71  
72  		// Scan the file system and record the differences between the directories.
73  		// This does a deep, heavy, scan of both directories.
74  		// It recursively examines the contents of both directories.
75  		// Files that exist in both, are compared for equality using an MD5 checksum
76  		List<DirDiff> diffs = getDiffs(requests);
77  
78  		// Use the diff info to generate a list of files to copy
79  		List<CopyFileRequest> copyRequests = getCopyFileRequests(diffs);
80  
81  		// Show how many files we are copying
82  		if (copyRequests.size() > 0) {
83  			logger.info("Copying {} files", copyRequests.size());
84  		}
85  
86  		// Copy the files and record the results
87  		List<CopyFileResult> copyResults = FileSystemUtils.copyFiles(copyRequests);
88  
89  		// Log the number of files copied
90  		logger.debug("Copied {} files", copyResults.size());
91  
92  		// Convert the diff information into sync information (adds, deletes, updates)
93  		List<SyncResult> results = getSyncResults(diffs);
94  
95  		// return the sync info
96  		return results;
97  	}
98  
99  	protected List<SyncResult> getSyncResults(List<DirDiff> diffs) {
100 		List<SyncResult> results = new ArrayList<SyncResult>();
101 		for (DirDiff diff : diffs) {
102 			SyncResult result = getSyncResult(diff);
103 			results.add(result);
104 		}
105 		return results;
106 	}
107 
108 	protected SyncResult getSyncResult(DirDiff diff) {
109 		List<File> adds = FileSystemUtils.getFullPaths(diff.getTargetDir(), diff.getSourceDirOnly());
110 		List<File> deletes = FileSystemUtils.getFullPaths(diff.getTargetDir(), diff.getTargetDirOnly());
111 		List<File> updates = new ArrayList<File>();
112 		for (MD5Result result : diff.getDifferent()) {
113 			updates.add(result.getTarget());
114 		}
115 
116 		SyncResult result = new SyncResult();
117 		result.setAdds(adds);
118 		result.setDeletes(deletes);
119 		result.setUpdates(updates);
120 		return result;
121 	}
122 
123 	protected List<CopyFileRequest> getCopyFileRequests(List<DirDiff> diffs) {
124 		List<CopyFileRequest> copyRequests = new ArrayList<CopyFileRequest>();
125 		for (DirDiff diff : diffs) {
126 			List<CopyFileRequest> list = getCopyFileRequests(diff);
127 			copyRequests.addAll(list);
128 		}
129 		return copyRequests;
130 	}
131 
132 	/**
133 	 * Convert the diff into requests for copying files.
134 	 */
135 	protected List<CopyFileRequest> getCopyFileRequests(DirDiff diff) {
136 
137 		// Copy all the files that were in source dir only
138 		List<CopyFileRequest> source = getCopyFileRequests(diff, diff.getSourceDirOnly());
139 
140 		// Copy files that are in both directories but have different contents
141 		List<CopyFileRequest> different = getCopyFileRequestsForFilesThatAreDifferent(diff.getDifferent());
142 
143 		// Return the combined list
144 		return CollectionUtils.combine(different, source);
145 	}
146 
147 	protected List<CopyFileRequest> getCopyFileRequestsForFilesThatAreDifferent(List<MD5Result> different) {
148 		List<CopyFileRequest> requests = new ArrayList<CopyFileRequest>();
149 		for (MD5Result md5Result : different) {
150 			File source = md5Result.getSource();
151 			File target = md5Result.getTarget();
152 			CopyFileRequest request = new CopyFileRequest(source, target);
153 			requests.add(request);
154 		}
155 		return requests;
156 	}
157 
158 	protected List<CopyFileRequest> getCopyFileRequests(DirDiff diff, List<String> relativePaths) {
159 		List<CopyFileRequest> requests = new ArrayList<CopyFileRequest>();
160 		for (String relativePath : relativePaths) {
161 			File source = new File(diff.getSourceDir(), relativePath);
162 			File target = new File(diff.getTargetDir(), relativePath);
163 			CopyFileRequest request = new CopyFileRequest(source, target);
164 			requests.add(request);
165 		}
166 		return requests;
167 	}
168 
169 }