View Javadoc
1   package de.fhdw.wtf.tooling;
2   
3   import java.io.IOException;
4   import java.net.URI;
5   import java.nio.charset.Charset;
6   import java.nio.charset.StandardCharsets;
7   import java.nio.file.Files;
8   import java.nio.file.Paths;
9   import java.util.ArrayList;
10  import java.util.Collection;
11  import java.util.concurrent.ExecutionException;
12  
13  import de.fhdw.wtf.common.ast.Model;
14  import de.fhdw.wtf.common.exception.editor.CheckException;
15  import de.fhdw.wtf.common.exception.editor.EditorMarkable;
16  import de.fhdw.wtf.common.exception.editor.EditorMarker;
17  import de.fhdw.wtf.common.exception.editor.GeneralCheckException;
18  import de.fhdw.wtf.common.exception.editor.MarkableCheckException;
19  import de.fhdw.wtf.common.exception.editor.MultipleCheckExceptions;
20  import de.fhdw.wtf.common.exception.parser.AbstractParserException;
21  import de.fhdw.wtf.common.exception.parser.NoValidTokenStreamException;
22  import de.fhdw.wtf.common.exception.referencer.ReferencerException;
23  import de.fhdw.wtf.common.exception.referencer.ReferencingNotSuccessfulException;
24  import de.fhdw.wtf.common.exception.walker.CyclicDependencyException;
25  import de.fhdw.wtf.common.exception.walker.CyclicPartDefinitionException;
26  import de.fhdw.wtf.common.exception.walker.TaskException;
27  import de.fhdw.wtf.common.stream.FilteredTokenStream;
28  import de.fhdw.wtf.common.stream.SimpleScannerInput;
29  import de.fhdw.wtf.common.task.DependencyTask;
30  import de.fhdw.wtf.common.task.GroupDependencyTask;
31  import de.fhdw.wtf.common.task.TaskExecutorFixed;
32  import de.fhdw.wtf.common.task.result.ExceptionalTaskResult;
33  import de.fhdw.wtf.common.task.result.OKTaskResult;
34  import de.fhdw.wtf.common.task.result.TaskResult;
35  import de.fhdw.wtf.common.task.result.visitor.TaskResultVisitor;
36  import de.fhdw.wtf.common.token.Position;
37  import de.fhdw.wtf.dsl.scanner.modelScanner.ModelDslScanner;
38  import de.fhdw.wtf.parser.Parser;
39  import de.fhdw.wtf.walker.tasks.AbstractOperationsCheck;
40  import de.fhdw.wtf.walker.tasks.AnalyzeInheritanceTreesTask;
41  import de.fhdw.wtf.walker.tasks.BaseTypeInheritanceCheck;
42  import de.fhdw.wtf.walker.tasks.ConstructorReferencer;
43  import de.fhdw.wtf.walker.tasks.CyclicInheritanceCheck;
44  import de.fhdw.wtf.walker.tasks.DoubleAttributenameCheck;
45  import de.fhdw.wtf.walker.tasks.DoubleGroupcomponentCheck;
46  import de.fhdw.wtf.walker.tasks.InvalidAttributeModifierCheck;
47  import de.fhdw.wtf.walker.tasks.OverloadingCheck;
48  import de.fhdw.wtf.walker.tasks.ProductCheck;
49  import de.fhdw.wtf.walker.tasks.PrototypesTask;
50  import de.fhdw.wtf.walker.tasks.ReferencedConstructorsCheck;
51  import de.fhdw.wtf.walker.tasks.SubtypesFillTask;
52  import de.fhdw.wtf.walker.tasks.SupertypesCleanInheritanceTask;
53  import de.fhdw.wtf.walker.tasks.SupertypesFillTask;
54  import de.fhdw.wtf.walker.tasks.SymmetricCheck;
55  import de.fhdw.wtf.walker.tasks.TypeReferencer;
56  import de.fhdw.wtf.walker.walker.SimpleWalkerTask;
57  
58  public abstract class SyntaxCheckAbstract {
59  	
60  	private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
61  	
62  	/**
63  	 * Erzeugt ein Modell aus dem übergebenen Pfad zum WTF-Modell.
64  	 * 
65  	 * @param uri
66  	 * @return
67  	 * @throws MultipleCheckExceptions
68  	 * @throws CyclicDependencyException
69  	 * @throws InterruptedException
70  	 * @throws CyclicPartDefinitionException
71  	 * @throws ExecutionException
72  	 */
73  	public Model getModelFromFile(final URI uri) throws MultipleCheckExceptions, CyclicDependencyException,
74  			InterruptedException, CyclicPartDefinitionException, ExecutionException {
75  		try {
76  			final String fileContent = readFile(uri, DEFAULT_CHARSET);
77  			return this.getModelFromString(fileContent);
78  		} catch (final IOException e) {
79  			e.printStackTrace();
80  			return null;
81  		}
82  	}
83  	
84  	/**
85  	 * Erzeugt ein Modell aus dem übergebenen Inhalt einer Datei die ein WTF-Modell enthält.
86  	 * 
87  	 * @param wtfFileContent
88  	 * @return
89  	 * @throws MultipleCheckExceptions
90  	 * @throws CyclicDependencyException
91  	 * @throws InterruptedException
92  	 * @throws CyclicPartDefinitionException
93  	 * @throws ExecutionException
94  	 */
95  	public Model getModelFromString(final String wtfFileContent) throws MultipleCheckExceptions,
96  			CyclicDependencyException, InterruptedException, CyclicPartDefinitionException, ExecutionException {
97  		final FilteredTokenStream output = this.scanString(wtfFileContent);
98  		Model result;
99  		result = this.parseStream(output);
100 		this.checkModelGeneral(result);
101 		return result;
102 	}
103 	
104 	/**
105 	 * Internal Method. This Method check the model.
106 	 *
107 	 * @param model
108 	 */
109 	public void checkModelGeneral(final Model model) throws MultipleCheckExceptions, CyclicDependencyException,
110 			InterruptedException, ExecutionException, CyclicPartDefinitionException {
111 		final MultipleCheckExceptions exceptions = new MultipleCheckExceptions();
112 		final TaskExecutorFixed taskmanager = TaskExecutorFixed.create();
113 		
114 		final GroupDependencyTask firstCheckers = GroupDependencyTask.create(taskmanager);
115 		final DependencyTask doubleGroupcomponent = DoubleGroupcomponentCheck.create(model, taskmanager);
116 		final DependencyTask abstractOperationsCheck = AbstractOperationsCheck.create(model, taskmanager);
117 		final DependencyTask productCheck = ProductCheck.create(model, taskmanager);
118 		final DependencyTask symmetricCheck = SymmetricCheck.create(model, taskmanager);
119 		firstCheckers.addMembers(doubleGroupcomponent, abstractOperationsCheck, productCheck, symmetricCheck);
120 		
121 		final TypeReferencer typeReferencer = TypeReferencer.create(model, taskmanager);
122 		typeReferencer.addDependency(firstCheckers);
123 		
124 		final GroupDependencyTask inheritanceChecker = GroupDependencyTask.create(taskmanager);
125 		final DependencyTask cyclicInheritance = CyclicInheritanceCheck.create(model, taskmanager);
126 		final DependencyTask baseTypeInheritanceCheck = BaseTypeInheritanceCheck.create(model, taskmanager);
127 		inheritanceChecker.addMembers(cyclicInheritance, baseTypeInheritanceCheck);
128 		inheritanceChecker.addDependency(typeReferencer);
129 		
130 		final GroupDependencyTask checkersAfterReferencing = GroupDependencyTask.create(taskmanager);
131 		final SimpleWalkerTask invalidAttributeModifierCheck = InvalidAttributeModifierCheck.create(model, taskmanager);
132 		final DependencyTask doubleAttributenameCheck = DoubleAttributenameCheck.create(model, taskmanager);
133 		checkersAfterReferencing.addMembers(invalidAttributeModifierCheck, doubleAttributenameCheck);
134 		checkersAfterReferencing.addDependency(inheritanceChecker);
135 		
136 		final GroupDependencyTask completers = GroupDependencyTask.create(taskmanager);
137 		final DependencyTask prototypesTask = PrototypesTask.create(model, taskmanager);
138 		final DependencyTask subtypesFillTask = SubtypesFillTask.create(model, taskmanager);
139 		final SupertypesFillTask supertypesFillTask = SupertypesFillTask.create(model, taskmanager);
140 		final DependencyTask supertypesCleanInheritanceTask =
141 				SupertypesCleanInheritanceTask.create(model, taskmanager, supertypesFillTask);
142 		prototypesTask.addDependency(subtypesFillTask);
143 		supertypesFillTask.addDependency(prototypesTask);
144 		supertypesCleanInheritanceTask.addDependency(supertypesFillTask);
145 		completers.addMembers(subtypesFillTask, prototypesTask, supertypesFillTask, supertypesCleanInheritanceTask);
146 		completers.addDependency(checkersAfterReferencing);
147 		final SimpleWalkerTask overloadingCheck = OverloadingCheck.create(model, taskmanager);
148 		overloadingCheck.addDependency(completers);
149 		
150 		final ConstructorReferencer constructorReferencer = ConstructorReferencer.create(model, taskmanager);
151 		constructorReferencer.addDependency(overloadingCheck);
152 		
153 		final DependencyTask analyzeInheritanceTreesTask = AnalyzeInheritanceTreesTask.create(model, taskmanager);
154 		analyzeInheritanceTreesTask.addDependency(constructorReferencer);
155 		
156 		final DependencyTask referencedConstructorsCheck = ReferencedConstructorsCheck.create(model, taskmanager);
157 		referencedConstructorsCheck.addDependency(analyzeInheritanceTreesTask);
158 		
159 		taskmanager.startAllKnownTasks();
160 		final Collection<TaskResult> results = taskmanager.getResultsAndShutdown();
161 		
162 		final Collection<Exception> occuredExceptions = new ArrayList<>();
163 		for (final TaskResult current : results) {
164 			current.accept(new TaskResultVisitor() {
165 				
166 				@Override
167 				public void handleOkTaskResult(final OKTaskResult result) {
168 					// Everything right
169 				}
170 				
171 				@Override
172 				public void handleExceptionalTaskResult(final ExceptionalTaskResult result) {
173 					occuredExceptions.add(result.getError());
174 				}
175 			});
176 		}
177 		if (!occuredExceptions.isEmpty()) {
178 			for (final Exception occuredException : occuredExceptions) {
179 				if (occuredException instanceof ReferencingNotSuccessfulException) {
180 					for (final TaskException e : typeReferencer.getExceptions()) {
181 						if (e instanceof ReferencerException) {
182 							exceptions.add(new MarkableCheckException(((ReferencerException) e).getPosStart(),
183 									((ReferencerException) e).getPosEnd(), e, EditorMarker.REFERENCER_MARKER));
184 						}
185 					}
186 				} else if (occuredException instanceof EditorMarkable) {
187 					final EditorMarkable e = (EditorMarkable) occuredException;
188 					exceptions.add(new MarkableCheckException(e.getStartPosition(), e.getEndPos(), occuredException, e
189 							.getMarker()));
190 				} else {
191 					exceptions.add(new GeneralCheckException(occuredException));
192 				}
193 			}
194 			
195 			throw exceptions;
196 		}
197 	}
198 	
199 	private Model parseStream(final FilteredTokenStream output) throws MultipleCheckExceptions {
200 		Model result;
201 		final Parser parser = Parser.create(output);
202 		try {
203 			result = parser.parse();
204 			return result;
205 		} catch (final NoValidTokenStreamException e) {
206 			
207 			final Collection<CheckException> excList = new ArrayList<>();
208 			for (final AbstractParserException parserException : parser.getExceptions()) {
209 				final int positionInLine =
210 						parserException.getToken().getPosition().getPosition() + parserException.getToken().getLength();
211 				final int columnNumber =
212 						parserException.getToken().getPosition().getPosition() + parserException.getToken().getLength();
213 				final int lineNumber = parserException.getToken().getPosition().getLineNumber();
214 				final Position startPos = parserException.getToken().getPosition();
215 				final Position endPos =
216 						Position.create(
217 								parserException.getToken().getPosition().getFilePath(),
218 								lineNumber,
219 								columnNumber,
220 								positionInLine);
221 				final MarkableCheckException markableException =
222 						new MarkableCheckException(startPos, endPos, parserException, EditorMarker.PARSER_MARKER);
223 				excList.add(markableException);
224 			}
225 			throw new MultipleCheckExceptions(excList); // NOPMD - "e" is not a cause here
226 		}
227 	}
228 	
229 	private FilteredTokenStream scanString(final String fileContent) {
230 		final FilteredTokenStream output = FilteredTokenStream.create();
231 		final ModelDslScanner scanner = ModelDslScanner.create();
232 		final SimpleScannerInput input = new SimpleScannerInput(fileContent);
233 		scanner.scan(input, output);
234 		return output;
235 	}
236 	
237 	private static String readFile(final URI uri, final Charset encoding) throws IOException {
238 		final byte[] encoded = Files.readAllBytes(Paths.get(uri.getPath()));
239 		return new String(encoded, encoding);
240 	}
241 	
242 }