1 | package com.gs3.testGXT.server;
|
---|
2 |
|
---|
3 | import java.io.File;
|
---|
4 | import java.io.IOException;
|
---|
5 | import java.util.LinkedList;
|
---|
6 |
|
---|
7 | import com.google.gwt.user.server.rpc.RemoteServiceServlet;
|
---|
8 | import com.gs3.testGXT.client.services.FileConflictCheckService;
|
---|
9 |
|
---|
10 | @SuppressWarnings("serial")
|
---|
11 | public class FileConflictCheckServiceImpl extends RemoteServiceServlet implements FileConflictCheckService {
|
---|
12 |
|
---|
13 | public final int NO_ERR_CODE = 0;
|
---|
14 | public final int ERR_SOURCE_NOT_FOUND = 1;
|
---|
15 | public final int ERR_SOURCE_NOT_READABLE = 2;
|
---|
16 | public final int ERR_DEST_NOT_WRITEABLE = 3;
|
---|
17 | public final int ERR_FILE_SELF_SIMILAR = 4;
|
---|
18 | public final int ERR_INSUFFICIENT_SPACE = 5;
|
---|
19 |
|
---|
20 | /**
|
---|
21 | * input: list of folders and files to be copied (merged)
|
---|
22 | * output: list of files which conflict with already existing files
|
---|
23 | */
|
---|
24 | @Override
|
---|
25 | public LinkedList<String[]> fileConflictCheck(LinkedList<String> paths, String remoteTarget) {
|
---|
26 | CheckConflictInstance instance = new CheckConflictInstance();
|
---|
27 | return instance.fileConflictCheck(paths, remoteTarget);
|
---|
28 | }
|
---|
29 |
|
---|
30 | private class CheckConflictInstance {
|
---|
31 | private LinkedList<String[]> res;
|
---|
32 | private int conflicts = 0;
|
---|
33 |
|
---|
34 | public LinkedList<String[]> fileConflictCheck(LinkedList<String> paths, String remoteTarget) {
|
---|
35 | res = new LinkedList<String[]>();
|
---|
36 | // Structure:
|
---|
37 | // first string[] is return status
|
---|
38 | // second and following are conflicts
|
---|
39 | File target = new File(remoteTarget);
|
---|
40 | String[] response;
|
---|
41 | String basePath = null;
|
---|
42 | if(target.isDirectory()) {
|
---|
43 | for(String path : paths) {
|
---|
44 | int i = path.lastIndexOf("/");
|
---|
45 | basePath = path.substring(0, i); //TODO: if necessary, add 1 to that index?
|
---|
46 | checkConflict(path, remoteTarget, basePath);
|
---|
47 | }
|
---|
48 |
|
---|
49 | if(conflicts == 0) { //at this point, we can probably just perform the copy serverside
|
---|
50 | response = new String[] {"Success", conflicts + " conflicting files detected"};
|
---|
51 | }
|
---|
52 | else { //we need to get confirmation before we do the copy
|
---|
53 | response = new String[] {"Warning", conflicts + " conflicting files detected"};
|
---|
54 | }
|
---|
55 | }
|
---|
56 | else { //we shouldn't be able to do this unless we have some multi-user trickery going on
|
---|
57 | response = new String[] {"Error", "The item at '" + remoteTarget + "' is not a directory, and cannot be made to contain files."};
|
---|
58 | }
|
---|
59 | System.err.println();
|
---|
60 | res.addFirst(response);
|
---|
61 | printArr(response);
|
---|
62 | return res;
|
---|
63 | }
|
---|
64 |
|
---|
65 | //TODO: replace this with an iterative stack-based solution,
|
---|
66 | // to avoid any potential stack overflow errors on extremely large file-systems:
|
---|
67 | // low priority, but would be needed for a final solution
|
---|
68 | private void checkConflict(String fullFromPath, String remoteTarget, String baseFromPath) {
|
---|
69 | //Structure:
|
---|
70 | // file:
|
---|
71 | // warn on conflict
|
---|
72 | // folder:
|
---|
73 | // recurse on conflict
|
---|
74 | // only root level elements are given as crossfunction input, so we can recurse on the children of those elements
|
---|
75 | String modifiedPath = fullFromPath.substring(baseFromPath.length(), fullFromPath.length());
|
---|
76 | String outputPath = remoteTarget + modifiedPath;
|
---|
77 | System.err.println("Base path: " + baseFromPath);
|
---|
78 | System.err.println("Resultant path: " + modifiedPath);
|
---|
79 | System.err.println("output path: " + outputPath);
|
---|
80 |
|
---|
81 | //check if the input file exists
|
---|
82 | File destination = new File(outputPath);
|
---|
83 |
|
---|
84 | //check that we aren't replacing the same file with itself on the filesystem
|
---|
85 | File source = new File(fullFromPath);
|
---|
86 |
|
---|
87 | /** We ensure that the source file actually does exist - just incase the user had a stale version of the tree */
|
---|
88 | if(!source.exists()) {
|
---|
89 | String[] str = new String[]{"Error", destination.getName(), destination.getPath(),
|
---|
90 | source.getPath(), "" + source.length(), "" + ERR_SOURCE_NOT_FOUND};
|
---|
91 |
|
---|
92 | System.err.println("The source file does not exist");
|
---|
93 |
|
---|
94 | conflicts++;
|
---|
95 | res.add(str);
|
---|
96 | return;
|
---|
97 | }
|
---|
98 |
|
---|
99 | //we need to make sure we can actually read this file
|
---|
100 | if(!source.canRead()/* && source.canExecute()*/) {
|
---|
101 | String[] str = new String[]{"Error", destination.getName(), destination.getPath(),
|
---|
102 | source.getPath(), "" + source.length(), "" + ERR_SOURCE_NOT_READABLE};
|
---|
103 |
|
---|
104 | System.err.println("The source file does not exist");
|
---|
105 |
|
---|
106 | conflicts++;
|
---|
107 | res.add(str);
|
---|
108 | return;
|
---|
109 | }
|
---|
110 |
|
---|
111 | /** Here, we check if we're copying a file into itself - we can omit the error message, and just ignore these cases in the future */
|
---|
112 | if(source.getAbsolutePath().equals(destination.getAbsolutePath())) {
|
---|
113 | //TODO: this one should ACTUALLY be an ignore - or should it?
|
---|
114 | String[] str = new String[]{"Error", destination.getName(), destination.getPath(),
|
---|
115 | source.getPath(), "" + source.length(), "" + ERR_FILE_SELF_SIMILAR};
|
---|
116 |
|
---|
117 | System.err.println("Detected attempt to replace file with itself");
|
---|
118 |
|
---|
119 | conflicts++;
|
---|
120 | res.add(str);
|
---|
121 | return; //try not to replace a file with itself
|
---|
122 | }
|
---|
123 |
|
---|
124 | //Response Structure:
|
---|
125 | //
|
---|
126 | // Conflict/No Conflict
|
---|
127 | // Destination Name
|
---|
128 | // Destination Path
|
---|
129 | // Source Path
|
---|
130 | // File Size (if not folder - just give 0 for those)
|
---|
131 | // Error Code (if one exists)
|
---|
132 |
|
---|
133 | /** check if the destination exists - needed for merge/replace operations */
|
---|
134 | if(destination.exists()) {
|
---|
135 | //file exists: this means there is a conflict
|
---|
136 | System.err.println("Conflict: the file '" + outputPath + "' already exists!");
|
---|
137 |
|
---|
138 | if(destination.isDirectory()) {
|
---|
139 | //we need to make a check and see if the file on the left is a directory
|
---|
140 | if(source.isDirectory()) {
|
---|
141 | //if it conflicts and is a directory, we do a recursive check
|
---|
142 | File[] children = source.listFiles();
|
---|
143 | for(File child : children) {
|
---|
144 | try {
|
---|
145 | checkConflict(child.getCanonicalPath(), remoteTarget, baseFromPath);
|
---|
146 | } catch (IOException e) {
|
---|
147 | e.printStackTrace();
|
---|
148 | }
|
---|
149 | }
|
---|
150 | }
|
---|
151 | else {//the file on the left is a file: we may be replacing a folder with a file.
|
---|
152 |
|
---|
153 | //we need to make sure that we have permissions to delete the file
|
---|
154 | if(!(destination.canRead() && destination.canWrite())) {
|
---|
155 | String[] str = new String[]{"Error", destination.getName(), destination.getPath(),
|
---|
156 | source.getPath(), "" + source.length(), "" + ERR_DEST_NOT_WRITEABLE};
|
---|
157 |
|
---|
158 | System.err.println("The source file does not exist");
|
---|
159 |
|
---|
160 | conflicts++;
|
---|
161 | res.add(str);
|
---|
162 | return;
|
---|
163 | }
|
---|
164 |
|
---|
165 | String[] str = new String[]{"Conflict", destination.getName(), destination.getPath(), source.getPath(), "" + source.length()};
|
---|
166 | res.add(str);
|
---|
167 | conflicts++;
|
---|
168 | }
|
---|
169 | }
|
---|
170 | else if (destination.isFile()) {
|
---|
171 | //if it conflicts and is a file, then we create a warning
|
---|
172 | // conflict, file, location
|
---|
173 | String[] str = new String[]{"Conflict", destination.getName(), destination.getPath(), source.getPath(), "" + source.length()};
|
---|
174 | res.add(str);
|
---|
175 | conflicts++;
|
---|
176 | }
|
---|
177 | }
|
---|
178 | /** The destination doesn't exist - we're free to do whatever */
|
---|
179 | else {
|
---|
180 | //we want to specifically check any children (if they exist) as well - primarily just for permissions
|
---|
181 | if(source.isDirectory()) { //if it's a directory and has children, we must also check those children (to get the file sizes)
|
---|
182 | File[] children = source.listFiles();
|
---|
183 | if(children != null && children.length > 0) { //the != null check can probably be used in place of the directory check
|
---|
184 | //check specifically each child - we're copying these
|
---|
185 | for(File child : children) {
|
---|
186 | try {
|
---|
187 | checkConflict(child.getCanonicalPath(), remoteTarget, baseFromPath);
|
---|
188 | } catch (IOException e) {
|
---|
189 | e.printStackTrace(); //TODO: update this - something more meaningful has to happen here...
|
---|
190 | }
|
---|
191 | }
|
---|
192 | return;
|
---|
193 | }
|
---|
194 | }
|
---|
195 | String[] str = new String[]{"No Conflict", destination.getName(), destination.getPath(), source.getPath(), "" + source.length()};
|
---|
196 | res.add(str);
|
---|
197 | }
|
---|
198 | }
|
---|
199 |
|
---|
200 | private void printArr(String[] input) {
|
---|
201 | for (int i = 0; i < input.length; i++)
|
---|
202 | if(i == input.length -1)
|
---|
203 | System.err.print(input[i]);
|
---|
204 | else
|
---|
205 | System.err.print(input[i] + ": ");
|
---|
206 | System.err.println();
|
---|
207 | }
|
---|
208 | }
|
---|
209 | }
|
---|