Method: createSourceUnit(IFile, IVdmProject)

1: /*
2: * #%~
3: * org.overture.ide.core
4: * %%
5: * Copyright (C) 2008 - 2014 Overture
6: * %%
7: * This program is free software: you can redistribute it and/or modify
8: * it under the terms of the GNU General Public License as
9: * published by the Free Software Foundation, either version 3 of the
10: * License, or (at your option) any later version.
11: *
12: * This program is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: * GNU General Public License for more details.
16: *
17: * You should have received a copy of the GNU General Public
18: * License along with this program. If not, see
19: * <http://www.gnu.org/licenses/gpl-3.0.html>.
20: * #~%
21: */
22: package org.overture.ide.internal.core;
23:
24: import java.util.ArrayList;
25: import java.util.Hashtable;
26: import java.util.LinkedList;
27: import java.util.List;
28: import java.util.Map;
29: import java.util.Queue;
30: import java.util.Vector;
31:
32: import org.eclipse.core.resources.IContainer;
33: import org.eclipse.core.resources.IFile;
34: import org.eclipse.core.resources.IFolder;
35: import org.eclipse.core.resources.IProject;
36: import org.eclipse.core.resources.IResource;
37: import org.eclipse.core.resources.IResourceChangeEvent;
38: import org.eclipse.core.resources.IResourceChangeListener;
39: import org.eclipse.core.resources.IResourceDelta;
40: import org.eclipse.core.resources.IResourceDeltaVisitor;
41: import org.eclipse.core.resources.IWorkspaceRunnable;
42: import org.eclipse.core.resources.ResourcesPlugin;
43: import org.eclipse.core.runtime.Assert;
44: import org.eclipse.core.runtime.CoreException;
45: import org.eclipse.core.runtime.IProgressMonitor;
46: import org.eclipse.core.runtime.IStatus;
47: import org.eclipse.core.runtime.Status;
48: import org.eclipse.core.runtime.content.IContentType;
49: import org.eclipse.core.runtime.jobs.Job;
50: import org.overture.ide.core.IVdmModel;
51: import org.overture.ide.core.VdmCore;
52: import org.overture.ide.core.resources.IVdmProject;
53: import org.overture.ide.core.resources.IVdmSourceUnit;
54: import org.overture.ide.core.resources.VdmSourceUnit;
55: import org.overture.ide.internal.core.ast.VdmModelManager;
56: import org.overture.ide.internal.core.resources.VdmProject;
57:
58: public class ResourceManager implements IResourceChangeListener
59: {
60:
61:         Map<String, IVdmProject> projects = new Hashtable<String, IVdmProject>();
62:         Map<IFile, IVdmSourceUnit> vdmSourceUnits = new Hashtable<IFile, IVdmSourceUnit>();
63:         Queue<IVdmProject> lastAccessed = new LinkedList<IVdmProject>();
64:         ArrayList<IProject> projectsToRebuild = new ArrayList<IProject>();
65:
66:         /**
67:          * A handle to the unique Singleton instance.
68:          */
69:         static private volatile ResourceManager _instance = null;
70:
71:         /**
72:          * @return The unique instance of this class.
73:          */
74:         static public ResourceManager getInstance()
75:         {
76:                 if (null == _instance)
77:                 {
78:                         _instance = new ResourceManager();
79:                 }
80:                 return _instance;
81:         }
82:
83:         public IVdmSourceUnit getVdmSourceUnit(IFile file)
84:         {
85:                 if (file == null)
86:                 {
87:                         return null;
88:                 }
89:
90:                 if (vdmSourceUnits.containsKey(file))
91:                 {
92:                         return vdmSourceUnits.get(file);
93:                 } else
94:                 {
95:                         if (VdmProject.isVdmProject(file.getProject()))
96:                         {
97:                                 IVdmProject project = VdmProject.createProject(file.getProject());
98:
99:                                 try
100:                                 {
101:                                         if (!file.isSynchronized(IResource.DEPTH_ONE))
102:                                         {
103:                                                 file.refreshLocal(IResource.DEPTH_ONE, null);
104:                                         }
105:                                         // if (file.getContentDescription() != null
106:                                         // &&
107:                                         // project.getContentTypeIds().contains(file.getContentDescription().getContentType().getId()))
108:                                         if (project.isModelFile(file))
109:                                         {
110:                                                 IVdmSourceUnit unit = createSourceUnit(file, project);
111:                                                 return unit;
112:                                         }
113:                                 } catch (CoreException e)
114:                                 {
115:                                         if (VdmCore.DEBUG)
116:                                         {
117:                                                 e.printStackTrace();
118:                                         }
119:                                 }
120:
121:                         } else
122:                                 System.err.println("project is not vdm complient");
123:                 }
124:                 return null;
125:         }
126:
127:         private IVdmSourceUnit createSourceUnit(IFile file, IVdmProject project)
128:         {
129:                 IVdmModel model = project.getModel();
130:                 model.addVdmSourceUnit(new VdmSourceUnit(project, file));
131:                 IVdmSourceUnit unit = model.getVdmSourceUnit(file);
132:                 vdmSourceUnits.put(file, unit);
133:                 return unit;
134:         }
135:
136:         /***
137:          * Recursive search of a project for files based on the content type
138:          *
139:          * @param project
140:          * the project to search
141:          * @param resource
142:          * the resource currently selected to be searched
143:          * @param contentTypeId
144:          * a possibly null content type id, if null it is just checked that a content type exist for the file
145:          * @return a list of IFiles
146:          * @throws CoreException
147:          */
148:         public List<IVdmSourceUnit> getFiles(IVdmProject project,
149:                         IResource resource, IContentType contentTypeId)
150:                         throws CoreException
151:         {
152:                 List<IVdmSourceUnit> list = new Vector<IVdmSourceUnit>();
153:
154:                 if (resource instanceof IFolder)
155:                 {
156:                         if (resource.getLocation().lastSegment().startsWith("."))// skip
157:                                 return list;
158:                         // . folders like.svn
159:                         for (IResource res : ((IFolder) resource).members(IContainer.INCLUDE_PHANTOMS
160:                                         | IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS))
161:                         {
162:
163:                                 list.addAll(getFiles(project, res, contentTypeId));
164:                         }
165:                 }
166:                 // check if it is a IFile and that there exists a known content type for
167:                 // this file and the project
168:                 else if (resource instanceof IFile)
169:                 {
170:                         // if (contentTypeId != null
171:                         // && contentTypeId.isAssociatedWith(resource.toString()) &&
172:                         // !resource.getName().startsWith("~"))
173:                         if (project.isModelFile((IFile) resource))
174:                         {
175:                                 list.add(getVdmSourceUnit((IFile) resource));
176:                         }
177:                 }
178:                 return list;
179:         }
180:
181:         public boolean hasProject(IProject project)
182:         {
183:                 return projects.containsKey(project.getName());
184:         }
185:
186:         public IVdmProject getProject(IProject project)
187:         {
188:                 return projects.get(project.getName());
189:         }
190:
191:         public synchronized IVdmProject addProject(IVdmProject project)
192:         {
193:
194:                 if (projects.containsKey(project.getName()))
195:                         return projects.get(project.getName());
196:                 else
197:                 {
198:
199:                         IVdmProject p = getLeastAccessed();
200:                         if (p != null)
201:                         {
202:                                 lastAccessed.remove(p);
203:                                 lastAccessed.add(project);
204:                         }
205:
206:                         try
207:                         {
208:                                 projects.put(project.getName(), project);
209:                                 VdmModelManager.getInstance().createModel(project);
210:                                 // System.out.println("Creating project: " + project.getName());
211:                                 project.getSpecFiles();
212:                                 return project;
213:                         } catch (CoreException e)
214:                         {
215:                                 if (VdmCore.DEBUG)
216:                                 {
217:                                         e.printStackTrace();
218:                                 }
219:                                 return null;
220:                         }
221:                 }
222:         }
223:
224:         private IVdmProject getLeastAccessed()
225:         {
226:
227:                 return lastAccessed.poll();
228:
229:         }
230:
231:         public void resourceChanged(IResourceChangeEvent event)
232:         {
233:
234:                 try
235:                 {
236:                         IResource res = event.getResource();
237:                         switch (event.getType())
238:                         {
239:                                 case IResourceChangeEvent.PRE_DELETE:
240:                                 case IResourceChangeEvent.PRE_CLOSE:
241:                                         remove(res);
242:                                         break;
243:                                 case IResourceChangeEvent.PRE_BUILD:
244:
245:                                         break;
246:                                 case IResourceChangeEvent.POST_CHANGE:
247:
248:                                         event.getDelta().accept(new DeltaPrinter());
249:                                         break;
250:
251:                                 default:
252:                                         break;
253:                         }
254:
255:                         // rebuilds projects added to the projectsToRebuild
256:                         // during the exploration of the delta
257:                         rebuildProjects();
258:                 } catch (CoreException e)
259:                 {
260:                         // TODO Auto-generated catch block
261:                         e.printStackTrace();
262:                 }
263:         }
264:
265:         private synchronized void remove(IResource res)
266:         {
267:                 // VDM Project is closing
268:                 if (res instanceof IProject && hasProject((IProject) res))
269:                 {
270:                         if (projects.containsKey(res.getName()))
271:                         {
272:                                 projects.remove(res.getName());
273:                         }
274:                 } else if (res instanceof IFile)
275:                 {
276:                         if (vdmSourceUnits.containsKey(res))
277:                         {
278:
279:                                 final IVdmProject vdmProject = vdmSourceUnits.get(res).getProject();
280:                                 vdmProject.getModel().remove(vdmSourceUnits.get(res));
281:                                 vdmSourceUnits.remove(res);
282:
283:                                 IProject p = res.getProject();
284:                                 synchronized (projectsToRebuild)
285:                                 {
286:                                         if (!projectsToRebuild.contains(p))
287:                                         {
288:                                                 projectsToRebuild.add(p);
289:                                         }
290:                                 }
291:                         }
292:
293:                 } else if (res instanceof IFolder)
294:                 {
295:                         // no special action
296:                 } else
297:                 {
298: //                        System.err.println("Resource not handled in remove: " + res);
299:                 }
300:
301:         }
302:
303:         class DeltaPrinter implements IResourceDeltaVisitor
304:         {
305:                 public boolean visit(IResourceDelta delta)
306:                 {
307:                         IResource res = delta.getResource();
308:                         switch (delta.getKind())
309:                         {
310:                                 case IResourceDelta.ADDED:
311:                                         // System.out.print("Resource ");
312:                                         // System.out.print(res.getFullPath());
313:                                         // System.out.println(" was added.");
314:                                         add(res);
315:                                         break;
316:                                 case IResourceDelta.REMOVED:
317:                                         remove(res);
318: //                                        if (res instanceof IFile)
319: //                                        {
320: //                                                if (isProjectBuildConttent((IFile) res))
321: //                                                {
322: //                                                        IProject p = res.getProject();
323: //                                                        synchronized (projectsToRebuild)
324: //                                                        {
325: //                                                                if (!projectsToRebuild.contains(p))
326: //                                                                {
327: //                                                                        projectsToRebuild.add(p);
328: //                                                                }
329: //                                                        }
330: //                                                }
331: //
332: //                                        }
333:
334:                                         break;
335:                                 case IResourceDelta.CHANGED:
336:                                         try
337:                                         {
338:                                                 for (IResourceDelta resourceDelta : delta.getAffectedChildren())
339:                                                 {
340:                                                         resourceDelta.accept(new DeltaPrinter());
341:                                                 }
342:
343:                                         } catch (CoreException e)
344:                                         {
345:                                                 // TODO Auto-generated catch block
346:                                                 e.printStackTrace();
347:                                         }
348:                                         break;
349:                         }
350:
351:                         return true; // visit the children
352:                 }
353:
354:                 private void add(final IResource res)
355:                 {
356:                         if (res instanceof IProject
357:                                         && VdmProject.isVdmProject((IProject) res))
358:                         {
359:                                 addBuilderProject((IProject) res);// , false);
360:
361:                         } else if (res instanceof IFile)
362:                         {
363:                                 IFile file = (IFile) res;
364:                                 
365:                                 //FIXME use new method         isProjectBuildConttent(file)
366:                                 if (VdmProject.isVdmProject(file.getProject()))
367:                                 {
368:                                         // Add the VDM builder to the project if missing and the
369:                                         // project have the correct nature
370:                                         addBuilderProject(res.getProject());
371:                                         // Call getVdmSourceUnit to associate the the IFile to the
372:                                         // project if the project contains the content type
373:
374:                                         IVdmProject project = (IVdmProject) res.getProject().getAdapter(IVdmProject.class);
375:                                         Assert.isNotNull(project, "Project in ResourceManager is null for file: "
376:                                                         + file);
377:                                         IContentType contentTypeId = null;
378:                                         try
379:                                         {
380:                                                 if (file.getContentDescription() != null)
381:                                                 {
382:                                                         contentTypeId = file.getContentDescription().getContentType();
383:                                                 }
384:                                         } catch (CoreException e)
385:                                         {
386:
387:                                         }
388:                                         if (project.getContentTypeIds().contains(contentTypeId))
389:                                         {
390:                                                 getVdmSourceUnit(file);
391:                                         }
392:                                 }
393:                         }
394:
395:                 }
396:         }
397:
398:
399:         private List<IProject> addBuilders = new Vector<IProject>();
400:         private boolean addBuilderThreadRunning = false;
401:
402:         private synchronized IProject getAddBuidlerProject()
403:         {
404:                 if (addBuilders.size() > 0)
405:                 {
406:                         IProject p = addBuilders.get(0);
407:                         addBuilders.remove(p);
408:                         return p;
409:                 }
410:                 return null;
411:         }
412:
413:         private synchronized void addBuilderProject(IProject project)
414:         {
415:                 if (!addBuilders.contains(project))
416:                 {
417:                         addBuilders.add(project);
418:                         if (!addBuilderThreadRunning)
419:                         {
420:
421:                                 System.out.println("starting add builder thread");
422:                                 new AddBuilderThread().start();
423:                                 addBuilderThreadRunning = true;
424:                         }
425:                 }
426:         }
427:
428:         /**
429:          * Sync existing IVdmSource files with the build path of the project. This is used when the build path changed and
430:          * the project should be updated. This method removed old IVdmSource files which no longer is withing the build
431:          * path.
432:          *
433:          * @param project
434:          * @throws CoreException
435:          */
436:         public synchronized void syncBuildPath(IVdmProject project)
437:                         throws CoreException
438:         {
439:                 List<IVdmSourceUnit> syncedVdmSourceUnits = project.getSpecFiles();
440:
441:                 List<IFile> removedFiles = new Vector<IFile>();
442:                 IProject p = (IProject) project.getAdapter(IProject.class);
443:
444:                 for (IFile file : vdmSourceUnits.keySet())
445:                 {
446:                         if (file.getProject().equals(p)
447:                                         && !syncedVdmSourceUnits.contains(vdmSourceUnits.get(file)))
448:                         {
449:                                 removedFiles.add(file);
450:                                 System.out.println("Found an existing file removed from build path: "
451:                                                 + file);
452:                         }
453:                 }
454:
455:                 // remove the old files
456:                 for (IFile iFile : removedFiles)
457:                 {
458:                         remove(iFile);
459:                 }
460:         }
461:
462:         private class AddBuilderThread extends Thread
463:         {
464:                 @Override
465:                 public void run()
466:                 {
467:
468:                         try
469:                         {
470:                                 while (ResourcesPlugin.getWorkspace().isTreeLocked())
471:                                 {
472:                                         try
473:                                         {
474:                                                 Thread.sleep(500);
475:                                         } catch (InterruptedException e)
476:                                         {
477:                                         }
478:                                 }
479:                                 ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable()
480:                                 {
481:
482:                                         public void run(IProgressMonitor monitor)
483:                                                         throws CoreException
484:                                         {
485:
486:                                                 IProject p = null;
487:                                                 while (addBuilders.size() > 0)
488:                                                 {
489:                                                         p = getAddBuidlerProject();
490:                                                         if (p == null)
491:                                                         {
492:                                                                 addBuilderThreadRunning = false;
493:                                                                 System.out.println("ended add builder thread");
494:                                                                 return;
495:                                                         }
496:
497:                                                         System.out.println("Adding builder for: " + p);
498:                                                         IVdmProject project = VdmProject.createProject(p);
499:                                                         Assert.isNotNull(project, "VDM Project creation faild for project: "
500:                                                                         + p);
501:                                                         try
502:                                                         {
503:                                                                 if (!project.hasBuilder())
504:                                                                 {
505:                                                                         project.setBuilder(project.getLanguageVersion());
506:                                                                 }
507:                                                                 project.getSpecFiles();// sync with content type
508:                                                                 // files
509:                                                         } catch (CoreException e1)
510:                                                         {
511:                                                                 e1.printStackTrace();
512:                                                         }
513:
514:                                                 }
515:                                                 System.out.println("DONE adding");
516:                                         }
517:                                 }, null);
518:                         } catch (CoreException e)
519:                         {
520:                                 VdmCore.log("Error in ResourceManager: AddBuilderThread", e);
521:                         }
522:                 }
523:         }
524:
525:         private void rebuildProjects()
526:         {
527:                 synchronized (projectsToRebuild)
528:                 {
529:                         for (int i = 0; i < projectsToRebuild.size(); i++)
530:                         {
531:                                 IProject p = projectsToRebuild.get(i);
532:                                 IVdmProject vdmProject = (IVdmProject) p.getAdapter(IVdmProject.class);
533:                                 if (vdmProject != null)
534:                                 {
535:                                         scheduleBuilder(vdmProject);
536:                                 }
537:                         }
538:                         projectsToRebuild.clear();
539:                 }
540:         }
541:
542:         private void scheduleBuilder(IVdmProject project)
543:         {
544:                 final IVdmProject vdmProject = project;
545:                 Job job = new Job("Refresh resources")
546:                 {
547:
548:                         @Override
549:                         protected IStatus run(IProgressMonitor monitor)
550:                         {
551:                                 try
552:                                 {
553:                                         vdmProject.getModel().setIsTypeChecked(false);
554:                                         vdmProject.typeCheck(true, monitor);
555:                                 } catch (CoreException e)
556:                                 {
557:                                         VdmCore.log("Faild to auto build project", e);
558:                                 }
559:                                 return Status.OK_STATUS;
560:                         }
561:                 };
562:
563:                 job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
564:                 job.schedule();
565:         }
566:
567: }