Skip to content

Package: ClipToFileTask

ClipToFileTask

nameinstructionbranchcomplexitylinemethod
ClipToFileTask(TaskExecutor, ClipperConfiguration)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
containsTransitive(DependencyTask)
M: 0 C: 2
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
createDirectoryForClass(String)
M: 12 C: 44
79%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 1 C: 10
91%
M: 0 C: 1
100%
doWork()
M: 6 C: 17
74%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 2 C: 4
67%
M: 0 C: 1
100%
extractClassComment(File, String, String)
M: 0 C: 64
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 13
100%
M: 0 C: 1
100%
extractNonGenerationPart(File, String)
M: 0 C: 65
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
findCorrespondingClosingCurlyBracket(int, String)
M: 5 C: 70
93%
M: 1 C: 7
88%
M: 1 C: 4
80%
M: 1 C: 13
93%
M: 0 C: 1
100%
parseAttributeToFile(String, String, File)
M: 0 C: 52
100%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 9
100%
M: 0 C: 1
100%
parseImportsToFile(String, String, File)
M: 0 C: 17
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
parseOperationToFile(String, String, File)
M: 17 C: 125
88%
M: 3 C: 11
79%
M: 3 C: 5
63%
M: 2 C: 28
93%
M: 0 C: 1
100%
removeLeadingWhiteBreaks(String)
M: 0 C: 44
100%
M: 0 C: 8
100%
M: 0 C: 5
100%
M: 0 C: 14
100%
M: 0 C: 1
100%
repairGenerics(String[])
M: 24 C: 42
64%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 1 C: 8
89%
M: 0 C: 1
100%
replaceIllegalChars(String)
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
scanFileToDirectory(File, File)
M: 0 C: 16
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
scanFileToDirectoryInternal(File, ClipperJavaFileShadowCopy)
M: 24 C: 176
88%
M: 5 C: 15
75%
M: 4 C: 7
64%
M: 3 C: 44
94%
M: 0 C: 1
100%
walkThroughJava(File)
M: 0 C: 84
100%
M: 0 C: 6
100%
M: 0 C: 4
100%
M: 0 C: 16
100%
M: 0 C: 1
100%

Coverage

1: package de.fhdw.wtf.generator.transformer.clipper;
2:
3: import java.io.File;
4: import java.io.IOException;
5: import java.util.ArrayList;
6: import java.util.Iterator;
7: import java.util.List;
8: import java.util.regex.Matcher;
9: import java.util.regex.Pattern;
10:
11: import de.fhdw.wtf.common.exception.walker.TaskException;
12: import de.fhdw.wtf.common.task.DependencyTask;
13: import de.fhdw.wtf.common.task.TaskExecutor;
14: import de.fhdw.wtf.common.task.result.ExceptionalTaskResult;
15: import de.fhdw.wtf.common.task.result.OKTaskResult;
16: import de.fhdw.wtf.common.task.result.TaskResult;
17: import de.fhdw.wtf.file.FileUtils;
18: import de.fhdw.wtf.generator.transformer.clipper.internal.ClipperJavaFileShadowCopy;
19: import de.fhdw.wtf.generator.transformer.exception.ClipperImportFormatException;
20: import de.fhdw.wtf.generator.transformer.util.Tuple;
21:
22: /**
23: * Extracts methods from current java project into Clipper repository.
24: *
25: */
26: public class ClipToFileTask extends DependencyTask {
27:         
28:         /**
29:          * Constant for "}".
30:          */
31:         private static final String CURLY_BRACKET_CLOSE = "}";
32:         
33:         /**
34:          * Constant for "{".
35:          */
36:         private static final String CURLY_BRACKET_OPEN = "{";
37:         
38:         /**
39:          * Constant for "/".
40:          */
41:         private static final String FILESYSTEM_PATH_SEPERATOR = "/";
42:         
43:         /**
44:          * Constant for "\\".
45:          */
46:         private static final String BRACKET_CLOSE = "\\)";
47:         
48:         /**
49:          * Constant for "\\(".
50:          */
51:         private static final String BRACKET_OPEN = "\\(";
52:         
53:         /**
54:          * The associated clipper configuration.
55:          */
56:         private final ClipperConfiguration configuration;
57:         
58:         /**
59:          * This task extracts methods, attributes and comments from the Java source code into the Clipper repository.
60:          *
61:          * @param taskmanager
62:          * manager that e.g. starts this task when its dependencies are met
63:          * @param configuration
64:          * the configuration
65:          */
66:         public ClipToFileTask(final TaskExecutor taskmanager, final ClipperConfiguration configuration) {
67:                 super(taskmanager);
68:                 this.configuration = configuration;
69:         }
70:         
71:         @Override
72:         public boolean containsTransitive(final DependencyTask a) {
73:                 return false;
74:         }
75:         
76:         @Override
77:         public TaskResult doWork() {
78:                 try {
79:                         FileUtils.deleteDirectory(this.configuration.getRepoDirectoryRoot());
80:                         this.walkThroughJava(new File(this.configuration.getJavaDirectoryRoot()));
81:                 } catch (final TaskException | IOException e) {
82:                         return new ExceptionalTaskResult(e);
83:                 }
84:                 return new OKTaskResult();
85:         }
86:         
87:         private void walkThroughJava(final File startDir) throws TaskException, IOException {
88:                 final File[] directoryListing = startDir.listFiles();
89:•                if (directoryListing != null) {
90:•                        for (final File child : directoryListing) {
91:•                                if (child.isDirectory()) {
92:                                         this.walkThroughJava(child);
93:                                 } else {
94:                                         String fullClassName = child.getCanonicalFile().getCanonicalPath();
95:                                         fullClassName =
96:                                                         fullClassName.substring(new File(this.configuration.getJavaDirectoryRoot())
97:                                                                         .getCanonicalPath().length() + 1);
98:                                         final File classDir = this.createDirectoryForClass(fullClassName);
99:                                         try {
100:                                                 this.scanFileToDirectory(child, classDir);
101:                                         } catch (final ClipperImportFormatException | TaskException e) {
102:                                                 System.err.println("ClipperImportFormatException(" + fullClassName + "): " + e.getMessage());
103:                                                 // continue with next file!
104:                                                 // throw new TaskException(e); //enabled in test TODO
105:                                         }
106:                                         
107:                                 }
108:                                 
109:                         }
110:                 } else {
111:                         System.err.println("ClipperImportFormatException(" + startDir + "): Java Directory cannot be accessed.");
112:                 }
113:         }
114:         
115:         private void scanFileToDirectoryInternal(final File path, final ClipperJavaFileShadowCopy javaFile)
116:                         throws IOException, ClipperImportFormatException {
117:                 final File classRepoDir = path;
118:                 
119:                 // Erzeuge Unterordner wenn notwendig
120:                 // --------------------------------------------------------------------------
121:•                if (!classRepoDir.exists()) {
122:•                        if (!classRepoDir.mkdir()) {
123:                                 throw new ClipperImportFormatException("Ordner '" + classRepoDir + "' konnte nicht erzeugt werden!");
124:                         }
125:                 }
126:                 
127:                 // Iteriere über alle inneren Klassen
128:                 // --------------------------------------------------------------------------
129:                 final Iterator<ClipperJavaFileShadowCopy> it = javaFile.getInnerClasses().iterator();
130:•                while (it.hasNext()) {
131:                         final ClipperJavaFileShadowCopy current = it.next();
132:                         final String newPath = path + "/" + current.getName();
133:                         this.scanFileToDirectoryInternal(new File(newPath), current);
134:                 }
135:                 
136:                 // Hier startet der eigentliche Clipper
137:                 // --------------------------------------------------------------------------
138:                 String file = javaFile.getFullClass();
139:                 file = this.extractNonGenerationPart(classRepoDir, file);
140:                 final String withoutcommentFile = ClipperUtils.simplifyJavaCode(file);
141:                 
142:                 // Klammern ermitteln
143:                 final int classStart = this.extractClassComment(classRepoDir, file, withoutcommentFile);
144:                 final int classEnd = findCorrespondingClosingCurlyBracket(classStart, withoutcommentFile);
145:                 
146:                 // Schneidet den Inhalt der Klasse heraus (= entfernen der Klammern & Co.)
147:                 final String cFile = file.substring(classStart + 1, classEnd);
148:                 final String cWithoutComments = withoutcommentFile.substring(classStart + 1, classEnd);
149:                 
150:                 int pos = 0;
151:                 while (true) {
152:                         int i = cWithoutComments.indexOf(String.valueOf(';'), pos);
153:•                        if (i == -1) {
154:                                 break;
155:                         }
156:                         i++;
157:                         final String opOrAttWithout = cWithoutComments.substring(pos, i);
158:                         String opOrAttFile = cFile.substring(pos, i);
159:•                        if (!opOrAttFile.contains("$super") && opOrAttFile.contains("generated.Tuple")
160:•                                        && opOrAttFile.contains("> $getTuple_")) {
161:                                 opOrAttFile = opOrAttFile.substring(opOrAttFile.indexOf('$'));
162:                         }
163:                         opOrAttFile = this.removeLeadingWhiteBreaks(opOrAttFile);
164:•                        if (opOrAttWithout.contains("(")) {
165:                                 this.parseOperationToFile(opOrAttWithout, opOrAttFile, classRepoDir);
166:                         } else {
167:                                 this.parseAttributeToFile(opOrAttWithout, opOrAttFile, classRepoDir);
168:                         }
169:                         pos = i;
170:                 }
171:                 int importsBegin = 0;
172:                 int importsEnd = 0;
173:                 importsBegin = file.indexOf("import ", importsBegin);
174:                 
175:•                if (importsBegin >= 0) {
176:                         int importBegin = importsBegin;
177:•                        while (importBegin >= 0) {
178:                                 importsEnd = file.indexOf(';', importBegin);
179:                                 importBegin = file.indexOf("import", importsEnd);
180:                         }
181:                         importsEnd++;
182:                         final String preCFile = file.substring(0, importsEnd);
183:                         
184:                         final String importsBlockWithout = preCFile.substring(importsBegin, importsEnd);
185:                         final String importsBlockInFile = preCFile.substring(importsBegin, importsEnd);
186:                         this.parseImportsToFile(importsBlockWithout, importsBlockInFile, classRepoDir);
187:                 }
188:         }
189:         
190:         /**
191:          * Scans the given class file operations to the local clipper repository.
192:          *
193:          * @param classFile
194:          * @param classRepoDir
195:          * @throws IOException
196:          * @throws TaskException
197:          * @throws ClipperImportFormatException
198:          */
199:         private void scanFileToDirectory(final File classFile, final File classRepoDir) throws IOException, TaskException,
200:                         ClipperImportFormatException {
201:                 
202:                 // Load the source into "file"
203:                 final String file = FileUtils.getFileString(classFile.getAbsolutePath());
204:                 final ClipperJavaFileShadowCopy clss = new ClipperJavaFileShadowCopy();
205:                 clss.analyze(file);
206:                 
207:                 // Analyze
208:                 this.scanFileToDirectoryInternal(classRepoDir, clss);
209:                 
210:         }
211:         
212:         /**
213:          *
214:          * @param opOrAttFile
215:          * String to be bettered
216:          * @return better String
217:          */
218:         private String removeLeadingWhiteBreaks(final String opOrAttFile) {
219:                 String result = opOrAttFile;
220:                 boolean lastRunWithoutChanges = false;
221:•                while (!lastRunWithoutChanges) {
222:                         lastRunWithoutChanges = true;
223:•                        if (result.startsWith("\t\n")) {
224:                                 result = result.replaceFirst("\t\n", "");
225:                                 lastRunWithoutChanges = false;
226:                         }
227:•                        if (result.startsWith("\n")) {
228:                                 result = result.replaceFirst("\n", "");
229:                                 lastRunWithoutChanges = false;
230:                         }
231:•                        if (result.startsWith("\t\t")) {
232:                                 result = result.replaceFirst("\t\t", "\t");
233:                                 lastRunWithoutChanges = false;
234:                         }
235:                 }
236:                 return result;
237:         }
238:         
239:         /**
240:          *
241:          * @param withoutcomments
242:          * probably needed for further changes
243:          * @param file
244:          * that will be saved to directory
245:          * @param classRepoDir
246:          * path of directory
247:          * @throws IOException
248:          * saveToFile may throw this exception
249:          */
250:         private void parseImportsToFile(final String withoutcomments, final String file, final File classRepoDir)
251:                         throws IOException {
252:                 FileUtils.saveToFile(file, new File(classRepoDir.getAbsolutePath() + FILESYSTEM_PATH_SEPERATOR
253:                                 + ClipperUtils.IMPORTS_FILENAME));
254:                 
255:         }
256:         
257:         private void parseAttributeToFile(final String withoutcomments, final String file, final File classRepoDir)
258:                         throws IOException {
259:                 final String opPattern = "\\s*" + "(?<type>.*)?\\s+" + "(?<name>" + ClipperUtils.IDENTIFIER_REGEX + ")\\s*;";
260:                 final Pattern p = Pattern.compile(opPattern, Pattern.DOTALL);
261:                 final Matcher m = p.matcher(withoutcomments);
262:•                if (m.matches()) {
263:                         final String name = m.group("name");
264:                         final String type = replaceIllegalChars(m.group("type"));
265:                         final String filename = ClipperUtils.ATTRIBUTE_START + name + ClipperUtils.SEPERATOR + type;
266:                         FileUtils.saveToFile(file, new File(classRepoDir.getAbsolutePath() + FILESYSTEM_PATH_SEPERATOR + filename));
267:                         
268:                 }
269:         }
270:         
271:         /**
272:          * "Repairs" a parameter type list by gluing parts that belong to the same parameter type. This is necessary as a
273:          * type parameter may have generic type arguments which may also be separated by ",".
274:          *
275:          * @param params
276:          * The parameter type list resulting from splitting at ",".
277:          * @return The repaired type list.
278:          */
279:         private List<String> repairGenerics(final String[] params) {
280:                 final List<String> result = new ArrayList<>();
281:                 int angleBracketsDifference = 0;
282:•                for (final String param : params) {
283:•                        if (angleBracketsDifference != 0) {
284:                                 result.set(result.size() - 1, result.get(result.size() - 1) + ClipperUtils.PARAMETER_SEPARATOR + param);
285:                         } else {
286:                                 result.add(param);
287:                         }
288:                         angleBracketsDifference +=
289:                                         param.split(ClipperUtils.GENERIC_OPEN).length - param.split(ClipperUtils.GENERIC_CLOSE).length;
290:                 }
291:                 return result;
292:         }
293:         
294:         private void parseOperationToFile(final String withoutcomments, final String file, final File classRepoDir)
295:                         throws ClipperImportFormatException, IOException {
296:                 final String opPattern =
297:                                 "\\s*" + "(?<type>.*\\s+)?" + "(?<name>" + ClipperUtils.IDENTIFIER_REGEX + ")\\s*" + BRACKET_OPEN
298:                                                 + "(?<params>.*)" + BRACKET_CLOSE + ".*\\s*;";
299:                 final Pattern p = Pattern.compile(opPattern, Pattern.DOTALL);
300:                 final Matcher m = p.matcher(withoutcomments);
301:•                if (m.matches()) {
302:                         String name = m.group("name");
303:                         final String type = m.group("type");
304:                         String params = m.group("params");
305:                         
306:•                        if (type == null) {
307:                                 name = ClipperUtils.CONSTRUCTOR_FILENAME;
308:                         }
309:•                        if (params.trim().length() > 0) {
310:                                 params += ClipperUtils.PARAMETER_SEPARATOR;
311:                                 final String[] paramStrings = params.split(ClipperUtils.PARAMETER_SEPARATOR);
312:                                 final String nextWordPattern = "\\s*(.*)\\s+(" + ClipperUtils.IDENTIFIER_REGEX + ")\\s*";
313:                                 final Pattern p1 = Pattern.compile(nextWordPattern, Pattern.DOTALL);
314:•                                for (final String para : this.repairGenerics(paramStrings)) {
315:                                         final String trimmedPara = para.trim();
316:                                         final Matcher m1 = p1.matcher(trimmedPara);
317:•                                        if (m1.matches()) {
318:                                                 final String paramType = trimmedPara.substring(m1.start(1), m1.end(1));
319:                                                 name += ClipperUtils.SEPERATOR + paramType;
320:                                         } else {
321:                                                 throw new ClipperImportFormatException("Parameter seems invalid: " + params);
322:                                         }
323:                                 }
324:                         }
325:                         
326:•                        if (!name.contains(ClipperUtils.CONSTRUCTOR_FILENAME)) {
327:                                 name = replaceIllegalChars(name);
328:•                                if (!name.startsWith("$super")) {
329:                                         FileUtils.saveToFile(file, new File(classRepoDir.getAbsolutePath() + FILESYSTEM_PATH_SEPERATOR
330:                                                         + name));
331:                                 }
332:                         }
333:                 } else {
334:                         throw new ClipperImportFormatException("Regex does not match operation signature!");
335:                 }
336:                 
337:         }
338:         
339:         /**
340:          * Extracts first comment before class keyword as class comment and saves it.
341:          *
342:          * @param classRepoDir
343:          * @param file
344:          * @param withoutcommentFile
345:          *
346:          * @return class start
347:          * @throws IOException
348:          * @throws ClipperImportFormatException
349:          */
350:         private int extractClassComment(final File classRepoDir, final String file, final String withoutcommentFile)
351:                         throws IOException, ClipperImportFormatException {
352:                 final String classKeyword = "\\s(class|interface)\\s";
353:                 final Pattern p2 = Pattern.compile(classKeyword, Pattern.DOTALL);
354:                 final Matcher m2 = p2.matcher(withoutcommentFile);
355:•                if (m2.find()) {
356:                         final int start = m2.start();
357:                         final Tuple<Integer, Integer> commentBefore =
358:                                         ClipperUtils.getCommentBefore(start, file, withoutcommentFile);
359:                         final int commentStart = commentBefore.getA();
360:                         final int commentEnd = commentBefore.getB();
361:•                        if (!(commentStart == commentEnd)) {
362:                                 FileUtils.saveToFile(file.substring(commentStart, commentEnd), new File(classRepoDir.getAbsolutePath()
363:                                                 + FILESYSTEM_PATH_SEPERATOR + ClipperUtils.CLASSCOMMENT_FILENAME));
364:                         }
365:                         return file.indexOf(String.valueOf(CURLY_BRACKET_OPEN), start);
366:                 }
367:                 throw new ClipperImportFormatException("Keyword 'class' or 'interface' not found!");
368:                 
369:         }
370:         
371:         /**
372:          * Extracts the non-generation part from the file and saves it in the clipper repository.
373:          *
374:          * @param classRepoDir
375:          * @param file
376:          *
377:          * @return the file without the non generation part
378:          * @throws IOException
379:          */
380:         private String extractNonGenerationPart(final File classRepoDir, final String file) throws IOException {
381:                 String fileWithoutNonGenerationPart = file;
382:                 final Pattern p2 = Pattern.compile(ClipperUtils.NON_GEN_PART_MATCH, Pattern.DOTALL);
383:                 final Matcher m2 = p2.matcher(file);
384:•                if (m2.matches()) {
385:                         String nongenpart = file.substring(m2.start(1), m2.end(1));
386:                         nongenpart = nongenpart.replaceFirst("\\r|\\n", "");
387:                         FileUtils.saveToFile(nongenpart, new File(classRepoDir.getAbsolutePath() + FILESYSTEM_PATH_SEPERATOR
388:                                         + ClipperUtils.PROTECTED_AREA_FILENAME));
389:                         fileWithoutNonGenerationPart = file.substring(0, m2.start(1)) + "\r\n" + file.substring(m2.end(1));
390:                 }
391:                 return fileWithoutNonGenerationPart;
392:         }
393:         
394:         /**
395:          * Returns the position of the corresponding closing curly bracket.
396:          *
397:          * @param openBracketPos
398:          * postion of the {-symbol.
399:          * @param file
400:          * file to be searched in
401:          * @return position
402:          * @throws ClipperImportFormatException
403:          * when the bracket cannot be found
404:          */
405:         public static Integer findCorrespondingClosingCurlyBracket(final int openBracketPos, final String file)
406:                         throws ClipperImportFormatException {
407:                 Integer lastOpenedBracketPos = openBracketPos;
408:                 Integer openBracketMinusClosed = 1;
409:•                while (openBracketMinusClosed != 0) {
410:                         final int indexOfClose = file.indexOf(String.valueOf(CURLY_BRACKET_CLOSE), lastOpenedBracketPos + 1);
411:                         final int indexOfOpen = file.indexOf(String.valueOf(CURLY_BRACKET_OPEN), lastOpenedBracketPos + 1);
412:•                        if (indexOfClose < indexOfOpen || indexOfOpen == -1) {
413:                                 openBracketMinusClosed--;
414:                                 lastOpenedBracketPos = indexOfClose;
415:                         } else {
416:                                 openBracketMinusClosed++;
417:                                 lastOpenedBracketPos = indexOfOpen;
418:                         }
419:•                        if (indexOfClose == -1) {
420:                                 throw new ClipperImportFormatException("Unbalanced Brackets!");
421:                         }
422:                 }
423:                 return lastOpenedBracketPos;
424:         }
425:         
426:         /**
427:          * Replaces illegal chars in String by replacement character (_). Good for filesystem names.
428:          *
429:          * @param name
430:          * name possibly containing illegal characters
431:          * @return normalized string without illegal characters
432:          */
433:         public static String replaceIllegalChars(final String name) {
434:                 return name.replaceAll(ClipperUtils.GENERIC_OPEN, ClipperUtils.GENERIC_OPEN_REPLACEMENT).replaceAll(
435:                                 ClipperUtils.GENERIC_CLOSE,
436:                                 ClipperUtils.GENERIC_CLOSE_REPLACEMENT);
437:         }
438:         
439:         /**
440:          * Creates the directory for the class repo.
441:          *
442:          * @param fullQualifiedName
443:          * with groups qualified name
444:          * @throws TaskException
445:          * when directory cannot be created
446:          * @return created path
447:          */
448:         private File createDirectoryForClass(final String fullQualifiedName) throws TaskException {
449:                 String directoryName = fullQualifiedName;
450:•                if (directoryName.toLowerCase().endsWith(ClipperUtils.FILE_ENDING)) {
451:                         directoryName = directoryName.substring(0, fullQualifiedName.length() - ClipperUtils.FILE_ENDING.length());
452:                 }
453:                 final String path =
454:                                 this.configuration.getRepoDirectoryRoot() + FILESYSTEM_PATH_SEPERATOR
455:                                                 + directoryName.replace(".", FILESYSTEM_PATH_SEPERATOR);
456:                 final File result = new File(path);
457:                 final boolean success = result.mkdirs();
458:•                if (!success) {
459:                         throw new TaskException("Directory creation failed: " + path);
460:                 }
461:                 return result;
462:         }
463:         
464: }