1 package com.bonevich.erj.app;
2
3 import com.bonevich.erj.model.Schema;
4 import com.bonevich.erj.model.ModelElement;
5 import com.bonevich.erj.model.ModelElementTraverser;
6 import com.bonevich.erj.ErjConstants;
7 import com.bonevich.erj.db.*;
8 import com.bonevich.erj.diagram.ERDiagram;
9
10 import com.bonevich.util.Functor;
11 import com.bonevich.util.dependency.Dynamic;
12 import com.bonevich.java.util.ImmutableIterator;
13
14 import org.tigris.gef.base.*;
15
16 import java.util.*;
17 import java.util.zip.*;
18 import java.io.*;
19 import java.beans.PropertyChangeEvent;
20 import java.beans.PropertyChangeListener;
21
22 public final class Project implements PropertyChangeListener, ErjConstants
23 {
24 //////////////////////////////////////////////////////////
25 // Constants
26 private static final String FILE_EXTENSION_STR = ".zerj";
27
28 //////////////////////////////////////////////////////////
29 // Attributes
30 private String _name;
31 private String _author = EMPTY_STR;
32 private String _version = EMPTY_STR;
33 private String _description = EMPTY_STR;
34
35 private Application _parentApp;
36 private DatabaseLogin _targetDatabase;
37
38 private transient String _filepath = EMPTY_STR;
39 private transient boolean _modified = false;
40 private transient boolean _new = false;
41
42 private Schema _model;
43 private HashMap _modelRegistry;
44
45 private List _diagrams = new ArrayList(); // of Diagram instances
46 private int _diagramCount = 0;
47
48 private ProjectComponents _components = new ProjectComponents();
49
50 //////////////////////////////////////////////////////////
51 // Dynamic sentries
52 private Dynamic _dyn_name = new Dynamic();
53 private Dynamic _dyn_diagrams = new Dynamic();
54 private Dynamic _dyn_modified = new Dynamic();
55
56 //////////////////////////////////////////////////////////
57 // Constructors
58 /***
59 * Prevent instantiation by anyone but me.
60 */
61 protected Project(Application app)
62 {
63 _parentApp = app;
64 _components.addComponent(new ProjectProperties(this));
65 }
66
67 //////////////////////////////////////////////////////////
68 // Operations
69
70 // Vector cuz JList wants it that way
71 public Vector getComponents()
72 {
73 return _components.getComponents();
74 }
75
76 public void addComponent(ProjectComponent cmp)
77 {
78 _components.addComponent(cmp);
79 }
80
81 /***
82 * Returns an instance of one of the well-known project component types.
83 */
84 public ProjectComponent createComponent(String type)
85 {
86 // FIXME: setup a ProjectComponentFactory class
87 ProjectComponent newCmp = null;
88 if (ProjectComponent.ERJ.equals(type))
89 {
90 newCmp = new ProjectProperties(this);
91 }
92 else if (ProjectComponent.XMI.equals(type))
93 {
94 _model = new Schema();
95 newCmp = new ProjectModel(this, _model);
96 initModelRegistry();
97 }
98 else if (ProjectComponent.SVG.equals(type))
99 {
100 newCmp = new ProjectDiagram(this, null);
101 }
102 //System.err.println("newCmp = " + newCmp);
103 addComponent(newCmp);
104 return newCmp;
105 }
106
107 public void createDiagram()
108 {
109 ERDiagram d = new ERDiagram(_model);
110 try
111 {
112 d.setName("diagram_" + (++_diagramCount));
113 }
114 catch (Exception e) {}
115
116 ProjectDiagram cmp = new ProjectDiagram(this, d);
117 addComponent(cmp);
118 addDiagram(d);
119 }
120
121 /***
122 * Needed by ProjectDiagram during loading, but should not be
123 * utilized by anyone else.
124 */
125 protected void addDiagram(Diagram d)
126 {
127 if (!_diagrams.contains(d))
128 {
129 _dyn_diagrams.onSet();
130 _diagrams.add(d);
131 setModified(true);
132 }
133 }
134
135 public void removeDiagram(Diagram d)
136 {
137 if (_diagrams.remove(d))
138 {
139 _dyn_diagrams.onSet();
140 _components.removeDiagramComponent(d);
141 setModified(true);
142 }
143 }
144
145 public Iterator getDiagramIterator()
146 {
147 _dyn_diagrams.onGet();
148 return new ImmutableIterator(_diagrams.iterator());
149 }
150
151 public Schema getModel()
152 {
153 return _model;
154 }
155
156 public void setModel(Schema model)
157 {
158 _model = model;
159 initModelRegistry();
160 addComponent(new ProjectModel(this, _model));
161 }
162
163 /***
164 * Provides a map of model elements owned by the model schema.
165 */
166 protected HashMap getModelRegistry()
167 {
168 return _modelRegistry;
169 }
170 private void initModelRegistry()
171 {
172 if (_model != null)
173 {
174 _modelRegistry = new HashMap();
175
176 // key = {{ModelElement instance class name}}:{{ModelElement instance identifier value}}
177 // value = {{ModelElement instance}}
178 ModelElementTraverser traverser = new ModelElementTraverser
179 (
180 new Functor()
181 {
182 public Object function(Object arg)
183 {
184 ModelElement me = (ModelElement) arg;
185 String key = me.getOclReferenceId();
186 _modelRegistry.put(key, me);
187 return key;
188 }
189 }
190 );
191 traverser.traverse(_model);
192 }
193 }
194
195 public String getName()
196 {
197 _dyn_name.onGet();
198 return _name;
199 }
200 public void setName(String name)
201 {
202 if (!name.equals(_name))
203 {
204 _dyn_name.onSet();
205 _name = name;
206 setModified(true);
207 }
208 }
209
210 public String getDescription()
211 {
212 return _description;
213 }
214 public void setDescription(String description)
215 {
216 if (!description.equals(_description))
217 {
218 _description = description;
219 setModified(true);
220 }
221 }
222
223 public String getAuthor()
224 {
225 return _author;
226 }
227 public void setAuthor(String author)
228 {
229 if (!author.equals(_author))
230 {
231 _author = author;
232 setModified(true);
233 }
234 }
235
236 public String getVersion()
237 {
238 return _version;
239 }
240 public void setVersion(String version)
241 {
242 if (!version.equals(_version))
243 {
244 _version = version;
245 setModified(true);
246 }
247 }
248
249 public String getFilepath()
250 {
251 return _filepath;
252 }
253 public void setFilepath(String filepath)
254 {
255 if (filepath.endsWith(FILE_EXTENSION_STR))
256 {
257 _filepath = filepath;
258 }
259 else
260 {
261 _filepath = filepath + FILE_EXTENSION_STR;
262 }
263
264 if (_name == null || EMPTY_STR.equals(_name))
265 {
266 int nameIdx = _filepath.lastIndexOf(System.getProperty("file.separator"));
267 int dotIdx = _filepath.lastIndexOf('.');
268 if (nameIdx < 0) nameIdx = 0;
269 if (dotIdx < 0) dotIdx = _filepath.length();
270 setName(_filepath.substring(nameIdx + 1, dotIdx));
271 }
272 }
273
274 public DatabaseLogin getTargetDatabase()
275 {
276 return _targetDatabase;
277 }
278 public void setTargetDatabase(DatabaseLogin targetDatabase)
279 {
280 _targetDatabase = targetDatabase;
281 setModified(true);
282 }
283
284 public DatabaseLogin createDatabaseLogin(String dbName)
285 {
286 SupportedDatabase db = _parentApp.getSupportedDatabase(dbName);
287 DatabaseLogin newLogin = db.createDatabaseLogin();
288 setTargetDatabase(newLogin);
289 return newLogin;
290 }
291
292 public Application getParent()
293 {
294 return _parentApp;
295 }
296
297 public void load()
298 {
299 Globals.showStatus("Loading project from " + _filepath + "...");
300
301 // Load the properties file first - this sets up all the other
302 // components
303 ProjectComponent cmp = _components.getPropertiesComponent();
304 loadComponent(cmp, cmp.getEntryExtension());
305
306 cmp = _components.getModelComponent();
307 // FIXME: cmp could be null!
308 loadComponent(cmp, cmp.getEntryFilename());
309 _model = ((ProjectModel) cmp).getModel();
310 initModelRegistry();
311
312 Iterator diagrams = _components.getDiagramComponentIterator();
313 while (diagrams.hasNext())
314 {
315 cmp = (ProjectDiagram) diagrams.next();
316 loadComponent(cmp, cmp.getEntryFilename());
317 }
318
319 Globals.showStatus("Project " + _name + " loaded");
320
321 //loaded projects are never marked as new!
322 setModified(false);
323 _new = false;
324 }
325
326 private void loadComponent(ProjectComponent cmp, String targetPattern)
327 {
328 try
329 {
330 File file = new File(_filepath);
331 ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
332 String entryName = zis.getNextEntry().getName();
333 while (!entryName.endsWith(targetPattern))
334 {
335 ZipEntry next = zis.getNextEntry();
336 if (next != null)
337 {
338 entryName = next.getName();
339 }
340 else
341 {
342 break;
343 }
344 }
345 //System.err.println("entryName = " + entryName);
346 //System.err.println("targetPattern = " + targetPattern);
347 cmp.load(zis);
348 zis.close();
349 }
350 catch (FileNotFoundException e)
351 {
352 e.printStackTrace();
353 Globals.showStatus("ERROR loading project " + _name);
354 }
355 catch (IOException e)
356 {
357 e.printStackTrace();
358 Globals.showStatus("ERROR loading project " + _name);
359 }
360 }
361
362 public void save()
363 {
364 try
365 {
366 Globals.showStatus("Saving project to " + _filepath + "...");
367
368 File file = new File(_filepath);
369 ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(file));
370
371 // save the components of this project
372 _components.prepareForSave();
373 Iterator itr = _components.iterator();
374 while (itr.hasNext())
375 {
376 ProjectComponent pc = (ProjectComponent) itr.next();
377
378 System.err.println("saving component as " + pc.getEntryFilename());
379 ZipEntry cmpEntry = new ZipEntry(pc.getEntryFilename());
380 zos.putNextEntry(cmpEntry);
381
382 pc.save(zos);
383
384 zos.closeEntry();
385 }
386 zos.close();
387
388 Globals.showStatus("Project " + _name + " saved");
389
390 setModified(false);
391 _new = false;
392 }
393 catch (FileNotFoundException e)
394 {
395 e.printStackTrace();
396 Globals.showStatus("ERROR saving project " + _name);
397 }
398 catch (IOException e)
399 {
400 e.printStackTrace();
401 Globals.showStatus("ERROR saving project " + _name);
402 }
403 }
404
405 public void save(String projectFile)
406 {
407 setFilepath(projectFile);
408 save();
409 }
410
411 public boolean isModified()
412 {
413 _dyn_modified.onGet();
414 return _modified;
415 }
416 private void setModified(boolean modified)
417 {
418 if (_modified ^ modified)
419 {
420 _dyn_modified.onSet();
421 _modified = modified;
422 }
423 }
424
425 public void markAsModified()
426 {
427 setModified(true);
428 }
429
430 public boolean isNew()
431 {
432 return _new;
433 }
434
435 public void markAsNew()
436 {
437 _new = true;
438 setModified(false);
439 }
440
441 protected String convertNameToIdentifier()
442 {
443 StringBuffer buf = new StringBuffer();
444 char[] chars = _name.toCharArray();
445 boolean first = true;
446 for (int i = 0; i < _name.length(); i++)
447 {
448 char chr = Character.toLowerCase(chars[i]);
449 if (first)
450 {
451 if (Character.isUnicodeIdentifierStart(chr))
452 {
453 buf.append(chr);
454 first = false;
455 }
456 }
457 else
458 {
459 if (Character.isUnicodeIdentifierPart(chr))
460 {
461 buf.append(chr);
462 }
463 }
464 }
465
466 return buf.toString();
467 }
468
469 //////////////////////////////////////////////////////////
470 // PropertyChangeListener implementation
471
472 /***
473 * Receive diagram property change notification and, if appropriate,
474 * mark the project as modified.
475 */
476 public void propertyChange(PropertyChangeEvent e)
477 {
478 //System.err.println("propertyChanged: property = " + e.getPropertyName() +
479 // " from " + e.getOldValue() + " to " + e.getNewValue());
480 // FIXME: for now we always mark modified; be more selective based on
481 // source Fig and/or newVal <> oldVal??
482 markAsModified();
483 }
484
485
486 //////////////////////////////////////////////////////////
487 // Inner Classes
488 class ProjectComponents
489 {
490 private ProjectProperties _propertiesCmp;
491 private ProjectModel _modelCmp;
492 private List _diagramCmps = new LinkedList();
493
494 public void addComponent(ProjectComponent cmp)
495 {
496 if (cmp == null) return;
497 if (cmp instanceof ProjectProperties) _propertiesCmp = (ProjectProperties) cmp;
498 else if (cmp instanceof ProjectModel) _modelCmp = (ProjectModel) cmp;
499 else if (cmp instanceof ProjectDiagram) _diagramCmps.add(cmp);
500 }
501
502 public Vector getComponents()
503 {
504 Vector tmp = new Vector();
505 tmp.add(_propertiesCmp);
506 tmp.add(_modelCmp);
507 tmp.addAll(_diagramCmps);
508 return tmp;
509 }
510
511 public ProjectProperties getPropertiesComponent()
512 {
513 return _propertiesCmp;
514 }
515
516 public ProjectModel getModelComponent()
517 {
518 return _modelCmp;
519 }
520
521 public Iterator getDiagramComponentIterator()
522 {
523 return _diagramCmps.iterator();
524 }
525
526 public void removeDiagramComponent(Diagram d)
527 {
528 Iterator itr = getDiagramComponentIterator();
529 while (itr.hasNext())
530 {
531 ProjectDiagram cmp = (ProjectDiagram) itr.next();
532 if (cmp.getDiagram() == d)
533 {
534 itr.remove();
535 break;
536 }
537 }
538 }
539
540 public Iterator iterator()
541 {
542 return getComponents().iterator();
543 }
544
545 public void prepareForSave()
546 {
547 _propertiesCmp.initEntryFilename();
548 _modelCmp.initEntryFilename();
549 Iterator diagrams = _diagramCmps.iterator();
550 while (diagrams.hasNext())
551 {
552 ((ProjectComponent) diagrams.next()).initEntryFilename();
553 }
554 }
555
556 } /* end inner class ProjectComponents */
557
558 } /* end class Project */
This page was automatically generated by Maven