001 package plugins.JavaRolePluginModule;
002
003 import sharpster.common.*;
004
005 public class Merger {
006
007 /** Idé: Första skannet görs med utgångspunkt från parseträdet för partsFile.
008 * Detta skan säkerställer att inga nya element har blivit tillförda
009 * och att inga olovliga ändringar har skett.
010 * Andra skannet görs med utgångspunkt från parseträdet för originalFile.
011 * Detta skan införlivar de nya och modifierade kommentarerna samtidigt
012 * som det säkerställer att inga element har tagits bort.
013 */
014 public static ResponseCollection mergePartsWithRoleDoc(SharedFile originalFile, SharedFile partsFile) {
015 //returvariabeln
016 ResponseCollection returnResponseCollection = new ResponseCollection();
017
018 Body originalFileBody = originalFile.getBody();
019 Body partsFileBody = partsFile.getBody();
020
021 /*test om någon av filern är binärfil (behövs kanske inte)
022 if (originalFileBody.isBinary() || partsFileBody.isBinary()) {
023 JavaRoleResponse res = new JavaRoleResponse();
024 res.setError(true);
025 res.setSubError(SubError.SYNTAX_ERROR);
026 res.setFilename(originalFile.getFileName());
027 returnResponseCollection.addResponse(res);
028 return returnResponseCollection;
029 }*/
030
031 String originalFileStr = new String(originalFileBody.getData());
032 String partsFileStr = new String(partsFileBody.getData());
033
034 ParseTree originalTree=new ParseTree(originalFileStr);
035 ParseTree partsTree=new ParseTree(partsFileStr);
036 if(originalTree.hasSyntaxError() || partsTree.hasSyntaxError()) {
037 JavaRoleResponse res = new JavaRoleResponse();
038 res.setError(true);
039 res.setSubError(SubError.SYNTAX_ERROR);
040 res.setFilename(originalFile.getFileName());
041 returnResponseCollection.addResponse(res);
042 return returnResponseCollection;
043
044 }
045
046 // om alla förändringar är "lagliga" ska orginalfilen uppdateras
047 if (Merger.performUpdateOfDoc(partsTree, originalTree, false)) {
048 System.out.println("OK, updating DOCCOMMENT:s.");
049 Merger.performUpdateOfDoc(originalTree, partsTree, true);
050 }
051 else {
052 System.out.println("Method, Class or variable header changed.");
053 JavaRoleResponse res = new JavaRoleResponse();
054 res.setError(true);
055 res.setSubError(SubError.UNAUTHORISED_CHANGE_IN_FILE);
056 res.setFilename(originalFile.getFileName());
057 returnResponseCollection.addResponse(res);
058 return returnResponseCollection;
059 }
060
061 SharedFilesResponse res = new SharedFilesResponse();
062 FileCollection fc = new FileCollection();
063 SharedFile sf = new SharedFile(originalFile);
064 Body body = new Body();
065
066 body.setData(originalTree.toString().getBytes());
067 sf.setBody(body);
068 fc.addFile(sf);
069
070 res.setFiles(fc);
071
072 returnResponseCollection.addResponse(res);
073 return returnResponseCollection;
074 }
075
076 /** If change==false when this method ensures that no new methodhead,
077 * methodbody, classhead, extra or variable has been added.
078 * @sharpster.micke
079 */
080 private static boolean performUpdateOfDoc(ParseTree originalTree, ParseTree partsTree, boolean change) {
081 Entity currentOriginal=originalTree.getFirstChildOfFile();
082 Entity currentParts=partsTree.getFirstChildOfFile();
083 while(currentOriginal!=null) {
084 switch(currentOriginal.type) {
085 case Entity.CLASSHEAD:
086 //System.out.println("merger.classhead");
087 currentParts=partsTree.getMatching(currentOriginal);
088 if(currentParts==null) {
089 System.out.print("Class head changed at : ");RMTester.print(currentOriginal);
090 return false;
091 }
092 if(change) {
093 mergeDocComment(originalTree,partsTree);
094 }
095 currentOriginal=originalTree.getNext();
096 currentParts=partsTree.getNext();
097 break;
098 case Entity.METHODHEAD:
099 //System.out.println("merger.methodhead");
100 currentParts=partsTree.getMatching(currentOriginal);
101 if(currentParts==null) {
102 System.out.print("Method head changed at : ");RMTester.print(currentOriginal);
103 return false;
104 }
105 if(change) {
106 mergeDocComment(originalTree,partsTree);
107 }
108 currentOriginal=originalTree.getNext();
109 currentParts=partsTree.getNext();
110 break;
111
112 case Entity.VARIABLE:
113 //System.out.println("merger.variable");
114 //System.out.println("c&wspace:"+'"'+currentOriginal.getContentAndWhitespace()+'"');
115 //System.out.println("contents:"+'"'+currentOriginal.getContent()+'"');
116 currentParts=partsTree.getMatching(currentOriginal);
117 if(currentParts==null) {
118 System.out.print("Variable changed at : ");RMTester.print(currentOriginal);
119 return false;
120 }
121 currentOriginal=originalTree.getNext();
122 //currentParts=partsTree.getNext();
123 break;
124 case Entity.ENDOFCLASSBODY:
125 currentOriginal=originalTree.getNext();
126 partsTree.getParent(); // CLASSBODY
127 partsTree.getParent(); // same level as originalTree
128 break;
129 case Entity.CLASSBODY:
130 if(currentParts!=null && currentParts.type==Entity.CLASSBODY) {
131 // hoppa ner en nivå i båda träden
132 currentOriginal=originalTree.getNext();
133 currentParts=partsTree.getNext();
134 }
135 else {
136 // klasskropp borta
137 System.out.print("Body gone at: ");RMTester.print(originalTree.getPrevious());
138 return false;
139 }
140 break;
141 case Entity.METHODBODY:
142 if(!change && currentParts.type!=Entity.SEMICOLON)
143 return false;
144 else {
145 currentOriginal=originalTree.getNext();
146 //currentParts=partsTree.getNext();
147 }
148 break;
149 default:
150 currentOriginal=originalTree.getNext();
151 //currentParts=partsTree.getNext();
152 break;
153 }
154 }
155 return true;
156 }
157
158 /** Updates the doccomment in originalTree according to the
159 * changes in partsTree. The cursor in originalTree should
160 * be positioned at *HEAD. The cursor in originalTree will be
161 * positioned at *HEAD after this method has been executed.
162 */
163 private static void mergeDocComment(ParseTree originalTree, ParseTree partsTree) {
164 Entity docOrig=originalTree.getPrevious(); // never null
165 Entity docParts=partsTree.getPrevious(); // never null
166 Entity currentOrig=docOrig;
167 Entity currentParts=partsTree.getNext();
168 if(docOrig.type==Entity.DOCCOMMENT) {
169 if(docParts.type==Entity.DOCCOMMENT) {
170 //System.out.print("Changing:");RMTester.print(docOrig);
171 currentOrig=originalTree.removeAndGetNext();
172 //System.out.print("New:");RMTester.print(docParts);
173 originalTree.insertBefore(docParts);
174 } else {
175 //System.out.print("No DOCCOMENT in partsTree at:");RMTester.print(docOrig);
176 currentOrig=originalTree.removeAndGetNext();
177 }
178 } else {
179 if(docParts.type==Entity.DOCCOMMENT) {
180 currentOrig=originalTree.getNext();
181 //System.out.print("Inserting:");RMTester.print(docParts);
182 originalTree.insertBefore(docParts);
183 } else {
184 currentOrig=originalTree.getNext();
185 }
186 }
187 //System.out.print("Orig at:");RMTester.print(currentOrig);
188 //System.out.print("Parts at:");RMTester.print(currentParts);
189
190 }
191
192
193 public static ResponseCollection mergePartsWithRole(SharedFile originalFile, SharedFile partsFile, String role) {
194 //returvariabeln
195 ResponseCollection returnResponseCollection = new ResponseCollection();
196
197 Body originalFileBody = originalFile.getBody();
198 Body partsFileBody = partsFile.getBody();
199
200 /*test om någon av filern är binärfil (behövs kanske inte)
201 if (originalFileBody.isBinary() || partsFileBody.isBinary()) {
202 JavaRoleResponse res = new JavaRoleResponse();
203 res.setError(true);
204 res.setSubError(SubError.SYNTAX_ERROR);
205 res.setFilename(originalFile.getFileName());
206 returnResponseCollection.addResponse(res);
207 return returnResponseCollection;
208 }*/
209
210 String originalFileStr = new String(originalFileBody.getData());
211 String partsFileStr = new String(partsFileBody.getData());
212
213 ParseTree originalTree=new ParseTree(originalFileStr);
214 ParseTree partsTree=new ParseTree(partsFileStr);
215
216 if(originalTree.hasSyntaxError() || partsTree.hasSyntaxError()) {
217 JavaRoleResponse res = new JavaRoleResponse();
218 res.setError(true);
219 res.setSubError(SubError.SYNTAX_ERROR);
220 res.setFilename(originalFile.getFileName());
221 returnResponseCollection.addResponse(res);
222 return returnResponseCollection;
223
224 }
225
226 Entity currentOriginal=originalTree.getFirstChildOfFile();
227 Entity currentParts=null;
228 boolean hasAccess=false;
229
230 while(currentOriginal!=null) {
231 switch(currentOriginal.type) {
232 case Entity.METHODHEAD:
233 //System.out.println("merger.methodhead");
234 if(hasAccess) {
235 currentParts=partsTree.getMatching(currentOriginal);
236 if(currentParts==null) {
237 // överträdelsefel, header har blivit ändrad
238 System.out.print("Method head changed at : ");RMTester.print(currentOriginal);
239 JavaRoleResponse res = new JavaRoleResponse();
240 res.setError(true);
241 res.setSubError(SubError.UNAUTHORISED_CHANGE_IN_FILE);
242 res.setFilename(originalFile.getFileName());
243 returnResponseCollection.addResponse(res);
244 return returnResponseCollection;
245 }
246
247 currentOriginal=mergeDocAndBodyAndGetNext(originalTree, partsTree);
248 } else {
249 currentOriginal=originalTree.getNextSkipHeadAndBody();
250 }
251 hasAccess=false;
252 break;
253 case Entity.CLASSHEAD:
254 //System.out.println("merger.classhead");
255 currentParts=partsTree.getMatching(currentOriginal);
256 if(currentParts==null) {
257 // @todo hantera överträdelsefel, header har blivit ändrad
258 System.out.print("Class head changed at : ");RMTester.print(currentOriginal); JavaRoleResponse res = new JavaRoleResponse();
259 res.setError(true);
260 res.setSubError(SubError.UNAUTHORISED_CHANGE_IN_FILE);
261 res.setFilename(originalFile.getFileName());
262 returnResponseCollection.addResponse(res);
263 return returnResponseCollection;
264 }
265 if(hasAccess) {
266 currentOriginal=mergeDocAndBodyAndGetNext(originalTree,partsTree);
267 }
268 else{
269 currentOriginal=originalTree.getNext();
270 currentParts=partsTree.getNext();
271 }
272 hasAccess=false;
273 break;
274 case Entity.DOCCOMMENT:
275 //System.out.println("merger.doccomment");
276 if(currentOriginal.getContent().indexOf("@sharpster."+role)>0) {
277 hasAccess=true;
278 }else{
279 hasAccess=false;
280 }
281 currentOriginal=originalTree.getNext();
282 //System.out.println("hasAccess="+hasAccess);
283 break;
284 case Entity.ENDOFCLASSBODY:
285 //System.out.println("merger.endofclassbody");
286 hasAccess=false;
287 currentOriginal=originalTree.getNext();
288 partsTree.getParent(); // CLASSBODY
289 partsTree.getParent(); // same level as originalTree
290 break;
291 case Entity.CLASSBODY:
292 //System.out.println("merger.classbody");
293 if(currentParts!=null && currentParts.type==Entity.CLASSBODY) {
294 currentOriginal=originalTree.getNext();
295 currentParts=partsTree.getNext();
296 } else {
297 JavaRoleResponse res = new JavaRoleResponse();
298 res.setError(true);
299 res.setSubError(SubError.UNAUTHORISED_CHANGE_IN_FILE);
300 res.setFilename(originalFile.getFileName());
301 returnResponseCollection.addResponse(res);
302 return returnResponseCollection;
303 }
304 break;
305 default:
306 currentOriginal=originalTree.getNext();
307 hasAccess=false;
308 break;
309 }
310 }
311 SharedFilesResponse res = new SharedFilesResponse();
312 FileCollection fc = new FileCollection();
313 SharedFile sf = new SharedFile(originalFile);
314 Body body = new Body();
315
316 body.setData(originalTree.toString().getBytes());
317 sf.setBody(body);
318 fc.addFile(sf);
319
320 res.setFiles(fc);
321
322 returnResponseCollection.addResponse(res);
323 return returnResponseCollection;
324 }
325
326 private static Entity mergeDocAndBodyAndGetNext(ParseTree originalTree, ParseTree partsTree) {
327
328 mergeDocComment(originalTree,partsTree);
329
330 Entity bodyParts=partsTree.getNext(); // body
331 Entity currentParts=partsTree.getNext(); // next element after body
332
333 Entity currentOrig=originalTree.getNext(); // body or semicolon
334
335 //System.out.print("Inserting:");RMTester.print(currentParts);
336 originalTree.insertBefore(bodyParts);
337
338 //System.out.print("Removing:");RMTester.print(currentOrig);
339 currentOrig = originalTree.removeAndGetNext();
340
341 //System.out.print("Orig at:");RMTester.print(currentOrig);
342 //System.out.print("Parts at:");RMTester.print(currentParts);
343
344 return currentOrig;
345 }
346 }
347
348
349