You are viewing limited content. For full access, please sign in.

Question

Question

check to see if folder

SDK
asked on February 27, 2014

 Using RA how do I see if a folder exist, if not create it

1 0

Answer

APPROVED ANSWER
replied on February 27, 2014 Show version history

Bert's example will work, but it has a few code patterns that should be avoided:

  • Depending on Exceptions for expected behavior. The Try-Catch around Folder.GetFolderInfo is not the best way to check if an entry exists. Exceptions are expensive to throw, so if you aren't sure that the item should exist, and you don't require that it exists, you should test for its existence without an Exception. In this case, the best way to do this is to use Entry.TryGetEntryInfo and check for a null return value instead of Folder.GetFolderInfo and expect an exception.
  • Using recursion to create the parent folders. This works, but function calls are not free, and in edge cases you can get problems like stack overflow. Instead, you can unwind the recursion with a stack.
  • Returning -1 for errors instead of throwing an Exception. You can't tell what went wrong when you return -1, and if later you decide that getting -1 should merit throwing an exception you won't get the full stack trace on your problem. When a method encounters a problem that it cannot recover from, it should throw an exception. If you want to stick with this design pattern, you should name the method "TryGetFolderID" to make it clear that you won't get Exceptions.
  • Returning an int instead of a FolderInfo means that there is time in between creating the folder and acquiring a lock on it, which can lead to problems in some cases, and is harder on the server (see Michael Allen's repsonse here).

Again, Cliff's suggestion looks like it will work. That said, here is a rework of the method, addressing some of the above issues in C#:

private static FolderInfo CreateHelper(string path, Session s)
{
    EntryInfo entry = null;
    Stack<string> toCreate = new Stack<string>();
    if (!path.StartsWith("\\"))
        path = "\\" + path;
    
    // This is equivalent to the recursion in the other
    // solution, but with an explicit stack instead of relying
    // on the call stack for state.
    while (entry == null)
    {
        toCreate.Push(path.Split('\\').Last());
        path = path.Substring(0, path.LastIndexOf('\\'));
        if (path == "")
            path = "\\";
        entry = Entry.TryGetEntryInfo(path, s);
    }
    FolderInfo folder = entry as FolderInfo;
    if (folder == null)
    {
        throw new DuplicateObjectException(
            "A parent of the requested folder is a non-folder entry.");
    }

    // Walk back up the stack as if returning from recursive
    // calls.
    FolderInfo parent = null;
    try
    {
        while (toCreate.Count > 0)
        {
            if (parent != null)
                parent.Dispose();
            parent = folder;
            folder = new FolderInfo(s);
            path = toCreate.Pop();
            folder.Create(parent, path, EntryNameOption.None);
        }
    }
    catch (Exception)
    {
        // Guarantee that folder does not leak if an Exception
        // is thrown.
        if (folder != null)
            folder.Dispose();
        throw;
    }
    finally
    {
        // Guarantee that parent does not leak.
        if (parent != null)
            parent.Dispose();
    }

    return folder;
}

public static FolderInfo GetOrCreateFolderInfo(string path, Session s)
{
    if (path == null)
        throw new ArgumentNullException("Path is null.");
    if (s == null)
        throw new ArgumentNullException("Session is null.");
    if (path == "")
        throw new ArgumentException("Path in an empty string.");

    // Will return null instead of throwing an Exception if the
    // entry does not exist.
    EntryInfo entry = Entry.TryGetEntryInfo(path, s);

    if (entry != null)
    {
        FolderInfo folder = entry as FolderInfo;
        if (folder != null)
        {
            return folder;
        }
        else
        {
            throw new DuplicateObjectException("Object already exists");
        }
    }
    else
    {
        return CreateHelper(path, s);
    }
}

To use it, call GetOrCreateFolderInfo with a path and a Session argument. It will make a best effort to create the folder. Note that this will throw Exceptions in cases similar to those when Folder.Create will throw Exceptions; invalid arguments, non-folder object already at the location that it is trying to put a folder. Also, the returned FolderInfo object must be disposed in order to avoid leaks!

 

The logic is almost identical to Bert's, but it unrolls the recursion, uses a different method to check for existence of the folder, and uses a different method to create the FolderInfo object. Its not perfectly optimized, and the string manipulations especially could use some work for clarity, but it appears to work in the limited test cases that I've tried it in.

 

EDIT 4/29/14: Added some comments to the code, fixed one or two wording issues in the text. Updated the helper method to fix a possible leak.

6 0
replied on September 18, 2018

This is a very useful block of code, thank you!

However I do think there is a FolderInfo lock leak in CreateHelper();  I had LF Admin open, and viewed Entry Locks, and I noticed that the leaf folder remained locked, and the locks accumulated for each new leaf folder created.  

To resolve this, I modifed the bottom half of CreateHelper() as follows:

           // Walk back up the stack as if returning from recursive
            // calls.
            FolderInfo parent = null;
            FolderInfo child = null;            // Added
            try
            {
                while (toCreate.Count > 0)
                {
                    if (parent != null)
                        parent.Dispose();
                    parent = folder;
                    folder = new FolderInfo(s);
                    child = folder;        // Added
                    path = toCreate.Pop();
                    folder.Create(parent, path, EntryNameOption.None);
                }
            }
            catch (Exception)
            {
                // Guarantee that folder does not leak if an Exception
                // is thrown.
                if (folder != null)
                    folder.Dispose();
                throw;
            }
            finally
            {
                // Guarantee that parent does not leak.
                if (parent != null)
                    parent.Dispose();
                if (child != null)          // Added
                    child.Dispose();
            }

 

1 0

Replies

replied on February 27, 2014 Show version history

here is a function I use:

    Private Function GetFolderID(ByVal sFolderPath As String, ByVal bCreateMissing As Boolean) As Integer
        Dim iReturn As Integer = -1
        Try
            ' Only try if session object is not null
            If mySession IsNot Nothing Then
                'Try to get folder by path
                Try
                    Dim myFolder As FolderInfo = Folder.GetFolderInfo(sFolderPath, mySession)
                    ' Save folder ID
                    iReturn = myFolder.Id
                    ' Release folder
                    myFolder.Dispose()
                    ' Return Folder ID
                    Return iReturn
                Catch
                    'Folder not found, but do nothing here
                End Try
                ' Only create missing folder if bCreateMissing is True
                If bCreateMissing Then
                    ' Get Parent path
                    Dim sParentPath As String = sFolderPath.Substring(0, sFolderPath.LastIndexOf("\"))
                    ' Get folder name
                    Dim sFolderName As String = sFolderPath.Substring(sFolderPath.LastIndexOf("\") + 1)
                    ' Get Parent ID
                    Dim iParentID As Integer = GetFolderID(sParentPath, bCreateMissing)
                    Try
                        ' Get Parent folder object
                        Dim ParentFolder As FolderInfo = Folder.GetFolderInfo(iParentID, mySession)
                        ' Create missing folder
                        iReturn = Folder.Create(ParentFolder, sFolderName, EntryNameOption.AutoRename, mySession)
                        ' Release parent folder
                        ParentFolder.Dispose()
                    Catch ex As Exception
                        ' Log error here
                        ' Make sure return value is -1
                        iReturn = -1
                    End Try
                End If
            End If
        Catch ex As Exception
            ' Log error here
            ' Make sure return value is -1
            iReturn = -1
        End Try
        ' Return Folder ID
        Return iReturn
    End Function

Requirements of this function:

  1. Path does not include Repository name and starts with "\"
  2. Path does not end with "\"
  3. mySession is a valid Session object with a valid connection to the repository with rights to create folders in path if missing

 

This function can be used like this:

     ' Get Folder ID
     Dim iFolderID As Integer = GetFolderID("\FolderPath", True)
     ' must be greater then -1 to be a folder ID
     If iFolderID > -1 Then
         'Folder exists
         MessageBox.Show("Folder ID: " & iFolderID.ToString)
     End If

 

4 0
replied on December 26, 2019

Bert,

Seeing your code helped get my program to work.  I needed to see the Dim myFolder As FolderInfo = Folder.GetFolderInfo(sFolderPath, mySession)  once I had that I was able to complete the rest of my code.

 

Thank you for your help!

Gary Schreader

1 0
You are not allowed to follow up in this post.

Sign in to reply to this post.