001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Gagnavarslan ehf
018 */
019package org.nuxeo.ecm.webdav.backend;
020
021import java.util.ArrayList;
022import java.util.HashMap;
023import java.util.LinkedList;
024import java.util.List;
025import java.util.Map;
026import java.util.concurrent.ConcurrentHashMap;
027
028import org.apache.commons.lang3.StringUtils;
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.nuxeo.common.utils.Path;
032import org.nuxeo.ecm.core.api.Blob;
033import org.nuxeo.ecm.core.api.CoreSession;
034import org.nuxeo.ecm.core.api.DocumentModel;
035import org.nuxeo.ecm.core.api.DocumentRef;
036import org.nuxeo.ecm.core.api.PathRef;
037
038public abstract class AbstractVirtualBackend extends AbstractCoreBackend implements VirtualBackend {
039
040    private static final Log log = LogFactory.getLog(AbstractVirtualBackend.class);
041
042    protected Map<String, Backend> backendMap;
043
044    protected LinkedList<String> orderedBackendNames;
045
046    protected String rootUrl;
047
048    private String backendDisplayName;
049
050    private RealBackendFactory realBackendFactory;
051
052    protected AbstractVirtualBackend(String name, String rootUrl, CoreSession session,
053            RealBackendFactory realBackendFactory) {
054        super(session);
055        this.backendDisplayName = name;
056        this.rootUrl = new Path(rootUrl).append(this.backendDisplayName).toString();
057        this.realBackendFactory = realBackendFactory;
058    }
059
060    protected void registerSimpleBackends(List<DocumentModel> docs) {
061        List<String> paths = new ArrayList<>();
062        for (DocumentModel doc : docs) {
063            paths.add(doc.getPathAsString());
064        }
065
066        List<String> heads = new ArrayList<>();
067        for (int idx = 0; idx < paths.size(); idx++) {
068            String path = paths.get(idx);
069            if (isHead(path, paths, idx)) {
070                heads.add(path);
071            }
072        }
073
074        for (String head : heads) {
075            String headName = new Path(head).lastSegment();
076            String name = headName;
077            int idx = 1;
078            while (backendMap.containsKey(name)) {
079                name = headName + "-" + idx;
080                idx = idx + 1;
081            }
082
083            Backend backend = realBackendFactory.createBackend(name, head,
084                    new Path(this.rootUrl).append(name).toString(), getSession());
085
086            registerBackend(backend);
087        }
088    }
089
090    private boolean isHead(String path, List<String> paths, int idx) {
091        int level = new Path(path).segmentCount();
092
093        for (int i = idx; i >= 0; i--) {
094            String other = paths.get(i);
095            if (path.contains(other)) {
096                if (new Path(other).segmentCount() == level - 1) {
097                    return false;
098                }
099            }
100        }
101        return true;
102    }
103
104    @Override
105    public String getRootPath() {
106        return "";
107    }
108
109    @Override
110    public String getRootUrl() {
111        return rootUrl;
112    }
113
114    @Override
115    public final boolean isVirtual() {
116        return true;
117    }
118
119    @Override
120    public boolean isRoot() {
121        return false;
122    }
123
124    @Override
125    public String getBackendDisplayName() {
126        return backendDisplayName;
127    }
128
129    @Override
130    public LinkedList<String> getVirtualFolderNames() {
131        initIfNeed();
132        if (orderedBackendNames == null) {
133            return new LinkedList<>();
134        }
135        return orderedBackendNames;
136    }
137
138    protected void registerBackend(Backend backend) {
139        if (backendMap == null) {
140            backendMap = new ConcurrentHashMap<>();
141        }
142        if (orderedBackendNames == null) {
143            orderedBackendNames = new LinkedList<>();
144        }
145        backendMap.put(backend.getBackendDisplayName(), backend);
146        orderedBackendNames.add(backend.getBackendDisplayName());
147    }
148
149    @Override
150    public Backend getBackend(String uri) {
151        Path path = new Path(uri);
152        if (path.segmentCount() == 0) {
153            return this;
154        } else {
155            String key = path.segment(0);
156            initIfNeed();
157            if (backendMap == null) {
158                return null;
159            }
160            Backend backend = backendMap.get(key);
161            if (backend == null) {
162                return null;
163            }
164            String location = path.removeFirstSegments(1).toString();
165            return backend.getBackend(location);
166        }
167    }
168
169    protected void initIfNeed() {
170        if (backendMap == null || orderedBackendNames == null) {
171            backendMap = new HashMap<>();
172            orderedBackendNames = new LinkedList<>();
173            init();
174        }
175    }
176
177    protected abstract void init();
178
179    @Override
180    public boolean isLocked(DocumentRef ref) {
181        throw new UnsupportedOperationException();
182    }
183
184    @Override
185    public boolean canUnlock(DocumentRef ref) {
186        throw new UnsupportedOperationException();
187    }
188
189    @Override
190    public String lock(DocumentRef ref) {
191        throw new UnsupportedOperationException();
192    }
193
194    @Override
195    public boolean unlock(DocumentRef ref) {
196        throw new UnsupportedOperationException();
197    }
198
199    @Override
200    public String getCheckoutUser(DocumentRef ref) {
201        throw new UnsupportedOperationException();
202    }
203
204    @Override
205    public DocumentModel resolveLocation(String location) {
206        throw new UnsupportedOperationException(location);
207    }
208
209    @Override
210    public Path parseLocation(String location) {
211        throw new UnsupportedOperationException();
212    }
213
214    @Override
215    public void removeItem(String location) {
216        throw new UnsupportedOperationException();
217    }
218
219    @Override
220    public void removeItem(DocumentRef ref) {
221        throw new UnsupportedOperationException();
222    }
223
224    @Override
225    public void renameItem(DocumentModel source, String destinationName) {
226        throw new UnsupportedOperationException();
227    }
228
229    @Override
230    public DocumentModel moveItem(DocumentModel source, PathRef targetParentRef) {
231        throw new UnsupportedOperationException();
232    }
233
234    @Override
235    public DocumentModel copyItem(DocumentModel source, PathRef targetParentRef) {
236        throw new UnsupportedOperationException();
237    }
238
239    @Override
240    public DocumentModel createFolder(String parentPath, String name) {
241        throw new UnsupportedOperationException();
242    }
243
244    @Override
245    public DocumentModel createFile(String parentPath, String name, Blob content) {
246        throw new UnsupportedOperationException();
247    }
248
249    @Override
250    public DocumentModel createFile(String parentPath, String name) {
251        throw new UnsupportedOperationException();
252    }
253
254    @Override
255    public List<DocumentModel> getChildren(DocumentRef ref) {
256        throw new UnsupportedOperationException();
257    }
258
259    @Override
260    public boolean isRename(String source, String destination) {
261        throw new UnsupportedOperationException();
262    }
263
264    @Override
265    public boolean exists(String location) {
266        throw new UnsupportedOperationException(location);
267    }
268
269    @Override
270    public String getDisplayName(DocumentModel doc) {
271        throw new UnsupportedOperationException();
272    }
273
274    @Override
275    public boolean hasPermission(DocumentRef docRef, String permission) {
276        throw new UnsupportedOperationException();
277    }
278
279    @Override
280    public DocumentModel getDocument(String location) {
281        throw new UnsupportedOperationException();
282    }
283
284    @Override
285    public DocumentModel updateDocument(DocumentModel doc, String name, Blob content) {
286        throw new UnsupportedOperationException();
287    }
288
289    @Override
290    public DocumentModel moveItem(DocumentModel source, DocumentRef targetParentRef, String name)
291            {
292        throw new UnsupportedOperationException();
293    }
294
295    @Override
296    public String getVirtualPath(String path) {
297        initIfNeed();
298        for (String backendName : orderedBackendNames) {
299            Backend backend = backendMap.get(backendName);
300            String url = backend.getVirtualPath(path);
301            if (StringUtils.isNotEmpty(url)) {
302                return url;
303            }
304        }
305        return null;
306    }
307
308    @Override
309    public LinkedList<String> getOrderedBackendNames() {
310        initIfNeed();
311        return orderedBackendNames;
312    }
313
314}