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