View Javadoc

1   /**
2    * Copyright 2006 woelfle
3    * Licensed under the Apache License, Version 2.0 (the "License"); 
4    * you may not use this file except in compliance with the License. 
5    * You may obtain a copy of the License 
6    * 
7    *     at http://www.apache.org/licenses/LICENSE-2.0 
8    * 
9    * Unless required by applicable law or agreed to in writing, software 
10   * distributed under the License is distributed on an "AS IS" BASIS, 
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
12   * See the License for the specific language governing permissions and 
13   * limitations under the License.
14   */
15  package org.tratoo.mdd.kernel.transformation.impl;
16  
17  import java.io.File;
18  import java.net.URI;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Set;
24  
25  import org.tratoo.mdd.kernel.AmbiguousConfigurationException;
26  import org.tratoo.mdd.kernel.Domain;
27  import org.tratoo.mdd.kernel.Repository;
28  import org.tratoo.mdd.kernel.RepositoryFactory;
29  import org.tratoo.mdd.kernel.TransformationChain;
30  import org.tratoo.mdd.kernel.TratooRuntimeException;
31  import org.tratoo.mdd.kernel.emitter.Emitter;
32  import org.tratoo.mdd.kernel.emitter.EmitterEngine;
33  import org.tratoo.mdd.kernel.emitter.EmitterException;
34  import org.tratoo.mdd.kernel.transformation.RunConfiguration;
35  import org.tratoo.mdd.kernel.transformation.Transformation;
36  import org.tratoo.mdd.kernel.transformation.TransformationEngine;
37  
38  /**
39   * Default implementation of the {@link TransformationEngine} interface.
40   * @see TransformationEngine
41   * @author woelfle
42   *
43   */
44  public final class TransformationEngineImpl implements TransformationEngine
45  {
46  	private final TransformationRepository trafoRepository = new TransformationRepository();
47  		
48  	/**
49  	 * @see TransformationEngine#run(RunConfiguration)
50  	 * @param runConfig @see {@link TransformationEngine#run(RunConfiguration)}
51  	 * @return @see {@link TransformationEngine#run(RunConfiguration)}
52  	 */
53  	public Collection<Object> run(final RunConfiguration runConfig)
54  	{
55  		final Collection<Object> results = new ArrayList<Object>();
56  
57  		// Create a new TransformationExecutor
58  		final ExecutionContext executionContext = new ExecutionContext(runConfig.getSourceRepository(), runConfig.getTargetRepository(), runConfig.getTransformation());
59  		final TransformationRun executor = new TransformationRun(trafoRepository, executionContext);
60  
61  		for(Object element : runConfig.getSourceElements())
62  		{
63  			// Execute the transformation
64  			results.addAll(executor.run(element));		
65  		}
66  				
67  		return results;
68  	}
69  	
70  	public boolean execute(TransformationChain chain)
71  	{
72  		boolean bResult = false;
73  		
74  		if(canExecute(chain))
75  		{
76  			// Ok. Seems that we can execute the transformation chain.
77  			Repository sourceRepository = chain.getSourceRepository();
78  			Repository targetRepository = null;
79  			if(chain.getTargetDomain() == null)
80  			{
81  				targetRepository = sourceRepository;
82  			}
83  			else
84  			{
85  				TransformationPath path = findPath(chain.getSourceRepository().getDomain(), chain.getTargetDomain()).iterator().next();
86  				for(Transformation trafo : path.transformations)
87  				{
88  					if(trafo.getTargetDomainID().equals(chain.getTargetDomain()) && chain.getTargetRepository() != null)
89  					{
90  						targetRepository = chain.getTargetRepository();
91  					}
92  					else
93  					{
94  						URI id = trafo.getTargetDomainID();
95  						targetRepository = createRepository(id);
96  					}
97  					final ExecutionContext executionContext = new ExecutionContext(sourceRepository, targetRepository, trafo);
98  					final TransformationRun executor = new TransformationRun(trafoRepository, executionContext);
99  					for(Object element : chain.getSourceElements())
100 					{
101 						executor.run(element);					
102 					}
103 				}
104 			}
105 			
106 			// Now perform the emitting
107 			// TODO Refactor this code block. Looks ugly
108 			Class emitterClass = chain.getEmitter();
109 			if(emitterClass != null)
110 			{
111 				for(Emitter emitter : trafoRepository.getEmitters())
112 				{
113 					if(emitterClass.isAssignableFrom(emitter.getClass()))
114 					{
115 						Class emitterEngineClass = emitter.getEmitterEngine();
116 						try
117 						{
118 							EmitterEngine engine = (EmitterEngine) emitterEngineClass.newInstance();
119 							File rootDir = chain.getRootDir();
120 							Collection sourceElements = targetRepository.getAllElements();
121 							org.tratoo.mdd.kernel.emitter.RunConfiguration config = new org.tratoo.mdd.kernel.emitter.RunConfiguration(sourceElements, emitterClass, rootDir);
122 							engine.registerEmitter(emitter);
123 							engine.emit(config);
124 						}
125 						catch (InstantiationException e)
126 						{
127 							throw new TratooRuntimeException("Unable to create emitter engine <" + emitterEngineClass + "> for emitter <" + emitter + ">", e);
128 						}
129 						catch (IllegalAccessException e)
130 						{
131 							throw new TratooRuntimeException("Unable to create emitter engine <" + emitterEngineClass + "> for emitter <" + emitter + ">", e);
132 						}
133 						catch (EmitterException e)
134 						{
135 							throw new TratooRuntimeException("Unable to emit using emitter <"+emitter+">, rootDir <"+chain.getRootDir()+">", e);
136 						}
137 						catch (AmbiguousConfigurationException e)
138 						{
139 							throw new TratooRuntimeException("Unable to register emitter.", e);
140 						}
141 					}
142 				}
143 			}
144 		}
145 		else
146 		{
147 			bResult = false;
148 		}
149 		
150 		chain.setStatus(TransformationChain.Status.success);
151 		
152 		return bResult;
153 	}
154 	
155 	protected Repository createRepository(URI domainId)
156 	{
157 		Repository repository = null;
158 		return repository;
159 	}
160 	
161 	/**
162 	 * Checks whether the given {@link TransformationChain}
163 	 * can be executed. Returns <code>true</code> if it can
164 	 * be executed. Otherwise <code>false</code> is returned.
165 	 * If the chain cannot be executed then descriptions on 
166 	 * what happened can be found in the 
167 	 * {@link TransformationChain#getWarnings()} collection.
168 	 * @param chain The {@link TransformationChain} to check.
169 	 * @return
170 	 */
171 	public boolean canExecute(TransformationChain chain)
172 	{
173 		boolean canExecute = false;
174 		
175 		// Check whether we have to perform a transformation.
176 		// In that case a path has to exist from the source to
177 		// the target domain. Otherwise only an emitting should
178 		// be performed and no path is needed.		
179 		Domain sourceDomain = chain.getSourceRepository().getDomain();
180 		Domain targetDomain = chain.getTargetDomain();
181 		if(targetDomain != null && !sourceDomain.equals(targetDomain))
182 		{
183 			List<TransformationPath> paths = findPath(sourceDomain, targetDomain);
184 			if(paths.size() == 0)
185 			{
186 				String message = "No transformation path found from source domain <" + 
187 					sourceDomain.getID() + "> to target domain <" + 
188 					targetDomain.getID() + ">";
189 				chain.getWarnings().add(message);
190 			}
191 			else if(paths.size() > 1)
192 			{
193 				String message = "Found more than one path from source domain <" +
194 					sourceDomain.getID() + "> to target domain <" +
195 					targetDomain.getID() + ">.\nFound paths: \n";
196 				
197 				for(TransformationPath path : paths)
198 				{
199 					message += "(sourceDomain->";
200 					for(Transformation trafo : path.transformations)
201 					{
202 						message += trafo + "->";
203 					}
204 					message += "targetDomain)\n";
205 				}				
206 				chain.getWarnings().add(message);
207 			}
208 		}
209 		else
210 		{
211 			canExecute = true;			
212 		}
213 				
214 		return canExecute;
215 	}	
216 	
217 	protected List<TransformationPath> findPath(Domain source, Domain target)
218 	{
219 		return findPath(source.getID(), target.getID(), new HashSet<URI>());		
220 	}
221 	
222 	private List<TransformationPath> findPath(URI source, URI target, Set<URI> alreadyVisited)
223 	{
224 		List<TransformationPath> paths = new ArrayList<TransformationPath>();
225 		for(Transformation trafo : getTransformations())
226 		{
227 			if(trafo.getSourceDomainID().equals(source))
228 			{
229 				// Found transformation with matching source domain.
230 				URI tmpURI = trafo.getTargetDomainID();
231 				
232 				// Check whether the target domain of the transformation
233 				// matches the target of the path.
234 				if(tmpURI.equals(target))
235 				{
236 					// Ok. We have found the first part of a path. Create
237 					// a new TransformationPath instance and add the transformation
238 					// to it.
239 					TransformationPath path = new TransformationPath();
240 					path.transformations.add(trafo);
241 					paths.add(path);
242 				}
243 				
244 				// Check whether the target domain of the transformation
245 				// has already been visited.
246 				if(!alreadyVisited.contains(tmpURI))
247 				{
248 					// Ok. We have not yet visited the target domain.
249 					// So add lets visit it.
250 					Set<URI> newVisited = new HashSet<URI>(alreadyVisited);
251 					newVisited.add(source);
252 					paths = findPath(tmpURI, target, newVisited);
253 					
254 					// Check whether paths have been found. If true, then add the current
255 					// transformation to all paths.
256 					for(TransformationPath path : paths)
257 					{
258 						path.transformations.add(trafo);
259 					}
260 				}
261 			}				
262 		}
263 		return paths;
264 	}
265 	
266 	/**
267 	 * @param transformation @see {@link TransformationEngine#registerTransformation(Transformation)}
268 	 */
269 	public void registerTransformation(final Transformation transformation)
270 	{
271 		trafoRepository.registerTransformation(transformation);
272 	}
273 	
274 	/**
275 	 * @param transformation @see {@link TransformationEngine#unregisterTransformation(Transformation)}
276 	 */
277 	public void unregisterTransformation(final Transformation transformation)
278 	{
279 		trafoRepository.unregisterTransformation(transformation);
280 	}
281 	
282 	/**
283 	 * @param domain @see {@link TransformationEngine#registerDomain(Domain)}
284 	 */
285 	public void registerDomain(final Domain domain)
286 	{
287 		trafoRepository.registerDomain(domain);
288 	}
289 	
290 	/**
291 	 * @param domain @see {@link TransformationEngine#unregisterDomain(Domain)}
292 	 */
293 	public void unregisterDomain(final Domain domain)
294 	{
295 		trafoRepository.unregisterDomain(domain);
296 	}
297 	
298 	/**
299 	 * @return @see {@link TransformationEngine#getDomains()}
300 	 */
301 	public Set<Domain> getDomains()
302 	{
303 		return trafoRepository.getDomains();
304 	}
305 	
306 	/**
307 	 * @return @see {@link TransformationEngine#getTransformations()}
308 	 */
309 	public Set<Transformation> getTransformations()
310 	{
311 		return trafoRepository.getTransformations();
312 	}
313 
314 	public Set<Emitter> getEmitters()
315 	{
316 		return trafoRepository.getEmitters();
317 	}
318 
319 	public void registerEmitter(Emitter emitter)
320 	{
321 		trafoRepository.registerEmitter(emitter);
322 	}
323 
324 	public void unregisterEmitter(Emitter emitter)
325 	{
326 		trafoRepository.unregisterEmitter(emitter);
327 	}
328 	
329 	public void registerRepositoryFactory(RepositoryFactory factory)
330 	{
331 		trafoRepository.registerRepositoryFactory(factory);
332 	}
333 
334 	public void unregisterRepositoryFactory(RepositoryFactory factory)
335 	{
336 		trafoRepository.unregisterRepositoryFactory(factory);		
337 	}
338 	
339 	public Set<RepositoryFactory> getRepositoryFactories()
340 	{
341 		return trafoRepository.getRepositoryFactories();
342 	}
343 
344 	private class TransformationPath
345 	{
346 		public final List<Transformation> transformations = new ArrayList<Transformation>();
347 	}
348 }