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