1 package org.andromda.core.configuration;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.Serializable;
6 import java.net.URL;
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.HashMap;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Map;
13
14 import org.andromda.core.common.ResourceUtils;
15
16
17 /***
18 * Stores the model information for each model that AndroMDA will process.
19 *
20 * @author Chad Brandon
21 */
22 public class Model
23 implements Serializable
24 {
25 /***
26 * Stores whether or not a last modified check
27 * should be performed.
28 */
29 private boolean lastModifiedCheck = false;
30
31 /***
32 * Whether or not to perform a last modified check on the model.
33 *
34 * @return Returns the lastModifiedCheck.
35 */
36 public boolean isLastModifiedCheck()
37 {
38 return lastModifiedCheck;
39 }
40
41 /***
42 * Sets whether or not to perform a last modified check when processing the model. If
43 * <code>true</code> the model will be checked for a timestamp before processing occurs.
44 *
45 * @param lastModifiedCheck true/false
46 */
47 public void setLastModifiedCheck(final boolean lastModifiedCheck)
48 {
49 this.lastModifiedCheck = lastModifiedCheck;
50 }
51
52 /***
53 * Stores the informationj about what packages should and shouldn't
54 * be processed.
55 */
56 private Filters packages = new Filters()/package-summary.html">ong> Filters packages = new Filters();
57
58 /***
59 * Sets the processAll flag on the internal model packages instance
60 * of this model.
61 *
62 * @param processAllPackages whether or not all packages should be processed by default.
63 */
64 public void setProcessAllPackages(final boolean processAllPackages)
65 {
66 packages.setApplyAll(processAllPackages);
67 }
68
69 /***
70 * Stores the information about what packages should/shouldn't be processed.
71 *
72 * @return Returns the packages.
73 */
74 public Filters getPackages()
75 {
76 return</strong> this.packages;
77 }
78
79 /***
80 * Sets the model packages for this model. This indicates what
81 * packages should and should not be processed from this model.
82 *
83 * @param packages the packages to process.
84 */
85 public void setPackages(final Filters packages)/package-summary.html">ong> void setPackages(final Filters packages)
86 {
87 this.packages = packages;
88 }
89
90 /***
91 * Stores the informationj about what constraints should and shouldn't
92 * be enforced.
93 */
94 private Filters constraints = new Filters();
95
96 /***
97 * Sets the applyAll flag on the internal filters instance
98 * of this model.
99 *
100 * @param enforceAllConstraints whether or not all constraints should be enforced by default.
101 */
102 public void setEnforceAllConstraints(final boolean enforceAllConstraints)
103 {
104 this.constraints.setApplyAll(enforceAllConstraints);
105 }
106
107 /***
108 * Stores the information about what constraints should/shouldn't be enforced.
109 *
110 * @return Returns the constraints instance.
111 */
112 public Filters getConstraints()
113 {
114 return this.constraints;
115 }
116
117 /***
118 * Sets the constraints for this model. This indicates what
119 * constraints should and should not be processed from this model.
120 *
121 * @param constraints the packages to process.
122 */
123 public void setConstraints(final Filters constraints)
124 {
125 this.constraints = constraints;
126 }
127
128 /***
129 * The URL to the model.
130 */
131 private List uris = new ArrayList();
132
133 /***
134 * Caches the urisAsStrings value (so we don't need
135 * to do the conversion more than once).
136 */
137 private String[] urisAsStrings = null;
138
139 /***
140 * All URIs that make up the model.
141 *
142 * @return Returns the uri.
143 */
144 public String[] getUris()
145 {
146 if (this.urisAsStrings == null)
147 {
148 final int uriNumber = uris.size();
149 this.urisAsStrings = new String[uriNumber];
150 for (int ctr = 0; ctr < uriNumber; ctr++)
151 {
152 urisAsStrings[ctr] = (uris.get(ctr)).toString();
153 }
154 }
155 return this.urisAsStrings;
156 }
157
158 /***
159 * Adds the location as a URI to one of the model files.
160 *
161 * @param uri the URI to the model.
162 */
163 public void addUri(final String uri)
164 {
165 try
166 {
167 final URL url = ResourceUtils.toURL(uri);
168 if (url == null)
169 {
170 throw new ConfigurationException("Model could not be loaded from invalid path --> '" + uri + "'");
171 }
172 try
173 {
174
175
176 url.openConnection().setDefaultUseCaches(false);
177 }
178 catch (final IOException exception)
179 {
180
181 }
182 this.uris.add(url);
183 }
184 catch (final Throwable throwable)
185 {
186 throw new ConfigurationException(throwable);
187 }
188 }
189
190 /***
191 * Stores the transformations for this Configuration instance.
192 */
193 private final Collection transformations = new ArrayList();
194
195 /***
196 * Adds a transformation to this configuration instance.
197 *
198 * @param transformation the transformation instance to add.
199 */
200 public void addTransformation(final Transformation transformation)
201 {
202 this.transformations.add(transformation);
203 }
204
205 /***
206 * Gets the transformations belonging to this configuration.
207 *
208 * @return the array of {@link Transformation} instances.
209 */
210 public Transformation[] getTransformations()
211 {
212 return (Transformation[])this.transformations.toArray(new Transformation[0]);
213 }
214
215 /***
216 * The locations in which to search for module.
217 */
218 private final Collection moduleSearchLocations = new ArrayList();
219
220 /***
221 * Adds a module search location (these are the locations
222 * in which a search for module is performed).
223 *
224 * @param location a location path.
225 * @see #addModuleSearchLocation(String)
226 */
227 public void addModuleSearchLocation(final Location location)
228 {
229 this.moduleSearchLocations.add(location);
230 }
231
232 /***
233 * Adds a module search location path (a location
234 * without a pattern defined).
235 *
236 * @param path a location path.
237 * @see #addModuleSearchLocation(Location)
238 */
239 public void addModuleSearchLocation(final String path)
240 {
241 if (path != null)
242 {
243 final Location location = new Location();
244 location.setPath(path);
245 this.moduleSearchLocations.add(location);
246 }
247 }
248
249 /***
250 * The type of model (i.e. uml-1.4, uml-2.0, etc).
251 */
252 private String type;
253
254 /***
255 * Gets the type of the model (i.e. the type of metamodel this
256 * model is based upon).
257 *
258 * @return Returns the type.
259 */
260 public String getType()
261 {
262 return this.type;
263 }
264
265 /***
266 * Sets the type of model (i.e. the type of metamodel this model
267 * is based upon).
268 *
269 * @param type The type to set.
270 */
271 public void setType(final String type)
272 {
273 this.type = type;
274 }
275
276 /***
277 * Gets the module searach locations for this model instance.
278 *
279 * @return the module search locations.
280 * @see #getModuleSearchLocationPaths()
281 */
282 public Location[] getModuleSearchLocations()
283 {
284 return (Location[])this.moduleSearchLocations.toArray(new Location[0]);
285 }
286
287 /***
288 * Stores the path for each module search location in this configuration.
289 */
290 private String[] moduleSearchLocationPaths = null;
291
292 /***
293 * Gets all found module search location paths for this model instance.
294 *
295 * @return the module search location paths.
296 * @see #getModuleSearchLocations()
297 */
298 public String[] getModuleSearchLocationPaths()
299 {
300 if (this.moduleSearchLocationPaths == null)
301 {
302 final Collection paths = new ArrayList();
303 for (final Iterator iterator = this.moduleSearchLocations.iterator(); iterator.hasNext();)
304 {
305 final Location location = (Location)iterator.next();
306 final URL[] resources = location.getResources();
307 final int resourceNumber = resources.length;
308 for (int ctr = 0; ctr < resourceNumber; ctr++)
309 {
310 paths.add(resources[ctr].toString());
311 }
312 paths.add(location.getPath());
313 }
314 this.moduleSearchLocationPaths = (String[])paths.toArray(new String[0]);
315 }
316 return this.moduleSearchLocationPaths;
317 }
318
319 /***
320 * Stores all resources including all resources found within the module search locations
321 * as well as a resource for the {@link #getUris()}.
322 */
323 private URL[] moduleSearchLocationResources = null;
324
325 /***
326 * Gets the accumulation of all files found when combining the contents
327 * of all module search location paths and their patterns by which they
328 * are filtered as well as the model URI.
329 *
330 * @return all module search location files.
331 */
332 public URL[] getModuleSearchLocationResources()
333 {
334 if (this.moduleSearchLocationResources == null)
335 {
336 final Collection allResources = new ArrayList();
337 final Location[] locations = this.getModuleSearchLocations();
338 for (int ctr = 0; ctr < locations.length; ctr++)
339 {
340 final URL[] resources = locations[ctr].getResources();
341 for (int fileCtr = 0; fileCtr < resources.length; fileCtr++)
342 {
343 allResources.add(resources[fileCtr]);
344 }
345 }
346 this.moduleSearchLocationResources = (URL[])allResources.toArray(new URL[0]);
347 }
348 return this.moduleSearchLocationResources;
349 }
350
351 /***
352 * Gets the time of the latest modified uri of the model as a <code>long</code>.
353 * If it can not be determined <code>0</code> is returned.
354 *
355 * @return the time this model was last modified
356 */
357 public long getLastModified()
358 {
359 long lastModifiedTime = 0;
360 for (final Iterator iterator = this.uris.iterator(); iterator.hasNext();)
361 {
362 final URL url = (URL)iterator.next();
363 final long modifiedTime = ResourceUtils.getLastModifiedTime(url);
364 if (modifiedTime > lastModifiedTime)
365 {
366 lastModifiedTime = modifiedTime;
367 }
368 }
369 return lastModifiedTime;
370 }
371
372 /***
373 * @see java.lang.Object#toString()
374 */
375 public String toString()
376 {
377 String toString = super.toString();
378 final String key = this.getKey();
379 if (key != null && key.trim().length() > 0)
380 {
381 toString = key;
382 }
383 return toString;
384 }
385
386 /***
387 * Stores the last modified times for each model at the time
388 * {@link #isChanged()} is called.
389 */
390 private static final Map modelModifiedTimes = new HashMap();
391
392 /***
393 * The unique key that identifies this model.
394 */
395 private String key = null;
396
397 /***
398 * Creates the unique key that identifies this model
399 * (its made up of a list of all the uris for this model
400 * concatinated).
401 *
402 * @return the unique key
403 */
404 private String getKey()
405 {
406 if (this.key == null || this.key.trim().length() == 0)
407 {
408 final StringBuffer buffer = new StringBuffer();
409 for (final Iterator iterator = this.uris.iterator(); iterator.hasNext();)
410 {
411 final URL uri = (URL)iterator.next();
412 buffer.append(new File(uri.getFile()));
413 if (iterator.hasNext())
414 {
415 buffer.append(", ");
416 }
417 }
418 this.key = buffer.toString();
419 }
420 return this.key;
421 }
422
423 /***
424 * The repository to which this model belongs.
425 */
426 private Repository repository;
427
428 /***
429 * Gets the repository to which this model belongs.
430 *
431 * @return the repository to which this model belongs.
432 */
433 public Repository getRepository()
434 {
435 return this.repository;
436 }
437
438 /***
439 * Sets the repository to which this model belongs.
440 *
441 * @param repository the repository configuration to which this model belongs.
442 */
443 void setRepository(final Repository repository)
444 {
445 this.repository = repository;
446 }
447
448 /***
449 * Indicates whether or not the given <code>model</code>
450 * has changed since the previous call to this method.
451 *
452 * @return true/false
453 */
454 public boolean isChanged()
455 {
456 boolean changed = this.getUris().length > 0;
457 if (changed)
458 {
459 final Object modelKey = this.getKey();
460 Map lastModifiedTimes = (Map)modelModifiedTimes.get(modelKey);
461
462
463
464 if (lastModifiedTimes != null)
465 {
466 final long modelLastModified = ((Long)lastModifiedTimes.get(modelKey)).longValue();
467 changed = this.getLastModified() > modelLastModified;
468 if (!changed)
469 {
470
471 final URL[] resources = this.getModuleSearchLocationResources();
472 for (int ctr = 0; ctr < resources.length; ctr++)
473 {
474 final URL resource = resources[ctr];
475 final Long lastModified = (Long)lastModifiedTimes.get(resource);
476 if (lastModified != null)
477 {
478
479 if (ResourceUtils.getLastModifiedTime(resource) > lastModified.longValue())
480 {
481 changed = true;
482 break;
483 }
484 }
485 }
486 }
487 }
488
489
490 if (changed)
491 {
492 this.loadLastModifiedTimes();
493 }
494 }
495 return changed;
496 }
497
498 /***
499 * Loads (or re-loads) the last modified times from the
500 * {@link #getUris()} and the modules found on the module search path.
501 */
502 private void loadLastModifiedTimes()
503 {
504 final Object modelKey = this.getKey();
505 Map lastModifiedTimes = (Map)modelModifiedTimes.get(modelKey);
506 if (lastModifiedTimes == null)
507 {
508 lastModifiedTimes = new HashMap();
509 }
510 else
511 {
512 lastModifiedTimes.clear();
513 }
514 final URL[] resources = this.getModuleSearchLocationResources();
515 for (int ctr = 0; ctr < resources.length; ctr++)
516 {
517 final URL resource = resources[ctr];
518 lastModifiedTimes.put(
519 resource,
520 new Long(ResourceUtils.getLastModifiedTime(resource)));
521 }
522
523
524
525 lastModifiedTimes.put(
526 modelKey,
527 new Long(this.getLastModified()));
528 modelModifiedTimes.put(
529 modelKey,
530 lastModifiedTimes);
531 }
532
533 /***
534 * Clears out the current last modified times.
535 */
536 static void clearLastModifiedTimes()
537 {
538 modelModifiedTimes.clear();
539 }
540 }