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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
13 import java.io.ByteArrayInputStream;
14 import java.io.UnsupportedEncodingException;
15 import java.util.ArrayList;
17 import net.sourceforge.phpdt.core.IBuffer;
18 import net.sourceforge.phpdt.core.IBufferFactory;
19 import net.sourceforge.phpdt.core.ICompilationUnit;
20 import net.sourceforge.phpdt.core.IJavaElement;
21 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
22 import net.sourceforge.phpdt.core.IJavaProject;
23 import net.sourceforge.phpdt.core.IMethod;
24 import net.sourceforge.phpdt.core.IPackageFragment;
25 import net.sourceforge.phpdt.core.IProblemRequestor;
26 import net.sourceforge.phpdt.core.IType;
27 import net.sourceforge.phpdt.core.JavaModelException;
28 import net.sourceforge.phpdt.core.JavaCore;
30 import org.eclipse.core.resources.IFile;
31 import org.eclipse.core.resources.IMarker;
32 import org.eclipse.core.resources.IResource;
33 import org.eclipse.core.runtime.CoreException;
34 import org.eclipse.core.runtime.IProgressMonitor;
39 * Implementation of a working copy compilation unit. A working
40 * copy maintains the timestamp of the resource it was created
44 public class WorkingCopy extends CompilationUnit {
47 * If set, this is the factory that will be used to create the buffer.
49 protected IBufferFactory bufferFactory;
52 * If set, this is the problem requestor which will be used to notify problems
53 * detected during reconciling.
55 protected IProblemRequestor problemRequestor;
58 * A counter of the number of time clients have asked for this
59 * working copy. It is set to 1, if the working
60 * copy is not managed. When destroyed, this counter is
61 * set to 0. Once destroyed, this working copy cannot be opened
62 * and non-handle info can not be accessed. This is
63 * never true if this compilation unit is not a working
66 protected int useCount = 1;
70 protected WorkingCopy(IPackageFragment parent, String name, IBufferFactory bufferFactory) {
71 this(parent, name, bufferFactory, null);
75 protected WorkingCopy(IPackageFragment parent, String name, IBufferFactory bufferFactory, IProblemRequestor problemRequestor) {
78 bufferFactory == null ?
79 this.getBufferManager().getDefaultBufferFactory() :
81 this.problemRequestor = problemRequestor;
86 public void commit(boolean force, IProgressMonitor monitor) throws JavaModelException {
87 ICompilationUnit original = (ICompilationUnit)this.getOriginalElement();
88 if (original.exists()) {
89 CommitWorkingCopyOperation op= new CommitWorkingCopyOperation(this, force);
90 runOperation(op, monitor);
92 String encoding = this.getJavaProject().getOption(JavaCore.CORE_ENCODING, true);
93 String contents = this.getSource();
94 if (contents == null) return;
96 byte[] bytes = encoding == null
98 : contents.getBytes(encoding);
99 ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
100 IFile originalRes = (IFile)original.getResource();
101 if (originalRes.exists()) {
102 originalRes.setContents(
104 force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
112 } catch (CoreException e) {
113 throw new JavaModelException(e);
114 } catch (UnsupportedEncodingException e) {
115 throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
120 * Returns a new element info for this element.
122 protected OpenableElementInfo createElementInfo() {
123 return new WorkingCopyElementInfo();
128 public void destroy() {
129 if (--this.useCount > 0) {
130 if (SHARED_WC_VERBOSE) {
131 System.out.println("Decrementing use count of shared working copy " + this.toStringWithAncestors());//$NON-NLS-1$
136 DestroyWorkingCopyOperation op = new DestroyWorkingCopyOperation(this);
137 runOperation(op, null);
138 } catch (JavaModelException e) {
143 public boolean exists() {
144 // working copy always exists in the model until it is detroyed
145 return this.useCount != 0;
150 * Answers custom buffer factory
152 public IBufferFactory getBufferFactory(){
154 return this.bufferFactory;
158 * Working copies must be identical to be equal.
162 public boolean equals(Object o) {
167 * Returns the info for this handle.
168 * If this element is not already open, it and all of its parents are opened.
169 * Does not return null.
170 * NOTE: BinaryType infos are NJOT rooted under JavaElementInfo.
171 * @exception JavaModelException if the element is not present or not accessible
173 // public Object getElementInfo() throws JavaModelException {
175 // JavaModelManager manager = JavaModelManager.getJavaModelManager();
176 // boolean shouldPerformProblemDetection = false;
177 // synchronized(manager){
178 // Object info = manager.getInfo(this);
179 // if (info == null) {
180 // shouldPerformProblemDetection = true;
183 // Object info = super.getElementInfo(); // will populate if necessary
185 // // perform problem detection outside the JavaModelManager lock
186 // if (this.problemRequestor != null && shouldPerformProblemDetection && this.problemRequestor.isActive()){
187 // this.problemRequestor.beginReporting();
188 // CompilationUnitProblemFinder.process(this, this.problemRequestor, null);
189 // this.problemRequestor.endReporting();
196 public IJavaElement getOriginal(IJavaElement workingCopyElement) {
197 //not a element contained in a compilation unit
198 int javaElementType = workingCopyElement.getElementType();
199 if (javaElementType < COMPILATION_UNIT || javaElementType == CLASS_FILE) {
202 // if (workingCopyElement instanceof BinaryMember) {
205 IJavaElement parent = workingCopyElement.getParent();
206 ArrayList hierarchy = new ArrayList(4);
208 while (parent.getElementType() > COMPILATION_UNIT) {
209 hierarchy.add(parent);
210 parent = parent.getParent();
212 if (parent.getElementType() == COMPILATION_UNIT) {
213 hierarchy.add(((ICompilationUnit)parent).getOriginalElement());
216 ICompilationUnit cu = (ICompilationUnit) getOriginalElement();
217 if (javaElementType == COMPILATION_UNIT) {
218 parent = workingCopyElement;
220 if (((ICompilationUnit) parent).isWorkingCopy() && !((ICompilationUnit) parent).getOriginalElement().equals(cu)) {
224 switch (javaElementType) {
225 // case PACKAGE_DECLARATION :
226 // return cu.getPackageDeclaration(workingCopyElement.getElementName());
227 // case IMPORT_CONTAINER :
228 // return cu.getImportContainer();
229 // case IMPORT_DECLARATION :
230 // return cu.getImport(workingCopyElement.getElementName());
232 // if (hierarchy.size() == 1) {
233 // return cu.getType(workingCopyElement.getElementName());
236 // return getOriginalType(hierarchy).getType(workingCopyElement.getElementName());
240 if (hierarchy.size() == 2) {
241 String typeName = ((IJavaElement) hierarchy.get(0)).getElementName();
242 type = cu.getType(typeName);
245 // type = getOriginalType(hierarchy);
247 return type.getMethod(workingCopyElement.getElementName(), ((IMethod) workingCopyElement).getParameterTypes());
249 if (hierarchy.size() == 2) {
250 String typeName = ((IJavaElement) hierarchy.get(0)).getElementName();
251 type = cu.getType(typeName);
254 // type = getOriginalType(hierarchy);
256 return type.getField(workingCopyElement.getElementName());
257 // case INITIALIZER :
258 // if (hierarchy.size() == 2) {
259 // String typeName = ((IJavaElement) hierarchy.get(0)).getElementName();
260 // type = cu.getType(typeName);
263 // type = getOriginalType(hierarchy);
265 // return type.getInitializer(((Initializer) workingCopyElement).getOccurrenceCount());
266 case COMPILATION_UNIT :
275 public IJavaElement getOriginalElement() {
276 return new CompilationUnit((IPackageFragment)getParent(), getElementName());
278 //protected IType getOriginalType(ArrayList hierarchy) {
279 // int size = hierarchy.size() - 1;
280 // ICompilationUnit typeCU = (ICompilationUnit) hierarchy.get(size);
281 // String typeName = ((IJavaElement) hierarchy.get(size - 1)).getElementName();
282 // IType type = typeCU.getType(typeName);
284 // while (size > -1) {
285 // typeName = ((IJavaElement) hierarchy.get(size)).getElementName();
286 // type = ((IType) type).getType(typeName);
295 public IResource getResource() {
302 public IJavaElement getSharedWorkingCopy(IProgressMonitor monitor, IBufferFactory factory, IProblemRequestor problemRequestor) throws JavaModelException {
306 * Returns <code>null<code> - a working copy does not have an underlying resource.
310 public IResource getUnderlyingResource() throws JavaModelException {
316 public IJavaElement getWorkingCopy() throws JavaModelException {
322 public IJavaElement getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory, IProblemRequestor problemRequestor) throws JavaModelException {
328 public boolean isBasedOn(IResource resource) {
329 if (resource.getType() != IResource.FILE) {
332 if (this.useCount == 0) {
336 // if resource got deleted, then #getModificationStamp() will answer IResource.NULL_STAMP, which is always different from the cached
338 return ((CompilationUnitElementInfo) getElementInfo()).fTimestamp == ((IFile) resource).getModificationStamp();
339 } catch (JavaModelException e) {
346 public boolean isWorkingCopy() {
351 * @see IOpenable#makeConsistent(IProgressMonitor)
353 //public void makeConsistent(IProgressMonitor monitor) throws JavaModelException {
354 // if (!isConsistent()) { // TODO: this code isn't synchronized with regular opening of a working copy (should use getElementInfo)
355 // super.makeConsistent(monitor);
357 // if (monitor != null && monitor.isCanceled()) return;
358 // if (this.problemRequestor != null && this.problemRequestor.isActive()){
359 // this.problemRequestor.beginReporting();
360 // CompilationUnitProblemFinder.process(this, this.problemRequestor, monitor);
361 // this.problemRequestor.endReporting();
370 * @exception JavaModelException attempting to open a read only element for something other than navigation
371 * or if this is a working copy being opened after it has been destroyed.
373 public void open(IProgressMonitor monitor) throws JavaModelException {
374 if (this.useCount == 0) { // was destroyed
375 throw newNotPresentException();
379 if (monitor != null && monitor.isCanceled()) return;
380 if (this.problemRequestor != null && this.problemRequestor.isActive()){
381 this.problemRequestor.beginReporting();
382 CompilationUnitProblemFinder.process(this, this.problemRequestor, monitor);
383 this.problemRequestor.endReporting();
390 //protected IBuffer openBuffer(IProgressMonitor pm) throws JavaModelException {
392 // if (this.useCount == 0) throw newNotPresentException(); // was destroyed
394 // // create buffer - working copies may use custom buffer factory
395 // IBuffer buffer = getBufferFactory().createBuffer(this);
396 // if (buffer == null) return null;
398 // // set the buffer source if needed
399 // if (buffer.getCharacters() == null) {
400 // ICompilationUnit original = (ICompilationUnit)this.getOriginalElement();
401 // if (original.isOpen()) {
402 // buffer.setContents(original.getSource());
404 // IFile file = (IFile)original.getResource();
405 // if (file == null || !file.exists()) {
406 // // initialize buffer with empty contents
407 // buffer.setContents(CharOperation.NO_CHAR);
409 // buffer.setContents(Util.getResourceContentsAsCharArray(file));
414 // // add buffer to buffer cache
415 // this.getBufferManager().addBuffer(buffer);
417 // // listen to buffer changes
418 // buffer.addBufferChangedListener(this);
423 * @see Openable#openParent(IProgressMonitor)
425 protected void openParent(IProgressMonitor pm) throws JavaModelException {
426 // if (FIX_BUG25184) {
428 // super.openParent(pm);
429 // } catch(JavaModelException e){
430 // // allow parent to not exist for working copies defined outside classpath
431 // if (!e.isDoesNotExist()){
436 super.openParent(pm);
443 public IMarker[] reconcile() throws JavaModelException {
444 reconcile(false, null);
451 public void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws JavaModelException {
452 ReconcileWorkingCopyOperation op = new ReconcileWorkingCopyOperation(this, forceProblemDetection);
453 runOperation(op, monitor);
459 public void restore() throws JavaModelException {
461 if (this.useCount == 0) throw newNotPresentException(); //was destroyed
463 CompilationUnit original = (CompilationUnit) getOriginalElement();
464 IBuffer buffer = this.getBuffer();
465 if (buffer == null) return;
466 buffer.setContents(original.getContents());
467 updateTimeStamp(original);
468 makeConsistent(null);
471 * @see JavaElement#rootedAt(IJavaProject)
473 public IJavaElement rootedAt(IJavaProject project) {
476 (IPackageFragment)((JavaElement)fParent).rootedAt(project),
484 public void save(IProgressMonitor pm, boolean force) throws JavaModelException {
486 throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.READ_ONLY, this));
488 // no need to save the buffer for a working copy (this is a noop)
489 //IBuffer buf = getBuffer();
490 //if (buf != null) { // some Openables (like a JavaProject) don't have a buffer
491 // buf.save(pm, force);
492 this.reconcile(); // not simply makeConsistent, also computes fine-grain deltas
493 // in case the working copy is being reconciled already (if not it would miss
494 // one iteration of deltas).
499 * @private Debugging purposes
501 protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
502 buffer.append(this.tabString(tab));
503 buffer.append("[Working copy] "); //$NON-NLS-1$
504 super.toStringInfo(0, buffer, info);
506 protected void updateTimeStamp(CompilationUnit original) throws JavaModelException {
508 ((IFile) original.getResource()).getModificationStamp();
509 if (timeStamp == IResource.NULL_STAMP) {
510 throw new JavaModelException(
511 new JavaModelStatus(IJavaModelStatusConstants.INVALID_RESOURCE));
513 ((CompilationUnitElementInfo) getElementInfo()).fTimestamp = timeStamp;