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