3m9 compatible;
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / JavaElement.java
index c45befb..8cfe6d8 100644 (file)
 package net.sourceforge.phpdt.internal.core;
 
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
 
 import net.sourceforge.phpdt.core.ICompilationUnit;
 import net.sourceforge.phpdt.core.IJavaElement;
 import net.sourceforge.phpdt.core.IJavaModel;
 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
 import net.sourceforge.phpdt.core.IJavaProject;
+import net.sourceforge.phpdt.core.IMember;
 import net.sourceforge.phpdt.core.IOpenable;
+import net.sourceforge.phpdt.core.IParent;
+import net.sourceforge.phpdt.core.ISourceRange;
+import net.sourceforge.phpdt.core.ISourceReference;
 import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
+import net.sourceforge.phpdt.core.jdom.IDOMNode;
+import net.sourceforge.phpdt.internal.corext.Assert;
 
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import net.sourceforge.phpdt.internal.core.JavaElementInfo;
+
+import net.sourceforge.phpdt.internal.core.JavaModelManager;
+import net.sourceforge.phpdt.internal.core.util.Util;
 
 /**
  * Root of Java element handle hierarchy.
@@ -50,83 +71,58 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement
         * them.  The occurrence count starts at 1 (thus the first 
         * occurrence is occurrence 1, not occurrence 0).
         */
-       protected int fOccurrenceCount = 1;
+       protected int occurrenceCount = 1;
 
 
        /**
         * This element's type - one of the constants defined
         * in IJavaLanguageElementTypes.
         */
-       protected int fLEType = 0;
+       //protected int fLEType = 0;
 
        /**
         * This element's parent, or <code>null</code> if this
         * element does not have a parent.
         */
-       protected IJavaElement fParent;
+       protected IJavaElement parent;
 
        /**
         * This element's name, or an empty <code>String</code> if this
         * element does not have a name.
         */
-       protected String fName;
+       protected String name;
 
        protected static final Object NO_INFO = new Object();
        
        /**
-        * Constructs a handle for a java element of the specified type, with
+        * Constructs a handle for a java element with
         * the given parent element and name.
         *
-        * @param type - one of the constants defined in IJavaLanguageElement
+        * @param parent The parent of java element
+        * @param name The name of java element
         *
         * @exception IllegalArgumentException if the type is not one of the valid
         *              Java element type constants
         *
         */
-       protected JavaElement(int type, IJavaElement parent, String name) throws IllegalArgumentException {
-               if (type < JAVA_MODEL || type > IMPORT_DECLARATION) {
-                       throw new IllegalArgumentException(Util.bind("element.invalidType")); //$NON-NLS-1$
-               }
-               fLEType= type;
-               fParent= parent;
-               fName= name;
+       protected JavaElement(JavaElement parent, String name) throws IllegalArgumentException {
+               this.parent = parent;
+               this.name = name;
        }
        /**
         * @see IOpenable
         */
-//     public void close() throws JavaModelException {
-//             Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
-//             if (info != null) {
-//                     boolean wasVerbose = false;
-//                     try {
-//                             if (JavaModelManager.VERBOSE) {
-//                                     System.out.println("CLOSING Element ("+ Thread.currentThread()+"): " + this.toStringWithAncestors());  //$NON-NLS-1$//$NON-NLS-2$
-//                                     wasVerbose = true;
-//                                     JavaModelManager.VERBOSE = false;
-//                             }
-//                             if (this instanceof IParent) {
-//                                     IJavaElement[] children = ((JavaElementInfo) info).getChildren();
-//                                     for (int i = 0, size = children.length; i < size; ++i) {
-//                                             JavaElement child = (JavaElement) children[i];
-//                                             child.close();
-//                                     }
-//                             }
-//                             closing(info);
-//                             JavaModelManager.getJavaModelManager().removeInfo(this);
-//                             if (wasVerbose) {
-//                                     System.out.println("-> Package cache size = " + JavaModelManager.getJavaModelManager().cache.pkgSize()); //$NON-NLS-1$
-//                                     System.out.println("-> Openable cache filling ratio = " + JavaModelManager.getJavaModelManager().cache.openableFillingRatio() + "%"); //$NON-NLS-1$//$NON-NLS-2$
-//                             }
-//                     } finally {
-//                             JavaModelManager.VERBOSE = wasVerbose;
-//                     }
-//             }
-//     }
+       public void close() throws JavaModelException {
+               JavaModelManager.getJavaModelManager().removeInfoAndChildren(this);
+       }
        /**
         * This element is being closed.  Do any necessary cleanup.
         */
-       protected void closing(Object info) throws JavaModelException {
-       }
+       protected abstract void closing(Object info) throws JavaModelException;
+       /*
+        * Returns a new element info for this element.
+        */
+       protected abstract Object createElementInfo();
        /**
         * Returns true if this handle represents the same Java element
         * as the given handle. By default, two handles represent the same
@@ -143,25 +139,21 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement
                if (this == o) return true;
        
                // Java model parent is null
-               if (fParent == null) return super.equals(o);
+               if (this.parent == null) return super.equals(o);
        
-               if (o instanceof JavaElement) {
-                       JavaElement other = (JavaElement) o;
-                       if (fLEType != other.fLEType) return false;
-                       
-                       return fName.equals(other.fName) &&
-                                       fParent.equals(other.fParent) &&
-                                       fOccurrenceCount == other.fOccurrenceCount;
-               }
-               return false;
+               // assume instanceof check is done in subclass
+               JavaElement other = (JavaElement) o;            
+               return this.occurrenceCount == other.occurrenceCount &&
+                               this.name.equals(other.name) &&
+                               this.parent.equals(other.parent);
        }
        /**
         * Returns true if this <code>JavaElement</code> is equivalent to the given
         * <code>IDOMNode</code>.
         */
-//     protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
-//             return false;
-//     }
+       protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+               return false;
+       }
        /**
         * @see IJavaElement
         */
@@ -179,66 +171,66 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement
         * Returns the <code>IDOMNode</code> that corresponds to this <code>JavaElement</code>
         * or <code>null</code> if there is no corresponding node.
         */
-//     public IDOMNode findNode(IDOMCompilationUnit dom) {
-//             int type = getElementType();
-//             if (type == IJavaElement.COMPILATION_UNIT || 
-//                     type == IJavaElement.FIELD || 
-//                     type == IJavaElement.IMPORT_DECLARATION || 
-//                     type == IJavaElement.INITIALIZER || 
-//                     type == IJavaElement.METHOD || 
-//                     type == IJavaElement.PACKAGE_DECLARATION || 
-//                     type == IJavaElement.TYPE) {
-//                     ArrayList path = new ArrayList();
-//                     IJavaElement element = this;
-//                     while (element != null && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
-//                             if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) {
-//                                     // the DOM does not have import containers, so skip them
-//                                     path.add(0, element);
-//                             }
-//                             element = element.getParent();
-//                     }
-//                     if (path.size() == 0) {
-//                             try {
-//                                     if (equalsDOMNode(dom)) {
-//                                             return dom;
-//                                     } else {
-//                                             return null;
-//                                     }
-//                             } catch(JavaModelException e) {
-//                                     return null;
-//                             }
-//                     }
-//                     return ((JavaElement) path.get(0)).followPath(path, 0, dom.getFirstChild());
-//             } else {
-//                     return null;
-//             }
-//     }
-//     /**
-//      */
-//     protected IDOMNode followPath(ArrayList path, int position, IDOMNode node) {
-//     
-//             try {
-//                     if (equalsDOMNode(node)) {
-//                             if (position == (path.size() - 1)) {
-//                                     return node;
-//                             } else {
-//                                     if (node.getFirstChild() != null) {
-//                                             position++;
-//                                             return ((JavaElement)path.get(position)).followPath(path, position, node.getFirstChild());
-//                                     } else {
-//                                             return null;
-//                                     }
-//                             }
-//                     } else if (node.getNextNode() != null) {
-//                             return followPath(path, position, node.getNextNode());
-//                     } else {
-//                             return null;
-//                     }
-//             } catch (JavaModelException e) {
-//                     return null;
-//             }
-//     
-//     }
+       public IDOMNode findNode(IDOMCompilationUnit dom) {
+               int type = getElementType();
+               if (type == IJavaElement.COMPILATION_UNIT || 
+                       type == IJavaElement.FIELD || 
+                       type == IJavaElement.IMPORT_DECLARATION || 
+                       type == IJavaElement.INITIALIZER || 
+                       type == IJavaElement.METHOD || 
+                       type == IJavaElement.PACKAGE_DECLARATION || 
+                       type == IJavaElement.TYPE) {
+                       ArrayList path = new ArrayList();
+                       IJavaElement element = this;
+                       while (element != null && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
+                               if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) {
+                                       // the DOM does not have import containers, so skip them
+                                       path.add(0, element);
+                               }
+                               element = element.getParent();
+                       }
+                       if (path.size() == 0) {
+                               try {
+                                       if (equalsDOMNode(dom)) {
+                                               return dom;
+                                       } else {
+                                               return null;
+                                       }
+                               } catch(JavaModelException e) {
+                                       return null;
+                               }
+                       }
+                       return ((JavaElement) path.get(0)).followPath(path, 0, dom.getFirstChild());
+               } else {
+                       return null;
+               }
+       }
+       /**
+        */
+       protected IDOMNode followPath(ArrayList path, int position, IDOMNode node) {
+       
+               try {
+                       if (equalsDOMNode(node)) {
+                               if (position == (path.size() - 1)) {
+                                       return node;
+                               } else {
+                                       if (node.getFirstChild() != null) {
+                                               position++;
+                                               return ((JavaElement)path.get(position)).followPath(path, position, node.getFirstChild());
+                                       } else {
+                                               return null;
+                                       }
+                               }
+                       } else if (node.getNextNode() != null) {
+                               return followPath(path, position, node.getNextNode());
+                       } else {
+                               return null;
+                       }
+               } catch (JavaModelException e) {
+                       return null;
+               }
+       
+       }
        /**
         * @see IJavaElement
         */
@@ -252,6 +244,12 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement
                return null;                            
        }
        /**
+        * Generates the element infos for this element, its ancestors (if they are not opened) and its children (if it is an Openable).
+        * Puts the newly created element info in the given map.
+        */
+       protected abstract void generateInfos(Object info, HashMap newElements, IProgressMonitor pm) throws JavaModelException;
+       
+       /**
         * @see IParent 
         */
        public IJavaElement[] getChildren() throws JavaModelException {
@@ -291,49 +289,33 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement
         * Returns the info for this handle.  
         * If this element is not already open, it and all of its parents are opened.
         * Does not return null.
-        * NOTE: BinaryType infos are NJOT rooted under JavaElementInfo.
+        * NOTE: BinaryType infos are NOT rooted under JavaElementInfo.
         * @exception JavaModelException if the element is not present or not accessible
         */
        public Object getElementInfo() throws JavaModelException {
-return null;
-               // workaround to ensure parent project resolved classpath is available to avoid triggering initializers
-               // while the JavaModelManager lock is acquired (can cause deadlocks in clients)
-//             IJavaProject project = getJavaProject();
-//             if (project != null && !project.isOpen()) {
-//                     // TODO: need to revisit, since deadlock could still occur if perProjectInfo is removed concurrent before entering the lock
-//                     try {
-//                             project.getResolvedClasspath(true); // trigger all possible container/variable initialization outside the model lock
-//                     } catch (JavaModelException e) {
-//                             // project is not accessible or is not a java project
-//                     }
-//             }
-//
-//             // element info creation is done inside a lock on the JavaModelManager
-//             JavaModelManager manager;
-//             synchronized(manager = JavaModelManager.getJavaModelManager()){
-//                     Object info = manager.getInfo(this);
-//                     if (info == null) {
-//                             openHierarchy();
-//                             info= manager.getInfo(this);
-//                             if (info == null) {
-//                                     throw newNotPresentException();
-//                             }
-//                     }
-//                     return info;
-//             }
+               return getElementInfo(null);
        }
        /**
-        * @see IAdaptable
+        * Returns the info for this handle.  
+        * If this element is not already open, it and all of its parents are opened.
+        * Does not return null.
+        * NOTE: BinaryType infos are NOT rooted under JavaElementInfo.
+        * @exception JavaModelException if the element is not present or not accessible
         */
-       public String getElementName() {
-               return fName;
+       public Object getElementInfo(IProgressMonitor monitor) throws JavaModelException {
+
+               JavaModelManager manager = JavaModelManager.getJavaModelManager();
+               Object info = manager.getInfo(this);
+               if (info != null) return info;
+               return openWhenClosed(createElementInfo(), monitor);
        }
        /**
-        * @see IJavaElement
+        * @see IAdaptable
         */
-       public int getElementType() {
-               return fLEType;
+       public String getElementName() {
+               return name;
        }
+
        /**
         * @see IJavaElement
         */
@@ -379,7 +361,7 @@ return null;
         * Returns the occurrence count of the handle.
         */
        protected int getOccurrenceCount() {
-               return fOccurrenceCount;
+               return occurrenceCount;
        }
        /*
         * @see IJavaElement
@@ -395,15 +377,28 @@ return null;
         */
        public IOpenable getOpenableParent() {
                
-               return (IOpenable)fParent;
+               return (IOpenable)parent;
        }
        /**
         * @see IJavaElement
         */
        public IJavaElement getParent() {
-               return fParent;
+               return parent;
        }
        
+       /*
+        * @see IJavaElement#getPrimaryElement()
+        */
+       public IJavaElement getPrimaryElement() {
+               return getPrimaryElement(true);
+       }
+       /*
+        * Returns the primary element. If checkOwner, and the cu owner is primary,
+        * return this element.
+        */
+       public IJavaElement getPrimaryElement(boolean checkOwner) {
+               return this;
+       }
        /**
         * Returns the element that is located at the given source position
         * in this element.  This is a helper method for <code>ICompilationUnit#getElementAt</code>,
@@ -411,30 +406,30 @@ return null;
         * known to be within this element's source range already, and if no finer
         * grained element is found at the position, this element is returned.
         */
-//     protected IJavaElement getSourceElementAt(int position) throws JavaModelException {
-//             if (this instanceof ISourceReference) {
-//                     IJavaElement[] children = getChildren();
-//                     int i;
-//                     for (i = 0; i < children.length; i++) {
-//                             IJavaElement aChild = children[i];
-//                             if (aChild instanceof SourceRefElement) {
-//                                     SourceRefElement child = (SourceRefElement) children[i];
-//                                     ISourceRange range = child.getSourceRange();
-//                                     if (position < range.getOffset() + range.getLength() && position >= range.getOffset()) {
-//                                             if (child instanceof IParent) {
-//                                                     return child.getSourceElementAt(position);
-//                                             } else {
-//                                                     return child;
-//                                             }
-//                                     }
-//                             }
-//                     }
-//             } else {
-//                     // should not happen
-//                     Assert.isTrue(false);
-//             }
-//             return this;
-//     }
+       protected IJavaElement getSourceElementAt(int position) throws JavaModelException {
+               if (this instanceof ISourceReference) {
+                       IJavaElement[] children = getChildren();
+                       int i;
+                       for (i = 0; i < children.length; i++) {
+                               IJavaElement aChild = children[i];
+                               if (aChild instanceof SourceRefElement) {
+                                       SourceRefElement child = (SourceRefElement) children[i];
+                                       ISourceRange range = child.getSourceRange();
+                                       if (position < range.getOffset() + range.getLength() && position >= range.getOffset()) {
+                                               if (child instanceof IParent) {
+                                                       return child.getSourceElementAt(position);
+                                               } else {
+                                                       return child;
+                                               }
+                                       }
+                               }
+                       }
+               } else {
+                       // should not happen
+                       Assert.isTrue(false);
+               }
+               return this;
+       }
        /**
         * Returns the SourceMapper facility for this element, or
         * <code>null</code> if this element does not have a
@@ -443,6 +438,51 @@ return null;
 //     public SourceMapper getSourceMapper() {
 //             return ((JavaElement)getParent()).getSourceMapper();
 //     }
+       /* (non-Javadoc)
+        * @see org.eclipse.jdt.core.IJavaElement#getSchedulingRule()
+        */
+       public ISchedulingRule getSchedulingRule() {
+               IResource resource = getResource();
+               if (resource == null) {
+                       class NoResourceSchedulingRule implements ISchedulingRule {
+                               public IPath path;
+                               public NoResourceSchedulingRule(IPath path) {
+                                       this.path = path;
+                               }
+                               public boolean contains(ISchedulingRule rule) {
+                                       if (rule instanceof NoResourceSchedulingRule) {
+                                               return this.path.isPrefixOf(((NoResourceSchedulingRule)rule).path);
+                                       } else {
+                                               return false;
+                                       }
+                               }
+                               public boolean isConflicting(ISchedulingRule rule) {
+                                       if (rule instanceof NoResourceSchedulingRule) {
+                                               IPath otherPath = ((NoResourceSchedulingRule)rule).path;
+                                               return this.path.isPrefixOf(otherPath) || otherPath.isPrefixOf(this.path);
+                                       } else {
+                                               return false;
+                                       }
+                               }
+                       }
+                       return new NoResourceSchedulingRule(getPath());
+               } else {
+                       return resource;
+               }
+       }
+       /**
+        * @see IParent 
+        */
+       public boolean hasChildren() throws JavaModelException {
+               // if I am not open, return true to avoid opening (case of a Java project, a compilation unit or a class file).
+               // also see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52474
+               Object elementInfo = JavaModelManager.getJavaModelManager().getInfo(this);
+               if (elementInfo instanceof JavaElementInfo) {
+                       return ((JavaElementInfo)elementInfo).getChildren().length > 0;
+               } else {
+                       return true;
+               }
+       }
 
        /**
         * Returns the hash code for this Java element. By default,
@@ -451,9 +491,10 @@ return null;
         * override this method.
         */
        public int hashCode() {
-               if (fParent == null) return super.hashCode();
-               return Util.combineHashCodes(fName.hashCode(), fParent.hashCode());
+               if (this.parent == null) return super.hashCode();
+               return Util.combineHashCodes(this.name.hashCode(), this.parent.hashCode());
        }
+       
        /**
         * Returns true if this element is an ancestor of the given element,
         * otherwise false.
@@ -475,20 +516,20 @@ return null;
        /**
         * @see IJavaElement
         */
-//     public boolean isStructureKnown() throws JavaModelException {
-//             return ((JavaElementInfo)getElementInfo()).isStructureKnown();
-//     }
+       public boolean isStructureKnown() throws JavaModelException {
+               return ((JavaElementInfo)getElementInfo()).isStructureKnown();
+       }
        /**
         * Creates and returns and not present exception for this element.
         */
        protected JavaModelException newNotPresentException() {
                return new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
        }
-//     /**
-//      * Opens this element and all parents that are not already open.
-//      *
-//      * @exception JavaModelException this element is not present or accessible
-//      */
+       /**
+        * Opens this element and all parents that are not already open.
+        *
+        * @exception JavaModelException this element is not present or accessible
+        */
 //     protected void openHierarchy() throws JavaModelException {
 //             if (this instanceof IOpenable) {
 //                     ((Openable) this).openWhenClosed(null);
@@ -509,6 +550,40 @@ return null;
         */
        protected void opening(Object info) {
        }
+       /*
+        * Opens an <code>Openable</code> that is known to be closed (no check for <code>isOpen()</code>).
+        * Returns the created element info.
+        */
+       protected Object openWhenClosed(Object info, IProgressMonitor monitor) throws JavaModelException {
+               JavaModelManager manager = JavaModelManager.getJavaModelManager();
+               boolean hadTemporaryCache = manager.hasTemporaryCache();
+               try {
+                       HashMap newElements = manager.getTemporaryCache();
+                       generateInfos(info, newElements, monitor);
+                       if (info == null) {
+                               info = newElements.get(this);
+                       }
+                       if (info == null) { // a source ref element could not be opened
+                               // close any buffer that was opened for the openable parent
+                               Iterator iterator = newElements.keySet().iterator();
+                               while (iterator.hasNext()) {
+                                       IJavaElement element = (IJavaElement)iterator.next();
+                                       if (element instanceof Openable) {
+                                               ((Openable)element).closeBuffer();
+                                       }
+                               }
+                               throw newNotPresentException();
+                       }
+                       if (!hadTemporaryCache) {
+                               manager.putInfos(this, newElements);
+                       }
+               } finally {
+                       if (!hadTemporaryCache) {
+                               manager.resetTemporaryCache();
+                       }
+               }
+               return info;
+       }
        /**
         */
        public String readableName() {
@@ -534,37 +609,37 @@ return null;
 //     /**
 //      * Returns a copy of this element rooted at the given project.
 //      */
-       public abstract IJavaElement rootedAt(IJavaProject project);
-//     /**
-//      * Runs a Java Model Operation
-//      */
-//     public static void runOperation(JavaModelOperation operation, IProgressMonitor monitor) throws JavaModelException {
-//             try {
-//                     if (operation.isReadOnly() || ResourcesPlugin.getWorkspace().isTreeLocked()) {
-//                             operation.run(monitor);
-//                     } else {
-//                             // use IWorkspace.run(...) to ensure that a build will be done in autobuild mode
-//                             ResourcesPlugin.getWorkspace().run(operation, monitor);
-//                     }
-//             } catch (CoreException ce) {
-//                     if (ce instanceof JavaModelException) {
-//                             throw (JavaModelException)ce;
-//                     } else {
-//                             if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
-//                                     Throwable e= ce.getStatus().getException();
-//                                     if (e instanceof JavaModelException) {
-//                                             throw (JavaModelException) e;
-//                                     }
-//                             }
-//                             throw new JavaModelException(ce);
-//                     }
-//             }
-//     }
+//     public abstract IJavaElement rootedAt(IJavaProject project);
+       /**
+        * Runs a Java Model Operation
+        */
+       public static void runOperation(JavaModelOperation operation, IProgressMonitor monitor) throws JavaModelException {
+               try {
+                       if (operation.isReadOnly() || ResourcesPlugin.getWorkspace().isTreeLocked()) {
+                               operation.run(monitor);
+                       } else {
+                               // use IWorkspace.run(...) to ensure that a build will be done in autobuild mode
+                               ResourcesPlugin.getWorkspace().run(operation, monitor);
+                       }
+               } catch (CoreException ce) {
+                       if (ce instanceof JavaModelException) {
+                               throw (JavaModelException)ce;
+                       } else {
+                               if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
+                                       Throwable e= ce.getStatus().getException();
+                                       if (e instanceof JavaModelException) {
+                                               throw (JavaModelException) e;
+                                       }
+                               }
+                               throw new JavaModelException(ce);
+                       }
+               }
+       }
        /**
         * Sets the occurrence count of the handle.
         */
        protected void setOccurrenceCount(int count) {
-               fOccurrenceCount = count;
+               occurrenceCount = count;
        }
        protected String tabString(int tab) {
                StringBuffer buffer = new StringBuffer();