001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.repository;
029
030import org.opencms.file.CmsFile;
031import org.opencms.file.CmsResource;
032import org.opencms.file.CmsResourceFilter;
033import org.opencms.file.CmsUser;
034import org.opencms.file.CmsVfsResourceAlreadyExistsException;
035import org.opencms.file.CmsVfsResourceNotFoundException;
036import org.opencms.file.types.CmsResourceTypeFolder;
037import org.opencms.file.wrapper.CmsObjectWrapper;
038import org.opencms.lock.CmsLock;
039import org.opencms.main.CmsException;
040import org.opencms.main.CmsLog;
041import org.opencms.main.OpenCms;
042import org.opencms.security.CmsSecurityException;
043import org.opencms.util.CmsFileUtil;
044
045import java.io.IOException;
046import java.io.InputStream;
047import java.util.ArrayList;
048import java.util.Iterator;
049import java.util.List;
050
051import org.apache.commons.logging.Log;
052
053/**
054 * This is the session class to work with the {@link CmsRepository}.<p>
055 *
056 * You can get an instance of this class by calling
057 * {@link CmsRepository#login(String, String)}.<p>
058 *
059 * This class provides basic file and folder operations on the resources
060 * in the VFS of OpenCms.<p>
061 *
062 * @see A_CmsRepositorySession
063 * @see I_CmsRepositorySession
064 *
065 * @since 6.5.6
066 */
067public class CmsRepositorySession extends A_CmsRepositorySession {
068
069    /** The log object for this class. */
070    private static final Log LOG = CmsLog.getLog(CmsRepositorySession.class);
071
072    /** The initialized {@link CmsObjectWrapper}. */
073    private final CmsObjectWrapper m_cms;
074
075    /**
076     * Constructor with an initialized {@link CmsObjectWrapper} and a
077     * {@link CmsRepositoryFilter} to use.<p>
078     *
079     * @param cms the initialized CmsObject
080     * @param filter the repository filter to use
081     */
082    public CmsRepositorySession(CmsObjectWrapper cms, CmsRepositoryFilter filter) {
083
084        m_cms = cms;
085        setFilter(filter);
086    }
087
088    /**
089     * @see org.opencms.repository.I_CmsRepositorySession#copy(java.lang.String, java.lang.String, boolean)
090     */
091    public void copy(String src, String dest, boolean overwrite) throws CmsException {
092
093        src = validatePath(src);
094        dest = validatePath(dest);
095
096        if (LOG.isDebugEnabled()) {
097            LOG.debug(Messages.get().getBundle().key(Messages.LOG_COPY_ITEM_2, src, dest));
098        }
099
100        // It is only possible in OpenCms to overwrite files.
101        // Folder are not possible to overwrite.
102        if (exists(dest)) {
103
104            if (overwrite) {
105                CmsResource srcRes = m_cms.readResource(src, CmsResourceFilter.DEFAULT);
106                CmsResource destRes = m_cms.readResource(dest, CmsResourceFilter.DEFAULT);
107
108                if ((srcRes.isFile()) && (destRes.isFile())) {
109
110                    if (LOG.isDebugEnabled()) {
111                        LOG.debug(Messages.get().getBundle().key(Messages.LOG_DELETE_DEST_0));
112                    }
113
114                    // delete existing resource
115                    delete(dest);
116                } else {
117
118                    if (LOG.isDebugEnabled()) {
119                        LOG.debug(Messages.get().getBundle().key(Messages.ERR_OVERWRITE_0));
120                    }
121
122                    // internal error (not possible)
123                    throw new CmsException(Messages.get().container(Messages.ERR_OVERWRITE_0));
124                }
125            } else {
126
127                if (LOG.isDebugEnabled()) {
128                    LOG.debug(Messages.get().getBundle().key(Messages.ERR_DEST_EXISTS_0));
129                }
130
131                throw new CmsVfsResourceAlreadyExistsException(Messages.get().container(Messages.ERR_DEST_EXISTS_0));
132            }
133        }
134
135        // copy resource
136        m_cms.copyResource(src, dest, CmsResource.COPY_PRESERVE_SIBLING);
137
138        // unlock destination resource
139        m_cms.unlockResource(dest);
140    }
141
142    /**
143     * @see org.opencms.repository.I_CmsRepositorySession#create(java.lang.String)
144     */
145    public void create(String path) throws CmsException {
146
147        path = validatePath(path);
148
149        if (LOG.isDebugEnabled()) {
150            LOG.debug(Messages.get().getBundle().key(Messages.LOG_CREATE_ITEM_1, path));
151        }
152
153        // create the folder
154        CmsResource res = m_cms.createResource(path, CmsResourceTypeFolder.RESOURCE_TYPE_ID);
155
156        // unlock new created folders if lock is not inherited
157        if (!m_cms.getLock(res).isInherited()) {
158            m_cms.unlockResource(path);
159        }
160    }
161
162    /**
163     * @see org.opencms.repository.I_CmsRepositorySession#delete(java.lang.String)
164     */
165    public void delete(String path) throws CmsException {
166
167        path = validatePath(path);
168
169        if (LOG.isDebugEnabled()) {
170            LOG.debug(Messages.get().getBundle().key(Messages.LOG_DELETE_ITEM_1, path));
171        }
172
173        CmsRepositoryLockInfo lock = getLock(path);
174
175        // lock resource
176        m_cms.lockResource(path);
177
178        // delete resource
179        m_cms.deleteResource(path, CmsResource.DELETE_PRESERVE_SIBLINGS);
180
181        // if deleting items out of a xml page restore lock state after deleting
182        try {
183            if (lock == null) {
184                m_cms.unlockResource(path);
185            }
186        } catch (CmsException ex) {
187            // noop
188        }
189    }
190
191    /**
192     * @see org.opencms.repository.I_CmsRepositorySession#exists(java.lang.String)
193     */
194    public boolean exists(String path) {
195
196        try {
197            path = validatePath(path);
198            return m_cms.existsResource(path);
199        } catch (CmsException ex) {
200            return false;
201        }
202    }
203
204    /**
205     * @see org.opencms.repository.I_CmsRepositorySession#getItem(java.lang.String)
206     */
207    public I_CmsRepositoryItem getItem(String path) throws CmsException {
208
209        path = validatePath(path);
210
211        if (LOG.isDebugEnabled()) {
212            LOG.debug(Messages.get().getBundle().key(Messages.LOG_READ_ITEM_1, path));
213        }
214
215        CmsResource res = m_cms.readResource(path, CmsResourceFilter.DEFAULT);
216
217        CmsRepositoryItem item = new CmsRepositoryItem(res, m_cms);
218        return item;
219    }
220
221    /**
222     * @see org.opencms.repository.I_CmsRepositorySession#getLock(java.lang.String)
223     */
224    public CmsRepositoryLockInfo getLock(String path) {
225
226        try {
227            CmsRepositoryLockInfo lockInfo = new CmsRepositoryLockInfo();
228
229            path = validatePath(path);
230
231            CmsResource res = m_cms.readResource(path, CmsResourceFilter.DEFAULT);
232
233            // check user locks
234            CmsLock cmsLock = m_cms.getLock(res);
235            if (!cmsLock.isUnlocked()) {
236                lockInfo.setPath(path);
237
238                CmsUser owner = m_cms.readUser(cmsLock.getUserId());
239                if (owner != null) {
240                    lockInfo.setUsername(owner.getName());
241                    lockInfo.setOwner(owner.getName() + "||" + owner.getEmail());
242                }
243                return lockInfo;
244            }
245
246            return null;
247        } catch (CmsException ex) {
248
249            // error occurred while finding locks
250            // return null (no lock found)
251            return null;
252        }
253    }
254
255    /**
256     * @see org.opencms.repository.I_CmsRepositorySession#list(java.lang.String)
257     */
258    public List<I_CmsRepositoryItem> list(String path) throws CmsException {
259
260        List<I_CmsRepositoryItem> ret = new ArrayList<I_CmsRepositoryItem>();
261
262        path = validatePath(path);
263
264        if (LOG.isDebugEnabled()) {
265            LOG.debug(Messages.get().getBundle().key(Messages.LOG_LIST_ITEMS_1, path));
266        }
267
268        List<CmsResource> resources = m_cms.getResourcesInFolder(path, CmsResourceFilter.DEFAULT);
269        Iterator<CmsResource> iter = resources.iterator();
270        while (iter.hasNext()) {
271            CmsResource res = iter.next();
272
273            if (!isFiltered(m_cms.getRequestContext().removeSiteRoot(res.getRootPath()))) {
274
275                // open the original resource (for virtual files this is the resource in the VFS
276                // which the virtual resource is based on)
277                // this filters e.g. property files for resources that are filtered out and thus
278                // should not be displayed
279                CmsResource org = m_cms.readResource(res.getStructureId(), CmsResourceFilter.DEFAULT);
280                if (!isFiltered(m_cms.getRequestContext().removeSiteRoot(org.getRootPath()))) {
281                    ret.add(new CmsRepositoryItem(res, m_cms));
282                }
283            }
284        }
285
286        if (LOG.isDebugEnabled()) {
287            LOG.debug(Messages.get().getBundle().key(Messages.LOG_LIST_ITEMS_SUCESS_1, new Integer(ret.size())));
288        }
289
290        return ret;
291    }
292
293    /**
294     * @see org.opencms.repository.I_CmsRepositorySession#lock(java.lang.String, org.opencms.repository.CmsRepositoryLockInfo)
295     */
296    public boolean lock(String path, CmsRepositoryLockInfo lock) throws CmsException {
297
298        path = validatePath(path);
299
300        if (LOG.isDebugEnabled()) {
301            LOG.debug(Messages.get().getBundle().key(Messages.LOG_LOCK_ITEM_1, path));
302        }
303
304        m_cms.lockResource(path);
305        return true;
306    }
307
308    /**
309     * @see org.opencms.repository.I_CmsRepositorySession#move(java.lang.String, java.lang.String, boolean)
310     */
311    public void move(String src, String dest, boolean overwrite) throws CmsException {
312
313        src = validatePath(src);
314        dest = validatePath(dest);
315
316        if (LOG.isDebugEnabled()) {
317            LOG.debug(Messages.get().getBundle().key(Messages.LOG_MOVE_ITEM_2, src, dest));
318        }
319
320        // It is only possible in OpenCms to overwrite files.
321        // Folder are not possible to overwrite.
322        if (exists(dest)) {
323
324            if (overwrite) {
325                CmsResource srcRes = m_cms.readResource(src, CmsResourceFilter.DEFAULT);
326                CmsResource destRes = m_cms.readResource(dest, CmsResourceFilter.DEFAULT);
327
328                if ((srcRes.isFile()) && (destRes.isFile())) {
329
330                    if (LOG.isDebugEnabled()) {
331                        LOG.debug(Messages.get().getBundle().key(Messages.LOG_DELETE_DEST_0));
332                    }
333
334                    // delete existing resource
335                    delete(dest);
336                } else {
337
338                    if (LOG.isDebugEnabled()) {
339                        LOG.debug(Messages.get().getBundle().key(Messages.ERR_OVERWRITE_0));
340                    }
341
342                    throw new CmsException(Messages.get().container(Messages.ERR_OVERWRITE_0));
343                }
344            } else {
345
346                if (LOG.isDebugEnabled()) {
347                    LOG.debug(Messages.get().getBundle().key(Messages.ERR_DEST_EXISTS_0));
348                }
349
350                throw new CmsVfsResourceAlreadyExistsException(Messages.get().container(Messages.ERR_DEST_EXISTS_0));
351            }
352        }
353
354        // lock source resource
355        m_cms.lockResource(src);
356
357        // moving
358        m_cms.moveResource(src, dest);
359
360        // unlock destination resource
361        m_cms.unlockResource(dest);
362    }
363
364    /**
365     * @see org.opencms.repository.I_CmsRepositorySession#save(java.lang.String, java.io.InputStream, boolean)
366     */
367    public void save(String path, InputStream inputStream, boolean overwrite) throws CmsException, IOException {
368
369        path = validatePath(path);
370        byte[] content = CmsFileUtil.readFully(inputStream);
371
372        try {
373            CmsFile file = m_cms.readFile(path, CmsResourceFilter.DEFAULT);
374
375            if (LOG.isDebugEnabled()) {
376                LOG.debug(Messages.get().getBundle().key(Messages.LOG_UPDATE_ITEM_1, path));
377            }
378
379            if (overwrite) {
380
381                file.setContents(content);
382
383                CmsLock lock = m_cms.getLock(file);
384
385                // lock resource
386                if (!lock.isInherited()) {
387                    m_cms.lockResource(path);
388                }
389
390                // write file
391                m_cms.writeFile(file);
392
393                if (lock.isNullLock()) {
394                    m_cms.unlockResource(path);
395                }
396            } else {
397
398                if (LOG.isDebugEnabled()) {
399                    LOG.debug(Messages.get().getBundle().key(Messages.ERR_DEST_EXISTS_0));
400                }
401
402                throw new CmsVfsResourceAlreadyExistsException(Messages.get().container(Messages.ERR_DEST_EXISTS_0));
403            }
404        } catch (CmsVfsResourceNotFoundException ex) {
405
406            if (LOG.isDebugEnabled()) {
407                LOG.debug(Messages.get().getBundle().key(Messages.LOG_CREATE_ITEM_1, path));
408            }
409
410            int type = OpenCms.getResourceManager().getDefaultTypeForName(path).getTypeId();
411
412            // create the file
413            CmsResource res = m_cms.createResource(path, type, content, null);
414
415            // unlock file after creation if lock is not inherited
416            if (!m_cms.getLock(res).isInherited()) {
417                m_cms.unlockResource(path);
418            }
419        }
420
421    }
422
423    /**
424     * @see org.opencms.repository.I_CmsRepositorySession#unlock(java.lang.String)
425     */
426    public void unlock(String path) {
427
428        try {
429            path = validatePath(path);
430
431            if (LOG.isDebugEnabled()) {
432                LOG.debug(Messages.get().getBundle().key(Messages.LOG_UNLOCK_ITEM_1, path));
433            }
434
435            m_cms.unlockResource(path);
436        } catch (CmsException ex) {
437
438            if (LOG.isErrorEnabled()) {
439                LOG.error(Messages.get().getBundle().key(Messages.ERR_UNLOCK_FAILED_0), ex);
440            }
441        }
442    }
443
444    /**
445     * Adds the site root to the path name and checks then if the path
446     * is filtered.<p>
447     *
448     * @see org.opencms.repository.A_CmsRepositorySession#isFiltered(java.lang.String)
449     */
450    @Override
451    protected boolean isFiltered(String name) {
452
453        boolean ret = super.isFiltered(m_cms.getRequestContext().addSiteRoot(name));
454        if (ret) {
455
456            if (LOG.isDebugEnabled()) {
457                LOG.debug(Messages.get().getBundle().key(Messages.ERR_ITEM_FILTERED_1, name));
458            }
459
460        }
461
462        return ret;
463    }
464
465    /**
466     * Validates (translates) the given path and checks if it is filtered out.<p>
467     *
468     * @param path the path to validate
469     *
470     * @return the validated path
471     *
472     * @throws CmsSecurityException if the path is filtered out
473     */
474    private String validatePath(String path) throws CmsSecurityException {
475
476        // Problems with spaces in new folders (default: "Neuer Ordner")
477        // Solution: translate this to a correct name.
478        String ret = m_cms.getRequestContext().getFileTranslator().translateResource(path);
479
480        // add site root only works correct if system folder ends with a slash
481        if (CmsResource.VFS_FOLDER_SYSTEM.equals(ret)) {
482            ret = ret.concat("/");
483        }
484
485        // filter path
486        if (isFiltered(ret)) {
487            throw new CmsSecurityException(Messages.get().container(Messages.ERR_ITEM_FILTERED_1, path));
488        }
489
490        return ret;
491    }
492}