cdeb0faabd916a483488da07bf41a39807d66cc9
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / JavaModel.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
12
13 import java.io.File;
14 import java.util.ArrayList;
15 import java.util.HashSet;
16 import java.util.Map;
17
18 import net.sourceforge.phpdt.core.IJavaElement;
19 import net.sourceforge.phpdt.core.IJavaModel;
20 import net.sourceforge.phpdt.core.IJavaProject;
21 import net.sourceforge.phpdt.core.IOpenable;
22 import net.sourceforge.phpdt.core.JavaModelException;
23 import net.sourceforge.phpdt.core.WorkingCopyOwner;
24 import net.sourceforge.phpdt.internal.core.util.MementoTokenizer;
25 import net.sourceforge.phpdt.internal.core.util.Util;
26
27 import org.eclipse.core.resources.IContainer;
28 import org.eclipse.core.resources.IFile;
29 import org.eclipse.core.resources.IFolder;
30 import org.eclipse.core.resources.IProject;
31 import org.eclipse.core.resources.IResource;
32 import org.eclipse.core.resources.IWorkspace;
33 import org.eclipse.core.resources.ResourcesPlugin;
34 import org.eclipse.core.runtime.IPath;
35 import org.eclipse.core.runtime.IProgressMonitor;
36 import org.eclipse.core.runtime.Path;
37 import org.eclipse.jface.util.Assert;
38
39 /**
40  * Implementation of <code>IJavaModel<code>. The Java Model maintains a cache of
41  * active <code>IJavaProject</code>s in a workspace. A Java Model is specific to a
42  * workspace. To retrieve a workspace's model, use the
43  * <code>#getJavaModel(IWorkspace)</code> method.
44  *
45  * @see IJavaModel
46  */
47 public class JavaModel extends Openable implements IJavaModel {
48
49         /**
50          * A set of java.io.Files used as a cache of external jars that are known to
51          * be existing. Note this cache is kept for the whole session.
52          */
53         public static HashSet existingExternalFiles = new HashSet();
54
55         /**
56          * Constructs a new Java Model on the given workspace. Note that only one
57          * instance of JavaModel handle should ever be created. One should only
58          * indirect through JavaModelManager#getJavaModel() to get access to it.
59          * 
60          * @exception Error
61          *                if called more than once
62          */
63         protected JavaModel() throws Error {
64                 super(null, "" /* workspace has empty name */); //$NON-NLS-1$
65         }
66
67         protected boolean buildStructure(OpenableElementInfo info,
68                         IProgressMonitor pm, Map newElements, IResource underlyingResource) /*
69                                                                                                                                                                  * throws
70                                                                                                                                                                  * JavaModelException
71                                                                                                                                                                  */{
72
73                 // determine my children
74                 IProject[] projects = ResourcesPlugin.getWorkspace().getRoot()
75                                 .getProjects();
76                 for (int i = 0, max = projects.length; i < max; i++) {
77                         IProject project = projects[i];
78                         if (JavaProject.hasJavaNature(project)) {
79                                 info.addChild(getJavaProject(project));
80                         }
81                 }
82
83                 newElements.put(this, info);
84
85                 return true;
86         }
87
88         /*
89          * @see IJavaModel
90          */
91         public boolean contains(IResource resource) {
92                 switch (resource.getType()) {
93                 case IResource.ROOT:
94                 case IResource.PROJECT:
95                         return true;
96                 }
97                 // file or folder
98                 IJavaProject[] projects;
99                 try {
100                         projects = this.getJavaProjects();
101                 } catch (JavaModelException e) {
102                         return false;
103                 }
104                 for (int i = 0, length = projects.length; i < length; i++) {
105                         JavaProject project = (JavaProject) projects[i];
106
107                         if (!project.contains(resource)) {
108                                 return false;
109                         }
110                 }
111                 return true;
112         }
113
114         /**
115          * @see IJavaModel
116          */
117         public void copy(IJavaElement[] elements, IJavaElement[] containers,
118                         IJavaElement[] siblings, String[] renamings, boolean force,
119                         IProgressMonitor monitor) throws JavaModelException {
120                 if (elements != null && elements.length > 0 && elements[0] != null
121                                 && elements[0].getElementType() < IJavaElement.TYPE) {
122                         runOperation(new CopyResourceElementsOperation(elements,
123                                         containers, force), elements, siblings, renamings, monitor);
124                 } else {
125                         runOperation(
126                                         new CopyElementsOperation(elements, containers, force),
127                                         elements, siblings, renamings, monitor);
128                 }
129         }
130
131         /**
132          * Returns a new element info for this element.
133          */
134         protected Object createElementInfo() {
135                 return new JavaModelInfo();
136         }
137
138         /**
139          * @see IJavaModel
140          */
141         public void delete(IJavaElement[] elements, boolean force,
142                         IProgressMonitor monitor) throws JavaModelException {
143                 if (elements != null && elements.length > 0 && elements[0] != null
144                                 && elements[0].getElementType() < IJavaElement.TYPE) {
145                         runOperation(new DeleteResourceElementsOperation(elements, force),
146                                         monitor);
147                 } else {
148                         runOperation(new DeleteElementsOperation(elements, force), monitor);
149                 }
150         }
151
152         /**
153          * Finds the given project in the list of the java model's children. Returns
154          * null if not found.
155          */
156         public IJavaProject findJavaProject(IProject project) {
157                 try {
158                         IJavaProject[] projects = this.getOldJavaProjectsList();
159                         for (int i = 0, length = projects.length; i < length; i++) {
160                                 IJavaProject javaProject = projects[i];
161                                 if (project.equals(javaProject.getProject())) {
162                                         return javaProject;
163                                 }
164                         }
165                 } catch (JavaModelException e) {
166                 }
167                 return null;
168         }
169
170         /**
171          * @see IJavaElement
172          */
173         public int getElementType() {
174                 return JAVA_MODEL;
175         }
176
177         /**
178          * Flushes the cache of external files known to be existing.
179          */
180         public static void flushExternalFileCache() {
181                 existingExternalFiles = new HashSet();
182         }
183
184         /**
185          */
186         protected boolean generateInfos(OpenableElementInfo info,
187                         IProgressMonitor pm, Map newElements, IResource underlyingResource)
188                         throws JavaModelException {
189
190                 JavaModelManager.getJavaModelManager().putInfo(this, info);
191                 // determine my children
192                 IProject[] projects = ResourcesPlugin.getWorkspace().getRoot()
193                                 .getProjects();
194                 for (int i = 0, max = projects.length; i < max; i++) {
195                         IProject project = projects[i];
196                         if (JavaProject.hasJavaNature(project)) {
197                                 info.addChild(getJavaProject(project));
198                         }
199                 }
200                 return true;
201         }
202
203         /**
204          * Returns the <code>IJavaElement</code> represented by the
205          * <code>String</code> memento.
206          * 
207          * @see getHandleMemento()
208          */
209         // protected IJavaElement getHandleFromMementoForBinaryMembers(String
210         // memento, IPackageFragmentRoot root, int rootEnd, int end) throws
211         // JavaModelException {
212         //
213         // //deal with class file and binary members
214         // IPackageFragment frag = null;
215         // if (rootEnd == end - 1) {
216         // //default package
217         // frag= root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
218         // } else {
219         // frag= root.getPackageFragment(memento.substring(rootEnd + 1, end));
220         // }
221         // int oldEnd = end;
222         // end = memento.indexOf(JavaElement.JEM_TYPE, oldEnd);
223         // if (end == -1) {
224         // //we ended with a class file
225         // return frag.getClassFile(memento.substring(oldEnd + 1));
226         // }
227         // IClassFile cf = frag.getClassFile(memento.substring(oldEnd + 1, end));
228         // oldEnd = end;
229         // end = memento.indexOf(JavaElement.JEM_TYPE, oldEnd);
230         // oldEnd = end;
231         // end = memento.indexOf(JavaElement.JEM_FIELD, end);
232         // if (end != -1) {
233         // //binary field
234         // IType type = cf.getType();
235         // return type.getField(memento.substring(end + 1));
236         // }
237         // end = memento.indexOf(JavaElement.JEM_METHOD, oldEnd);
238         // if (end != -1) {
239         // //binary method
240         // oldEnd = end;
241         // IType type = cf.getType();
242         // String methodName;
243         // end = memento.lastIndexOf(JavaElement.JEM_METHOD);
244         // String[] parameterTypes = null;
245         // if (end == oldEnd) {
246         // methodName = memento.substring(end + 1);
247         // //no parameter types
248         // parameterTypes = new String[] {};
249         // } else {
250         // String parameters = memento.substring(oldEnd + 1);
251         // StringTokenizer tokenizer = new StringTokenizer(parameters, new
252         // String(new char[] {JavaElement.JEM_METHOD}));
253         // parameterTypes = new String[tokenizer.countTokens() - 1];
254         // methodName= tokenizer.nextToken();
255         // int i = 0;
256         // while (tokenizer.hasMoreTokens()) {
257         // parameterTypes[i] = tokenizer.nextToken();
258         // i++;
259         // }
260         // }
261         // return type.getMethod(methodName, parameterTypes);
262         // }
263         //
264         // //binary type
265         // return cf.getType();
266         // }
267         /**
268          * Returns the <code>IPackageFragmentRoot</code> represented by the
269          * <code>String</code> memento.
270          * 
271          * @see getHandleMemento()
272          */
273         // protected IPackageFragmentRoot getHandleFromMementoForRoot(String
274         // memento, JavaProject project, int projectEnd, int rootEnd) {
275         // String rootName = null;
276         // if (rootEnd == projectEnd - 1) {
277         // //default root
278         // rootName = IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
279         // } else {
280         // rootName = memento.substring(projectEnd + 1, rootEnd);
281         // }
282         // return project.getPackageFragmentRoot(new Path(rootName));
283         // }
284         /**
285          * Returns the <code>IJavaElement</code> represented by the
286          * <code>String</code> memento.
287          * 
288          * @see getHandleMemento()
289          */
290         // protected IJavaElement getHandleFromMementoForSourceMembers(String
291         // memento, IPackageFragmentRoot root, int rootEnd, int end) throws
292         // JavaModelException {
293         //
294         // //deal with compilation units and source members
295         // IPackageFragment frag = null;
296         // if (rootEnd == end - 1) {
297         // //default package
298         // frag= root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
299         // } else {
300         // frag= root.getPackageFragment(memento.substring(rootEnd + 1, end));
301         // }
302         // int oldEnd = end;
303         // end = memento.indexOf(JavaElement.JEM_PACKAGEDECLARATION, end);
304         // if (end != -1) {
305         // //package declaration
306         // ICompilationUnit cu = frag.getCompilationUnit(memento.substring(oldEnd +
307         // 1, end));
308         // return cu.getPackageDeclaration(memento.substring(end + 1));
309         // }
310         // end = memento.indexOf(JavaElement.JEM_IMPORTDECLARATION, oldEnd);
311         // if (end != -1) {
312         // //import declaration
313         // ICompilationUnit cu = frag.getCompilationUnit(memento.substring(oldEnd +
314         // 1, end));
315         // return cu.getImport(memento.substring(end + 1));
316         // }
317         // int typeStart = memento.indexOf(JavaElement.JEM_TYPE, oldEnd);
318         // if (typeStart == -1) {
319         // //we ended with a compilation unit
320         // return frag.getCompilationUnit(memento.substring(oldEnd + 1));
321         // }
322         //
323         // //source members
324         // ICompilationUnit cu = frag.getCompilationUnit(memento.substring(oldEnd +
325         // 1, typeStart));
326         // end = memento.indexOf(JavaElement.JEM_FIELD, oldEnd);
327         // if (end != -1) {
328         // //source field
329         // IType type = getHandleFromMementoForSourceType(memento, cu, typeStart,
330         // end);
331         // return type.getField(memento.substring(end + 1));
332         // }
333         // end = memento.indexOf(JavaElement.JEM_METHOD, oldEnd);
334         // if (end != -1) {
335         // //source method
336         // IType type = getHandleFromMementoForSourceType(memento, cu, typeStart,
337         // end);
338         // oldEnd = end;
339         // String methodName;
340         // end = memento.lastIndexOf(JavaElement.JEM_METHOD);
341         // String[] parameterTypes = null;
342         // if (end == oldEnd) {
343         // methodName = memento.substring(end + 1);
344         // //no parameter types
345         // parameterTypes = new String[] {};
346         // } else {
347         // String parameters = memento.substring(oldEnd + 1);
348         // StringTokenizer mTokenizer = new StringTokenizer(parameters, new
349         // String(new char[] {JavaElement.JEM_METHOD}));
350         // parameterTypes = new String[mTokenizer.countTokens() - 1];
351         // methodName = mTokenizer.nextToken();
352         // int i = 0;
353         // while (mTokenizer.hasMoreTokens()) {
354         // parameterTypes[i] = mTokenizer.nextToken();
355         // i++;
356         // }
357         // }
358         // return type.getMethod(methodName, parameterTypes);
359         // }
360         //      
361         // end = memento.indexOf(JavaElement.JEM_INITIALIZER, oldEnd);
362         // if (end != -1 ) {
363         // //initializer
364         // IType type = getHandleFromMementoForSourceType(memento, cu, typeStart,
365         // end);
366         // return type.getInitializer(Integer.parseInt(memento.substring(end + 1)));
367         // }
368         // //source type
369         // return getHandleFromMementoForSourceType(memento, cu, typeStart,
370         // memento.length());
371         // }
372         /**
373          * Returns the <code>IJavaElement</code> represented by the
374          * <code>String</code> memento.
375          * 
376          * @see getHandleMemento()
377          */
378         // protected IType getHandleFromMementoForSourceType(String memento,
379         // ICompilationUnit cu, int typeStart, int typeEnd) throws
380         // JavaModelException {
381         // int end = memento.lastIndexOf(JavaElement.JEM_TYPE);
382         // IType type = null;
383         // if (end == typeStart) {
384         // String typeName = memento.substring(typeStart + 1, typeEnd);
385         // type = cu.getType(typeName);
386         //              
387         // } else {
388         // String typeNames = memento.substring(typeStart + 1, typeEnd);
389         // StringTokenizer tokenizer = new StringTokenizer(typeNames, new String(new
390         // char[] {JavaElement.JEM_TYPE}));
391         // type = cu.getType(tokenizer.nextToken());
392         // while (tokenizer.hasMoreTokens()) {
393         // //deal with inner types
394         // type= type.getType(tokenizer.nextToken());
395         // }
396         // }
397         // return type;
398         // }
399
400         /*
401          * @see JavaElement
402          */
403         public IJavaElement getHandleFromMemento(String token,
404                         MementoTokenizer memento, WorkingCopyOwner owner) {
405                 switch (token.charAt(0)) {
406                 case JEM_COUNT:
407                         return getHandleUpdatingCountFromMemento(memento, owner);
408                 case JEM_JAVAPROJECT:
409                         String projectName = memento.nextToken();
410                         JavaElement project = (JavaElement) getJavaProject(projectName);
411                         return project.getHandleFromMemento(memento, owner);
412                 }
413                 return null;
414         }
415
416         /**
417          * @see JavaElement#getHandleMemento()
418          */
419         public String getHandleMemento() {
420                 return getElementName();
421         }
422
423         /**
424          * Returns the <code>char</code> that marks the start of this handles
425          * contribution to a memento.
426          */
427         protected char getHandleMementoDelimiter() {
428                 Assert.isTrue(false, "Should not be called"); //$NON-NLS-1$
429                 return 0;
430         }
431
432         /**
433          * @see IJavaModel
434          */
435         public IJavaProject getJavaProject(String name) {
436                 return new JavaProject(ResourcesPlugin.getWorkspace().getRoot()
437                                 .getProject(name), this);
438         }
439
440         /**
441          * Returns the active Java project associated with the specified resource,
442          * or <code>null</code> if no Java project yet exists for the resource.
443          * 
444          * @exception IllegalArgumentException
445          *                if the given resource is not one of an IProject, IFolder,
446          *                or IFile.
447          */
448         public IJavaProject getJavaProject(IResource resource) {
449                 switch (resource.getType()) {
450                 case IResource.FOLDER:
451                         return new JavaProject(((IFolder) resource).getProject(), this);
452                 case IResource.FILE:
453                         return new JavaProject(((IFile) resource).getProject(), this);
454                 case IResource.PROJECT:
455                         return new JavaProject((IProject) resource, this);
456                 default:
457                         throw new IllegalArgumentException(Util
458                                         .bind("element.invalidResourceForProject")); //$NON-NLS-1$
459                 }
460         }
461
462         /**
463          * @see IJavaModel
464          */
465         public IJavaProject[] getJavaProjects() throws JavaModelException {
466                 ArrayList list = getChildrenOfType(JAVA_PROJECT);
467                 IJavaProject[] array = new IJavaProject[list.size()];
468                 list.toArray(array);
469                 return array;
470
471         }
472
473         // /**
474         // * @see IJavaModel
475         // */
476         // public Object[] getNonJavaResources() throws JavaModelException {
477         // return ((JavaModelInfo) getElementInfo()).getNonJavaResources();
478         // }
479
480         /**
481          * Workaround for bug 15168 circular errors not reported Returns the list of
482          * java projects before resource delta processing has started.
483          */
484         public IJavaProject[] getOldJavaProjectsList() throws JavaModelException {
485                 JavaModelManager manager = JavaModelManager.getJavaModelManager();
486                 return manager.javaProjectsCache == null ? this.getJavaProjects()
487                                 : manager.javaProjectsCache;
488         }
489
490         /*
491          * @see IJavaElement
492          */
493         public IPath getPath() {
494                 return Path.ROOT;
495         }
496
497         /*
498          * @see IJavaElement
499          */
500         public IResource getResource() {
501                 return ResourcesPlugin.getWorkspace().getRoot();
502         }
503
504         /**
505          * @see IOpenable
506          */
507         public IResource getUnderlyingResource() throws JavaModelException {
508                 return null;
509         }
510
511         /**
512          * Returns the workbench associated with this object.
513          */
514         public IWorkspace getWorkspace() {
515                 return ResourcesPlugin.getWorkspace();
516         }
517
518         /**
519          * @see IJavaModel
520          */
521         public void move(IJavaElement[] elements, IJavaElement[] containers,
522                         IJavaElement[] siblings, String[] renamings, boolean force,
523                         IProgressMonitor monitor) throws JavaModelException {
524                 if (elements != null && elements.length > 0 && elements[0] != null
525                                 && elements[0].getElementType() < IJavaElement.TYPE) {
526                         runOperation(new MoveResourceElementsOperation(elements,
527                                         containers, force), elements, siblings, renamings, monitor);
528                 } else {
529                         runOperation(
530                                         new MoveElementsOperation(elements, containers, force),
531                                         elements, siblings, renamings, monitor);
532                 }
533         }
534
535         /**
536          * @see IJavaModel#refreshExternalArchives(IJavaElement[], IProgressMonitor)
537          */
538         // public void refreshExternalArchives(IJavaElement[] elementsScope,
539         // IProgressMonitor monitor) throws JavaModelException {
540         // if (elementsScope == null){
541         // elementsScope = new IJavaElement[] { this };
542         // }
543         // JavaModelManager.getJavaModelManager().deltaProcessor.checkExternalArchiveChanges(elementsScope,
544         // monitor);
545         // }
546         /**
547          * @see IJavaModel
548          */
549         public void rename(IJavaElement[] elements, IJavaElement[] destinations,
550                         String[] renamings, boolean force, IProgressMonitor monitor)
551                         throws JavaModelException {
552                 MultiOperation op;
553                 if (elements != null && elements.length > 0 && elements[0] != null
554                                 && elements[0].getElementType() < IJavaElement.TYPE) {
555                         op = new RenameResourceElementsOperation(elements, destinations,
556                                         renamings, force);
557                 } else {
558                         op = new RenameElementsOperation(elements, destinations, renamings,
559                                         force);
560                 }
561
562                 runOperation(op, monitor);
563         }
564
565         /*
566          * @see JavaElement#rootedAt(IJavaProject)
567          */
568         public IJavaElement rootedAt(IJavaProject project) {
569                 return this;
570
571         }
572
573         /**
574          * Configures and runs the <code>MultiOperation</code>.
575          */
576         protected void runOperation(MultiOperation op, IJavaElement[] elements,
577                         IJavaElement[] siblings, String[] renamings,
578                         IProgressMonitor monitor) throws JavaModelException {
579                 op.setRenamings(renamings);
580                 if (siblings != null) {
581                         for (int i = 0; i < elements.length; i++) {
582                                 op.setInsertBefore(elements[i], siblings[i]);
583                         }
584                 }
585                 // runOperation(op, monitor);
586                 op.runOperation(monitor);
587         }
588
589         /**
590          * @private Debugging purposes
591          */
592         protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
593                 buffer.append(this.tabString(tab));
594                 buffer.append("Java Model"); //$NON-NLS-1$
595                 if (info == null) {
596                         buffer.append(" (not open)"); //$NON-NLS-1$
597                 }
598         }
599
600         /**
601          * Helper method - returns the targeted item (IResource if internal or
602          * java.io.File if external), or null if unbound Internal items must be
603          * referred to using container relative paths.
604          */
605         public static Object getTarget(IContainer container, IPath path,
606                         boolean checkResourceExistence) {
607
608                 if (path == null)
609                         return null;
610
611                 // lookup - inside the container
612                 if (path.getDevice() == null) { // container relative paths should not
613                                                                                 // contain a device
614                         // (see http://dev.eclipse.org/bugs/show_bug.cgi?id=18684)
615                         // (case of a workspace rooted at d:\ )
616                         IResource resource = container.findMember(path);
617                         if (resource != null) {
618                                 if (!checkResourceExistence || resource.exists())
619                                         return resource;
620                                 return null;
621                         }
622                 }
623
624                 // if path is relative, it cannot be an external path
625                 // (see http://dev.eclipse.org/bugs/show_bug.cgi?id=22517)
626                 if (!path.isAbsolute())
627                         return null;
628
629                 // lookup - outside the container
630                 File externalFile = new File(path.toOSString());
631                 if (!checkResourceExistence) {
632                         return externalFile;
633                 } else if (existingExternalFiles.contains(externalFile)) {
634                         return externalFile;
635                 } else {
636                         if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
637                                 System.out
638                                                 .println("(" + Thread.currentThread() + ") [JavaModel.getTarget(...)] Checking existence of " + path.toString()); //$NON-NLS-1$ //$NON-NLS-2$
639                         }
640                         if (externalFile.exists()) {
641                                 // cache external file
642                                 existingExternalFiles.add(externalFile);
643                                 return externalFile;
644                         }
645                 }
646                 return null;
647         }
648 }