001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.core;
011:
012: import java.util.ArrayList;
013: import java.util.Enumeration;
014: import java.util.Map;
015:
016: import org.eclipse.core.resources.*;
017: import org.eclipse.core.runtime.*;
018: import org.eclipse.jdt.core.*;
019: import org.eclipse.jdt.core.compiler.CharOperation;
020: import org.eclipse.jdt.internal.core.util.MementoTokenizer;
021: import org.eclipse.jdt.internal.core.util.Messages;
022: import org.eclipse.jdt.internal.core.util.Util;
023:
024: /**
025: * @see IPackageFragmentRoot
026: */
027: public class PackageFragmentRoot extends Openable implements
028: IPackageFragmentRoot {
029:
030: /**
031: * The delimiter between the source path and root path in the
032: * attachment server property.
033: */
034: protected final static char ATTACHMENT_PROPERTY_DELIMITER = '*';
035: /*
036: * No source attachment property
037: */
038: public final static String NO_SOURCE_ATTACHMENT = ""; //$NON-NLS-1$
039:
040: /**
041: * The resource associated with this root.
042: * (an IResource or a java.io.File (for external jar only))
043: */
044: protected Object resource;
045:
046: /**
047: * Constructs a package fragment root which is the root of the java package
048: * directory hierarchy.
049: */
050: protected PackageFragmentRoot(IResource resource,
051: JavaProject project) {
052: super (project);
053: this .resource = resource;
054: }
055:
056: /**
057: * @see IPackageFragmentRoot
058: */
059: public void attachSource(IPath sourcePath, IPath rootPath,
060: IProgressMonitor monitor) throws JavaModelException {
061: try {
062: verifyAttachSource(sourcePath);
063: if (monitor != null) {
064: monitor.beginTask(Messages.element_attachingSource, 2);
065: }
066: SourceMapper oldMapper = getSourceMapper();
067: IWorkspace workspace = ResourcesPlugin.getWorkspace();
068: boolean rootNeedsToBeClosed = false;
069:
070: if (sourcePath == null) {
071: //source being detached
072: rootNeedsToBeClosed = true;
073: setSourceMapper(null);
074: /* Disable deltas (see 1GDTUSD)
075: // fire a delta to notify the UI about the source detachement.
076: JavaModelManager manager = (JavaModelManager) JavaModelManager.getJavaModelManager();
077: JavaModel model = (JavaModel) getJavaModel();
078: JavaElementDelta attachedSourceDelta = new JavaElementDelta(model);
079: attachedSourceDelta .sourceDetached(this); // this would be a PackageFragmentRoot
080: manager.registerResourceDelta(attachedSourceDelta );
081: manager.fire(); // maybe you want to fire the change later. Let us know about it.
082: */
083: } else {
084: /*
085: // fire a delta to notify the UI about the source attachement.
086: JavaModelManager manager = (JavaModelManager) JavaModelManager.getJavaModelManager();
087: JavaModel model = (JavaModel) getJavaModel();
088: JavaElementDelta attachedSourceDelta = new JavaElementDelta(model);
089: attachedSourceDelta .sourceAttached(this); // this would be a PackageFragmentRoot
090: manager.registerResourceDelta(attachedSourceDelta );
091: manager.fire(); // maybe you want to fire the change later. Let us know about it.
092: */
093:
094: //check if different from the current attachment
095: IPath storedSourcePath = getSourceAttachmentPath();
096: IPath storedRootPath = getSourceAttachmentRootPath();
097: if (monitor != null) {
098: monitor.worked(1);
099: }
100: if (storedSourcePath != null) {
101: if (!(storedSourcePath.equals(sourcePath)
102: && (rootPath != null && rootPath
103: .equals(storedRootPath)) || storedRootPath == null)) {
104: rootNeedsToBeClosed = true;
105: }
106: }
107: // check if source path is valid
108: Object target = JavaModel.getTarget(
109: workspace.getRoot(), sourcePath, false);
110: if (target == null) {
111: throw new JavaModelException(new JavaModelStatus(
112: IJavaModelStatusConstants.INVALID_PATH,
113: sourcePath));
114: }
115: SourceMapper mapper = createSourceMapper(sourcePath,
116: rootPath);
117: if (rootPath == null && mapper.rootPath != null) {
118: // as a side effect of calling the SourceMapper constructor, the root path was computed
119: rootPath = new Path(mapper.rootPath);
120: }
121: setSourceMapper(mapper);
122: }
123: if (sourcePath == null) {
124: Util.setSourceAttachmentProperty(getPath(), null); //remove the property
125: } else {
126: //set the property to the path of the mapped source
127: Util
128: .setSourceAttachmentProperty(
129: getPath(),
130: sourcePath.toString()
131: + (rootPath == null ? "" : (ATTACHMENT_PROPERTY_DELIMITER + rootPath.toString()))); //$NON-NLS-1$
132: }
133: if (rootNeedsToBeClosed) {
134: if (oldMapper != null) {
135: oldMapper.close();
136: }
137: BufferManager manager = BufferManager
138: .getDefaultBufferManager();
139: Enumeration openBuffers = manager.getOpenBuffers();
140: while (openBuffers.hasMoreElements()) {
141: IBuffer buffer = (IBuffer) openBuffers
142: .nextElement();
143: IOpenable possibleMember = buffer.getOwner();
144: if (isAncestorOf((IJavaElement) possibleMember)) {
145: buffer.close();
146: }
147: }
148: if (monitor != null) {
149: monitor.worked(1);
150: }
151: }
152: } catch (JavaModelException e) {
153: Util.setSourceAttachmentProperty(getPath(), null); // loose info - will be recomputed
154: throw e;
155: } finally {
156: if (monitor != null) {
157: monitor.done();
158: }
159: }
160: }
161:
162: /**
163: * @see Openable
164: */
165: protected boolean buildStructure(OpenableElementInfo info,
166: IProgressMonitor pm, Map newElements,
167: IResource underlyingResource) throws JavaModelException {
168:
169: // check whether this pkg fragment root can be opened
170: IStatus status = validateOnClasspath();
171: if (!status.isOK())
172: throw newJavaModelException(status);
173: if (!resourceExists())
174: throw newNotPresentException();
175:
176: ((PackageFragmentRootInfo) info)
177: .setRootKind(determineKind(underlyingResource));
178: return computeChildren(info, newElements);
179: }
180:
181: SourceMapper createSourceMapper(IPath sourcePath, IPath rootPath) {
182: SourceMapper mapper = new SourceMapper(sourcePath,
183: rootPath == null ? null : rootPath.toOSString(),
184: getJavaProject().getOptions(true)); // cannot use workspace options if external jar is 1.5 jar and workspace options are 1.4 options
185: return mapper;
186: }
187:
188: /*
189: * @see org.eclipse.jdt.core.IPackageFragmentRoot#delete
190: */
191: public void delete(int updateResourceFlags, int updateModelFlags,
192: IProgressMonitor monitor) throws JavaModelException {
193:
194: DeletePackageFragmentRootOperation op = new DeletePackageFragmentRootOperation(
195: this , updateResourceFlags, updateModelFlags);
196: op.runOperation(monitor);
197: }
198:
199: /**
200: * Compute the package fragment children of this package fragment root.
201: *
202: * @exception JavaModelException The resource associated with this package fragment root does not exist
203: */
204: protected boolean computeChildren(OpenableElementInfo info,
205: Map newElements) throws JavaModelException {
206: // Note the children are not opened (so not added to newElements) for a regular package fragment root
207: // Howver they are opened for a Jar package fragment root (see JarPackageFragmentRoot#computeChildren)
208: try {
209: // the underlying resource may be a folder or a project (in the case that the project folder
210: // is actually the package fragment root)
211: IResource underlyingResource = getResource();
212: if (underlyingResource.getType() == IResource.FOLDER
213: || underlyingResource.getType() == IResource.PROJECT) {
214: ArrayList vChildren = new ArrayList(5);
215: IContainer rootFolder = (IContainer) underlyingResource;
216: char[][] inclusionPatterns = fullInclusionPatternChars();
217: char[][] exclusionPatterns = fullExclusionPatternChars();
218: computeFolderChildren(rootFolder, !Util.isExcluded(
219: rootFolder, inclusionPatterns,
220: exclusionPatterns), CharOperation.NO_STRINGS,
221: vChildren, inclusionPatterns, exclusionPatterns);
222: IJavaElement[] children = new IJavaElement[vChildren
223: .size()];
224: vChildren.toArray(children);
225: info.setChildren(children);
226: }
227: } catch (JavaModelException e) {
228: //problem resolving children; structure remains unknown
229: info.setChildren(new IJavaElement[] {});
230: throw e;
231: }
232: return true;
233: }
234:
235: /**
236: * Starting at this folder, create package fragments and add the fragments that are not exclused
237: * to the collection of children.
238: *
239: * @exception JavaModelException The resource associated with this package fragment does not exist
240: */
241: protected void computeFolderChildren(IContainer folder,
242: boolean isIncluded, String[] pkgName, ArrayList vChildren,
243: char[][] inclusionPatterns, char[][] exclusionPatterns)
244: throws JavaModelException {
245:
246: if (isIncluded) {
247: IPackageFragment pkg = getPackageFragment(pkgName);
248: vChildren.add(pkg);
249: }
250: try {
251: JavaProject javaProject = (JavaProject) getJavaProject();
252: JavaModelManager manager = JavaModelManager
253: .getJavaModelManager();
254: IResource[] members = folder.members();
255: boolean hasIncluded = isIncluded;
256: int length = members.length;
257: if (length > 0) {
258: String sourceLevel = javaProject.getOption(
259: JavaCore.COMPILER_SOURCE, true);
260: String complianceLevel = javaProject.getOption(
261: JavaCore.COMPILER_COMPLIANCE, true);
262: for (int i = 0; i < length; i++) {
263: IResource member = members[i];
264: String memberName = member.getName();
265:
266: switch (member.getType()) {
267:
268: case IResource.FOLDER:
269: // recurse into sub folders even even parent not included as a sub folder could be included
270: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=65637)
271: if (Util.isValidFolderNameForPackage(
272: memberName, sourceLevel,
273: complianceLevel)) {
274: // eliminate binary output only if nested inside direct subfolders
275: if (javaProject.contains(member)) {
276: String[] newNames = Util.arrayConcat(
277: pkgName, manager
278: .intern(memberName));
279: boolean isMemberIncluded = !Util
280: .isExcluded(member,
281: inclusionPatterns,
282: exclusionPatterns);
283: computeFolderChildren((IFolder) member,
284: isMemberIncluded, newNames,
285: vChildren, inclusionPatterns,
286: exclusionPatterns);
287: }
288: }
289: break;
290: case IResource.FILE:
291: // inclusion filter may only include files, in which case we still want to include the immediate parent package (lazily)
292: if (!hasIncluded
293: && Util.isValidCompilationUnitName(
294: memberName, sourceLevel,
295: complianceLevel)
296: && !Util.isExcluded(member,
297: inclusionPatterns,
298: exclusionPatterns)) {
299: hasIncluded = true;
300: IPackageFragment pkg = getPackageFragment(pkgName);
301: vChildren.add(pkg);
302: }
303: break;
304: }
305: }
306: }
307: } catch (IllegalArgumentException e) {
308: throw new JavaModelException(e,
309: IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST); // could be thrown by ElementTree when path is not found
310: } catch (CoreException e) {
311: throw new JavaModelException(e);
312: }
313: }
314:
315: /*
316: * @see org.eclipse.jdt.core.IPackageFragmentRoot#copy
317: */
318: public void copy(IPath destination, int updateResourceFlags,
319: int updateModelFlags, IClasspathEntry sibling,
320: IProgressMonitor monitor) throws JavaModelException {
321:
322: CopyPackageFragmentRootOperation op = new CopyPackageFragmentRootOperation(
323: this , destination, updateResourceFlags,
324: updateModelFlags, sibling);
325: op.runOperation(monitor);
326: }
327:
328: /**
329: * Returns a new element info for this element.
330: */
331: protected Object createElementInfo() {
332: return new PackageFragmentRootInfo();
333: }
334:
335: /**
336: * @see IPackageFragmentRoot
337: */
338: public IPackageFragment createPackageFragment(String pkgName,
339: boolean force, IProgressMonitor monitor)
340: throws JavaModelException {
341: CreatePackageFragmentOperation op = new CreatePackageFragmentOperation(
342: this , pkgName, force);
343: op.runOperation(monitor);
344: return getPackageFragment(op.pkgName);
345: }
346:
347: /**
348: * Returns the root's kind - K_SOURCE or K_BINARY, defaults
349: * to K_SOURCE if it is not on the classpath.
350: *
351: * @exception JavaModelException if the project and root do
352: * not exist.
353: */
354: protected int determineKind(IResource underlyingResource)
355: throws JavaModelException {
356: IClasspathEntry entry = ((JavaProject) getJavaProject())
357: .getClasspathEntryFor(underlyingResource.getFullPath());
358: if (entry != null) {
359: return entry.getContentKind();
360: }
361: return IPackageFragmentRoot.K_SOURCE;
362: }
363:
364: /**
365: * Compares two objects for equality;
366: * for <code>PackageFragmentRoot</code>s, equality is having the
367: * same parent, same resources, and occurrence count.
368: *
369: */
370: public boolean equals(Object o) {
371: if (this == o)
372: return true;
373: if (!(o instanceof PackageFragmentRoot))
374: return false;
375: PackageFragmentRoot other = (PackageFragmentRoot) o;
376: return this .resource.equals(other.resource)
377: && this .parent.equals(other.parent);
378: }
379:
380: /**
381: * @see IJavaElement
382: */
383: public boolean exists() {
384: return super .exists() && validateOnClasspath().isOK();
385: }
386:
387: private IClasspathEntry findSourceAttachmentRecommendation() {
388: try {
389: IPath rootPath = this .getPath();
390: IClasspathEntry entry;
391: IWorkspaceRoot workspaceRoot = ResourcesPlugin
392: .getWorkspace().getRoot();
393:
394: // try on enclosing project first
395: JavaProject parentProject = (JavaProject) getJavaProject();
396: try {
397: entry = parentProject.getClasspathEntryFor(rootPath);
398: if (entry != null) {
399: Object target = JavaModel.getTarget(workspaceRoot,
400: entry.getSourceAttachmentPath(), true);
401: if (target instanceof IResource) {
402: if (target instanceof IFile) {
403: IFile file = (IFile) target;
404: if (org.eclipse.jdt.internal.compiler.util.Util
405: .isArchiveFileName(file.getName())) {
406: return entry;
407: }
408: } else if (target instanceof IContainer) {
409: return entry;
410: }
411: } else if (target instanceof java.io.File) {
412: java.io.File file = JavaModel.getFile(target);
413: if (file != null) {
414: if (org.eclipse.jdt.internal.compiler.util.Util
415: .isArchiveFileName(file.getName())) {
416: return entry;
417: }
418: } else {
419: // external directory
420: return entry;
421: }
422: }
423: }
424: } catch (JavaModelException e) {
425: // ignore
426: }
427:
428: // iterate over all projects
429: IJavaModel model = getJavaModel();
430: IJavaProject[] jProjects = model.getJavaProjects();
431: for (int i = 0, max = jProjects.length; i < max; i++) {
432: JavaProject jProject = (JavaProject) jProjects[i];
433: if (jProject == parentProject)
434: continue; // already done
435: try {
436: entry = jProject.getClasspathEntryFor(rootPath);
437: if (entry != null) {
438: Object target = JavaModel.getTarget(
439: workspaceRoot, entry
440: .getSourceAttachmentPath(),
441: true);
442: if (target instanceof IResource) {
443: if (target instanceof IFile) {
444: IFile file = (IFile) target;
445: if (org.eclipse.jdt.internal.compiler.util.Util
446: .isArchiveFileName(file
447: .getName())) {
448: return entry;
449: }
450: } else if (target instanceof IContainer) {
451: return entry;
452: }
453: } else if (target instanceof java.io.File) {
454: java.io.File file = (java.io.File) target;
455: if (file.isFile()) {
456: if (org.eclipse.jdt.internal.compiler.util.Util
457: .isArchiveFileName(file
458: .getName())) {
459: return entry;
460: }
461: } else {
462: // external directory
463: return entry;
464: }
465: }
466: }
467: } catch (JavaModelException e) {
468: // ignore
469: }
470: }
471: } catch (JavaModelException e) {
472: // ignore
473: }
474:
475: return null;
476: }
477:
478: /*
479: * Returns the exclusion patterns from the classpath entry associated with this root.
480: */
481: public char[][] fullExclusionPatternChars() {
482: try {
483: if (this .isOpen()
484: && this .getKind() != IPackageFragmentRoot.K_SOURCE)
485: return null;
486: ClasspathEntry entry = (ClasspathEntry) getRawClasspathEntry();
487: if (entry == null) {
488: return null;
489: } else {
490: return entry.fullExclusionPatternChars();
491: }
492: } catch (JavaModelException e) {
493: return null;
494: }
495: }
496:
497: /*
498: * Returns the inclusion patterns from the classpath entry associated with this root.
499: */
500: public char[][] fullInclusionPatternChars() {
501: try {
502: if (this .isOpen()
503: && this .getKind() != IPackageFragmentRoot.K_SOURCE)
504: return null;
505: ClasspathEntry entry = (ClasspathEntry) getRawClasspathEntry();
506: if (entry == null) {
507: return null;
508: } else {
509: return entry.fullInclusionPatternChars();
510: }
511: } catch (JavaModelException e) {
512: return null;
513: }
514: }
515:
516: public String getElementName() {
517: if (this .resource instanceof IFolder)
518: return ((IFolder) this .resource).getName();
519: return ""; //$NON-NLS-1$
520: }
521:
522: /**
523: * @see IJavaElement
524: */
525: public int getElementType() {
526: return PACKAGE_FRAGMENT_ROOT;
527: }
528:
529: /**
530: * @see JavaElement#getHandleMemento()
531: */
532: protected char getHandleMementoDelimiter() {
533: return JavaElement.JEM_PACKAGEFRAGMENTROOT;
534: }
535:
536: /*
537: * @see JavaElement
538: */
539: public IJavaElement getHandleFromMemento(String token,
540: MementoTokenizer memento, WorkingCopyOwner owner) {
541: switch (token.charAt(0)) {
542: case JEM_PACKAGEFRAGMENT:
543: String pkgName;
544: if (memento.hasMoreTokens()) {
545: pkgName = memento.nextToken();
546: char firstChar = pkgName.charAt(0);
547: if (firstChar == JEM_CLASSFILE
548: || firstChar == JEM_COMPILATIONUNIT
549: || firstChar == JEM_COUNT) {
550: token = pkgName;
551: pkgName = IPackageFragment.DEFAULT_PACKAGE_NAME;
552: } else {
553: token = null;
554: }
555: } else {
556: pkgName = IPackageFragment.DEFAULT_PACKAGE_NAME;
557: token = null;
558: }
559: JavaElement pkg = (JavaElement) getPackageFragment(pkgName);
560: if (token == null) {
561: return pkg.getHandleFromMemento(memento, owner);
562: } else {
563: return pkg.getHandleFromMemento(token, memento, owner);
564: }
565: }
566: return null;
567: }
568:
569: /**
570: * @see JavaElement#getHandleMemento(StringBuffer)
571: */
572: protected void getHandleMemento(StringBuffer buff) {
573: IPath path;
574: IResource underlyingResource = getResource();
575: if (underlyingResource != null) {
576: // internal jar or regular root
577: if (getResource().getProject().equals(
578: getJavaProject().getProject())) {
579: path = underlyingResource.getProjectRelativePath();
580: } else {
581: path = underlyingResource.getFullPath();
582: }
583: } else {
584: // external jar
585: path = getPath();
586: }
587: ((JavaElement) getParent()).getHandleMemento(buff);
588: buff.append(getHandleMementoDelimiter());
589: escapeMementoName(buff, path.toString());
590: }
591:
592: /**
593: * @see IPackageFragmentRoot
594: */
595: public int getKind() throws JavaModelException {
596: return ((PackageFragmentRootInfo) getElementInfo())
597: .getRootKind();
598: }
599:
600: /**
601: * Returns an array of non-java resources contained in the receiver.
602: */
603: public Object[] getNonJavaResources() throws JavaModelException {
604: return ((PackageFragmentRootInfo) getElementInfo())
605: .getNonJavaResources(getJavaProject(), getResource(),
606: this );
607: }
608:
609: /**
610: * @see IPackageFragmentRoot
611: */
612: public IPackageFragment getPackageFragment(String packageName) {
613: // tolerate package names with spaces (e.g. 'x . y') (http://bugs.eclipse.org/bugs/show_bug.cgi?id=21957)
614: String[] pkgName = Util.getTrimmedSimpleNames(packageName);
615: return getPackageFragment(pkgName);
616: }
617:
618: public PackageFragment getPackageFragment(String[] pkgName) {
619: return new PackageFragment(this , pkgName);
620: }
621:
622: /**
623: * Returns the package name for the given folder
624: * (which is a decendent of this root).
625: */
626: protected String getPackageName(IFolder folder) {
627: IPath myPath = getPath();
628: IPath pkgPath = folder.getFullPath();
629: int mySegmentCount = myPath.segmentCount();
630: int pkgSegmentCount = pkgPath.segmentCount();
631: StringBuffer pkgName = new StringBuffer(
632: IPackageFragment.DEFAULT_PACKAGE_NAME);
633: for (int i = mySegmentCount; i < pkgSegmentCount; i++) {
634: if (i > mySegmentCount) {
635: pkgName.append('.');
636: }
637: pkgName.append(pkgPath.segment(i));
638: }
639: return pkgName.toString();
640: }
641:
642: /**
643: * @see IJavaElement
644: */
645: public IPath getPath() {
646: return getResource().getFullPath();
647: }
648:
649: /*
650: * @see IPackageFragmentRoot
651: */
652: public IClasspathEntry getRawClasspathEntry()
653: throws JavaModelException {
654:
655: IClasspathEntry rawEntry = null;
656: JavaProject project = (JavaProject) this .getJavaProject();
657: project.getResolvedClasspath(); // force the reverse rawEntry cache to be populated
658: Map rootPathToRawEntries = project.getPerProjectInfo().rootPathToRawEntries;
659: if (rootPathToRawEntries != null) {
660: rawEntry = (IClasspathEntry) rootPathToRawEntries.get(this
661: .getPath());
662: }
663: if (rawEntry == null) {
664: throw new JavaModelException(new JavaModelStatus(
665: IJavaModelStatusConstants.ELEMENT_NOT_ON_CLASSPATH,
666: this ));
667: }
668: return rawEntry;
669: }
670:
671: /*
672: * @see IJavaElement
673: */
674: public IResource getResource() {
675: return (IResource) this .resource;
676: }
677:
678: /**
679: * @see IPackageFragmentRoot
680: */
681: public IPath getSourceAttachmentPath() throws JavaModelException {
682: if (getKind() != K_BINARY)
683: return null;
684:
685: // 1) look source attachment property (set iff attachSource(...) was called
686: IPath path = getPath();
687: String serverPathString = Util
688: .getSourceAttachmentProperty(path);
689: if (serverPathString != null) {
690: int index = serverPathString
691: .lastIndexOf(ATTACHMENT_PROPERTY_DELIMITER);
692: if (index < 0) {
693: // no root path specified
694: return new Path(serverPathString);
695: } else {
696: String serverSourcePathString = serverPathString
697: .substring(0, index);
698: return new Path(serverSourcePathString);
699: }
700: }
701:
702: // 2) look at classpath entry
703: IClasspathEntry entry = ((JavaProject) getParent())
704: .getClasspathEntryFor(path);
705: IPath sourceAttachmentPath;
706: if (entry != null
707: && (sourceAttachmentPath = entry
708: .getSourceAttachmentPath()) != null)
709: return sourceAttachmentPath;
710:
711: // 3) look for a recommendation
712: entry = findSourceAttachmentRecommendation();
713: if (entry != null
714: && (sourceAttachmentPath = entry
715: .getSourceAttachmentPath()) != null) {
716: return sourceAttachmentPath;
717: }
718:
719: return null;
720: }
721:
722: /**
723: * For use by <code>AttachSourceOperation</code> only.
724: * Sets the source mapper associated with this root.
725: */
726: public void setSourceMapper(SourceMapper mapper)
727: throws JavaModelException {
728: ((PackageFragmentRootInfo) getElementInfo())
729: .setSourceMapper(mapper);
730: }
731:
732: /**
733: * @see IPackageFragmentRoot
734: */
735: public IPath getSourceAttachmentRootPath()
736: throws JavaModelException {
737: if (getKind() != K_BINARY)
738: return null;
739:
740: // 1) look source attachment property (set iff attachSource(...) was called
741: IPath path = getPath();
742: String serverPathString = Util
743: .getSourceAttachmentProperty(path);
744: if (serverPathString != null) {
745: int index = serverPathString
746: .lastIndexOf(ATTACHMENT_PROPERTY_DELIMITER);
747: if (index == -1)
748: return null;
749: String serverRootPathString = IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
750: if (index != serverPathString.length() - 1) {
751: serverRootPathString = serverPathString
752: .substring(index + 1);
753: }
754: return new Path(serverRootPathString);
755: }
756:
757: // 2) look at classpath entry
758: IClasspathEntry entry = ((JavaProject) getParent())
759: .getClasspathEntryFor(path);
760: IPath sourceAttachmentRootPath;
761: if (entry != null
762: && (sourceAttachmentRootPath = entry
763: .getSourceAttachmentRootPath()) != null)
764: return sourceAttachmentRootPath;
765:
766: // 3) look for a recomendation
767: entry = findSourceAttachmentRecommendation();
768: if (entry != null
769: && (sourceAttachmentRootPath = entry
770: .getSourceAttachmentRootPath()) != null)
771: return sourceAttachmentRootPath;
772:
773: return null;
774: }
775:
776: /**
777: * @see JavaElement
778: */
779: public SourceMapper getSourceMapper() {
780: SourceMapper mapper;
781: try {
782: PackageFragmentRootInfo rootInfo = (PackageFragmentRootInfo) getElementInfo();
783: mapper = rootInfo.getSourceMapper();
784: if (mapper == null) {
785: // first call to this method
786: IPath sourcePath = getSourceAttachmentPath();
787: IPath rootPath = getSourceAttachmentRootPath();
788: if (sourcePath == null)
789: mapper = createSourceMapper(getPath(), rootPath); // attach root to itself
790: else
791: mapper = createSourceMapper(sourcePath, rootPath);
792: rootInfo.setSourceMapper(mapper);
793: }
794: } catch (JavaModelException e) {
795: // no source can be attached
796: mapper = null;
797: }
798: return mapper;
799: }
800:
801: /**
802: * @see IJavaElement
803: */
804: public IResource getUnderlyingResource() throws JavaModelException {
805: if (!exists())
806: throw newNotPresentException();
807: return getResource();
808: }
809:
810: /**
811: * @see IParent
812: */
813: public boolean hasChildren() throws JavaModelException {
814: // a package fragment root always has the default package as a child
815: return true;
816: }
817:
818: public int hashCode() {
819: return this .resource.hashCode();
820: }
821:
822: /**
823: * @see IPackageFragmentRoot
824: */
825: public boolean isArchive() {
826: return false;
827: }
828:
829: /**
830: * @see IPackageFragmentRoot
831: */
832: public boolean isExternal() {
833: return false;
834: }
835:
836: /*
837: * Validate whether this package fragment root is on the classpath of its project.
838: */
839: protected IStatus validateOnClasspath() {
840:
841: IPath path = this .getPath();
842: try {
843: // check package fragment root on classpath of its project
844: JavaProject project = (JavaProject) getJavaProject();
845: IClasspathEntry entry = project.getClasspathEntryFor(path);
846: if (entry != null) {
847: return Status.OK_STATUS;
848: }
849: } catch (JavaModelException e) {
850: // could not read classpath, then assume it is outside
851: return e.getJavaModelStatus();
852: }
853: return new JavaModelStatus(
854: IJavaModelStatusConstants.ELEMENT_NOT_ON_CLASSPATH,
855: this );
856: }
857:
858: /*
859: * @see org.eclipse.jdt.core.IPackageFragmentRoot#move
860: */
861: public void move(IPath destination, int updateResourceFlags,
862: int updateModelFlags, IClasspathEntry sibling,
863: IProgressMonitor monitor) throws JavaModelException {
864:
865: MovePackageFragmentRootOperation op = new MovePackageFragmentRootOperation(
866: this , destination, updateResourceFlags,
867: updateModelFlags, sibling);
868: op.runOperation(monitor);
869: }
870:
871: /**
872: * @private Debugging purposes
873: */
874: protected void toStringInfo(int tab, StringBuffer buffer,
875: Object info, boolean showResolvedInfo) {
876: buffer.append(this .tabString(tab));
877: IPath path = getPath();
878: if (getJavaProject().getElementName().equals(path.segment(0))) {
879: if (path.segmentCount() == 1) {
880: buffer.append("<project root>"); //$NON-NLS-1$
881: } else {
882: buffer.append(path.removeFirstSegments(1)
883: .makeRelative());
884: }
885: } else {
886: if (isExternal()) {
887: buffer.append(path.toOSString());
888: } else {
889: buffer.append(path);
890: }
891: }
892: if (info == null) {
893: buffer.append(" (not open)"); //$NON-NLS-1$
894: }
895: }
896:
897: /**
898: * Possible failures: <ul>
899: * <li>ELEMENT_NOT_PRESENT - the root supplied to the operation
900: * does not exist
901: * <li>INVALID_ELEMENT_TYPES - the root is not of kind K_BINARY
902: * <li>RELATIVE_PATH - the path supplied to this operation must be
903: * an absolute path
904: * </ul>
905: */
906: protected void verifyAttachSource(IPath sourcePath)
907: throws JavaModelException {
908: if (!exists()) {
909: throw newNotPresentException();
910: } else if (this .getKind() != K_BINARY) {
911: throw new JavaModelException(new JavaModelStatus(
912: IJavaModelStatusConstants.INVALID_ELEMENT_TYPES,
913: this ));
914: } else if (sourcePath != null && !sourcePath.isAbsolute()) {
915: throw new JavaModelException(
916: new JavaModelStatus(
917: IJavaModelStatusConstants.RELATIVE_PATH,
918: sourcePath));
919: }
920: }
921:
922: }
|