Merge branch 'master' of git.curoverse.com:arvados into 11876-r-sdk
[arvados.git] / sdk / R / R / Collection.R
1 source("./R/Arvados.R")
2 source("./R/HttpParser.R")
3 source("./R/Subcollection.R")
4 source("./R/ArvadosFile.R")
5
6 #' Collection Class
7 #' 
8 #' @details 
9 #' Todo: Update description
10 #' Collection
11 #' 
12 #' @param uuid Object ID
13 #' @param etag Object version
14 #' @param owner_uuid No description
15 #' @param created_at No description
16 #' @param modified_by_client_uuid No description
17 #' @param modified_by_user_uuid No description
18 #' @param modified_at No description
19 #' @param portable_data_hash No description
20 #' @param replication_desired No description
21 #' @param replication_confirmed_at No description
22 #' @param replication_confirmed No description
23 #' @param updated_at No description
24 #' @param manifest_text No description
25 #' @param name No description
26 #' @param description No description
27 #' @param properties No description
28 #' @param delete_at No description
29 #' @param file_names No description
30 #' @param trash_at No description
31 #' @param is_trashed No description
32 #' 
33 #' @export Collection
34
35 #' @exportClass Collection
36 Collection <- setRefClass(
37
38     "Collection",
39
40     fields = list(uuid                     = "ANY",
41                   items                    = "ANY",
42                   fileContent              = "ANY",
43                   etag                     = "ANY",
44                   owner_uuid               = "ANY",
45                   created_at               = "ANY",
46                   modified_by_client_uuid  = "ANY",
47                   modified_by_user_uuid    = "ANY",
48                   modified_at              = "ANY",
49                   portable_data_hash       = "ANY",
50                   replication_desired      = "ANY",
51                   replication_confirmed_at = "ANY",
52                   replication_confirmed    = "ANY",
53                   updated_at               = "ANY",
54                   manifest_text            = "ANY",
55                   name                     = "ANY",
56                   description              = "ANY",
57                   properties               = "ANY",
58                   delete_at                = "ANY",
59                   file_names               = "ANY",
60                   trash_at                 = "ANY",
61                   is_trashed               = "ANY",
62
63                   getCollectionContent = "function",
64                   get                  = "function"
65     ),
66
67     methods = list(
68
69         initialize = function(api, uuid) 
70         {
71             result <- api$collection_get(uuid)
72             
73             # Private members
74             uuid                     <<- result$uuid                               
75             etag                     <<- result$etag                               
76             owner_uuid               <<- result$owner_uuid                         
77             created_at               <<- result$created_at                         
78             modified_by_client_uuid  <<- result$modified_by_client_uuid            
79             modified_by_user_uuid    <<- result$modified_by_user_uuid              
80             modified_at              <<- result$modified_at                        
81             portable_data_hash       <<- result$portable_data_hash                 
82             replication_desired      <<- result$replication_desired                
83             replication_confirmed_at <<- result$replication_confirmed_at           
84             replication_confirmed    <<- result$replication_confirmed              
85             updated_at               <<- result$updated_at                         
86             manifest_text            <<- result$manifest_text                      
87             name                     <<- result$name                               
88             description              <<- result$description                        
89             properties               <<- result$properties                         
90             delete_at                <<- result$delete_at                          
91             file_names               <<- result$file_names                         
92             trash_at                 <<- result$trash_at                           
93             is_trashed               <<- result$is_trashed                         
94
95             # Public methods
96
97             getCollectionContent <<- function()
98             {
99                 #TODO(Fudo): Use proper URL here.
100                 uri <- URLencode(api$getWebDavHostName())
101
102                 # fetch directory listing via curl and parse XML response
103                 h <- curl::new_handle()
104                 curl::handle_setopt(h, customrequest = "PROPFIND")
105
106                 #TODO(Fudo): Use proper token here.
107                 curl::handle_setheaders(h, "Authorization" = paste("OAuth2", api$getWebDavToken()))
108                 response <- curl::curl_fetch_memory(uri, h)
109
110                 HttpParser()$parseWebDAVResponse(response, uri)
111             }
112
113             get <<- function(pathToTheFile)
114             {
115                 fileWithPath <- unlist(stringr::str_split(pathToTheFile, "/"))
116                 fileWithPath <- fileWithPath[fileWithPath != ""]
117
118                 findFileIfExists <- function(name, node)
119                 {
120                     matchPosition <- match(name, sapply(node$content, function(nodeInSubcollection) {nodeInSubcollection$name}), -1)
121                     if(matchPosition != -1)
122                     {
123                         return(node$content[[matchPosition]])
124                     }
125                     else
126                     {
127                         return(NULL)
128                     }
129                 }
130                 
131                 nodeToCheck = .self$fileContent
132                 for(fileNameIndex in 1:length(fileWithPath))
133                 {
134                     nodeToCheck <- findFileIfExists(fileWithPath[fileNameIndex], nodeToCheck)
135                     if(is.null(nodeToCheck))
136                         stop("File or folder you asked for is not part of the collection.")
137                 }
138
139                 nodeToCheck
140             }
141
142
143             # Private methods
144             .createCollectionContentTree <- function(fileStructure)
145             {
146                 #TODO(Fudo): Refactor this.
147                 #TODO(Fudo): Find a way to link children to parents. (R has no pointers or references).
148                 treeBranches <- sapply(fileStructure, function(filePath)
149                 {
150                     fileWithPath <- unlist(stringr::str_split(filePath, "/"))
151                     file <- fileWithPath[length(fileWithPath), drop = T]
152
153                     if(file != "")
154                     {
155                         file <- ArvadosFile(file, api)
156                         file$relativePath <- filePath
157                     }
158                     else
159                     {
160                         file <- NULL
161                     }
162
163                     folders <- fileWithPath[-length(fileWithPath)]
164
165                     subcollections <- sapply(folders, function(folder)
166                     {
167                         folder <- Subcollection(folder)
168                         unname(folder)
169                     })
170
171                     if(!is.null(file))
172                         subcollections <- c(subcollections, file)
173
174                     if(length(subcollections) > 1)
175                     {
176                         for(subcollectionIndex in 1:(length(subcollections) - 1))
177                         {
178                             subcollections[[subcollectionIndex]]$relativePath <- paste(folders[1:(subcollectionIndex)], collapse = "/")
179                             subcollections[[subcollectionIndex]]$add(subcollections[[subcollectionIndex + 1]])
180                         }
181                     }
182                     subcollections[[1]]
183                 })
184
185                 root <- Subcollection(".")
186
187                 addIfExists <- function(firstNode, secondNode)
188                 {
189                     firstNodeContent <- sapply(firstNode$content, function(node) {node$name})
190                     if(length(firstNodeContent) == 0)
191                     {
192                         firstNode$add(secondNode)
193                         return()
194                     }
195
196                     matchPosition <- match(secondNode$name, firstNodeContent, -1)
197                     if(matchPosition != -1)
198                     {
199                         addIfExists(firstNode$content[[matchPosition]], secondNode$content[[1]])
200                     }
201                     else
202                     {
203                         firstNode$add(secondNode)
204                     }
205                 }
206
207                 sapply(treeBranches, function(branch)
208                 {
209                     addIfExists(root, branch)
210                 })
211
212                 root
213             }
214
215             #Todo(Fudo): This is dummy data. Real content will come from WebDAV server.
216             # testFileStructure <- c("math.h", "main.cpp", "emptyFolder/",
217                                    # "java/render.java", "java/test/observer.java",
218                                    # "java/test/observable.java",
219                                    # "csharp/this.cs", "csharp/is.cs",
220                                    # "csharp/dummy.cs", "csharp/file.cs")
221             items  <<- getCollectionContent()
222             fileContent  <<- .createCollectionContentTree(items)
223         }
224     )
225 )