1 /* ownCloud Android client application
2 * Copyright (C) 2015 ownCloud Inc.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2,
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package com
.owncloud
.android
.files
.services
;
20 import android
.accounts
.Account
;
22 import com
.owncloud
.android
.datamodel
.OCFile
;
25 import java
.util
.HashSet
;
26 import java
.util
.Iterator
;
28 import java
.util
.concurrent
.ConcurrentHashMap
;
29 import java
.util
.concurrent
.ConcurrentMap
;
32 * Helper structure to keep the trees of folders containing any file downloading or synchronizing.
34 * A map provides the indexation based in hashing.
36 * A tree is created per account.
38 * @author David A. Velasco
40 public class IndexedForest
<V
> {
42 private ConcurrentMap
<String
, Node
<V
>> mMap
= new ConcurrentHashMap
<String
, Node
<V
>>();
44 private class Node
<V
> {
46 Node
<V
> mParent
= null
;
47 Set
<Node
<V
>> mChildren
= new HashSet
<Node
<V
>>(); // TODO be careful with hash()
50 // payload is optional
51 public Node(String key
, V payload
) {
53 throw new IllegalArgumentException("Argument key MUST NOT be null");
59 public Node
<V
> getParent() {
63 public Set
<Node
<V
>> getChildren() {
67 public String
getKey() {
71 public V
getPayload() {
75 public void addChild(Node
<V
> child
) {
77 child
.setParent(this);
80 private void setParent(Node
<V
> parent
) {
84 public boolean hasChildren() {
85 return mChildren
.size() > 0;
88 public void removeChild(Node
<V
> removed
) {
89 mChildren
.remove(removed
);
94 public /* synchronized */ String
putIfAbsent(Account account
, String remotePath
, V value
) {
95 String targetKey
= buildKey(account
, remotePath
);
96 Node
<V
> valuedNode
= new Node(targetKey
, value
);
102 String currentPath
= remotePath
, parentPath
= null
, parentKey
= null
;
103 Node
<V
> currentNode
= valuedNode
, parentNode
= null
;
104 boolean linked
= false
;
105 while (!OCFile
.ROOT_PATH
.equals(currentPath
) && !linked
) {
106 parentPath
= new File(currentPath
).getParent();
107 if (!parentPath
.endsWith(OCFile
.PATH_SEPARATOR
)) {
108 parentPath
+= OCFile
.PATH_SEPARATOR
;
110 parentKey
= buildKey(account
, parentPath
);
111 parentNode
= mMap
.get(parentKey
);
112 if (parentNode
== null
) {
113 parentNode
= new Node(parentKey
, null
);
114 parentNode
.addChild(currentNode
);
115 mMap
.put(parentKey
, parentNode
);
117 parentNode
.addChild(currentNode
);
120 currentPath
= parentPath
;
121 currentNode
= parentNode
;
127 public /* synchronized */ V
remove(Account account
, String remotePath
) {
128 String targetKey
= buildKey(account
, remotePath
);
129 Node
<V
> firstRemoved
= mMap
.remove(targetKey
);
131 if (firstRemoved
!= null
) {
133 removeDescendants(firstRemoved
);
135 /// remove ancestors if only here due to firstRemoved
136 Node
<V
> removed
= firstRemoved
;
137 Node
<V
> parent
= removed
.getParent();
138 while (parent
!= null
) {
139 parent
.removeChild(removed
);
140 if (!parent
.hasChildren()) {
141 removed
= mMap
.remove(parent
.getKey());
142 parent
= removed
.getParent();
149 if (firstRemoved
!= null
) {
150 return firstRemoved
.getPayload();
157 private void removeDescendants(Node
<V
> removed
) {
158 Iterator
<Node
<V
>> childrenIt
= removed
.getChildren().iterator();
159 Node
<V
> child
= null
;
160 while (childrenIt
.hasNext()) {
161 child
= childrenIt
.next();
162 mMap
.remove(child
.getKey());
163 removeDescendants(child
);
167 public boolean contains(Account account
, String remotePath
) {
168 String targetKey
= buildKey(account
, remotePath
);
169 return mMap
.containsKey(targetKey
);
172 public /* synchronized */ V
get(String key
) {
173 Node
<V
> node
= mMap
.get(key
);
175 return node
.getPayload();
183 * Builds a key to index files
185 * @param account Account where the file to download is stored
186 * @param remotePath Path of the file in the server
188 private String
buildKey(Account account
, String remotePath
) {
189 return account
.name
+ remotePath
;