001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.documentlibrary.store;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.util.CharPool;
019    import com.liferay.portal.kernel.util.ContentTypes;
020    import com.liferay.portal.kernel.util.LocaleUtil;
021    import com.liferay.portal.kernel.util.StringPool;
022    import com.liferay.portal.kernel.util.StringUtil;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.portal.repository.cmis.CMISRepositoryUtil;
025    import com.liferay.portal.util.PropsValues;
026    import com.liferay.portlet.documentlibrary.DuplicateFileException;
027    import com.liferay.portlet.documentlibrary.NoSuchFileException;
028    import com.liferay.portlet.documentlibrary.util.DLUtil;
029    
030    import java.io.InputStream;
031    
032    import java.util.ArrayList;
033    import java.util.HashMap;
034    import java.util.List;
035    import java.util.Locale;
036    import java.util.Map;
037    
038    import org.apache.chemistry.opencmis.client.api.CmisObject;
039    import org.apache.chemistry.opencmis.client.api.Document;
040    import org.apache.chemistry.opencmis.client.api.Folder;
041    import org.apache.chemistry.opencmis.client.api.ItemIterable;
042    import org.apache.chemistry.opencmis.client.api.ObjectId;
043    import org.apache.chemistry.opencmis.client.api.Repository;
044    import org.apache.chemistry.opencmis.client.api.Session;
045    import org.apache.chemistry.opencmis.client.api.SessionFactory;
046    import org.apache.chemistry.opencmis.client.runtime.ObjectIdImpl;
047    import org.apache.chemistry.opencmis.commons.PropertyIds;
048    import org.apache.chemistry.opencmis.commons.SessionParameter;
049    import org.apache.chemistry.opencmis.commons.data.ContentStream;
050    import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
051    import org.apache.chemistry.opencmis.commons.enums.BindingType;
052    import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
053    import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
054    
055    /**
056     * @author Alexander Chow
057     * @author Edward Han
058     */
059    public class CMISStore extends BaseStore {
060    
061            public CMISStore() {
062                    _systemRootDir = getFolder(
063                            SessionHolder.session.getRootFolder(),
064                            PropsValues.DL_STORE_CMIS_SYSTEM_ROOT_DIR);
065    
066                    if (_systemRootDir == null) {
067                            _systemRootDir = createFolder(
068                                    SessionHolder.session.getRootFolder(),
069                                    PropsValues.DL_STORE_CMIS_SYSTEM_ROOT_DIR);
070                    }
071            }
072    
073            @Override
074            public void addDirectory(
075                    long companyId, long repositoryId, String dirName) {
076    
077                    Folder folder = getRepositoryFolder(companyId, repositoryId);
078    
079                    String[] dirNames = StringUtil.split(dirName, CharPool.SLASH);
080    
081                    for (String curDirName : dirNames) {
082                            Folder subFolder = getFolder(folder, curDirName);
083    
084                            if (subFolder == null) {
085                                    subFolder = createFolder(folder, curDirName);
086                            }
087    
088                            folder = subFolder;
089                    }
090            }
091    
092            @Override
093            public void addFile(
094                            long companyId, long repositoryId, String fileName, InputStream is)
095                    throws PortalException {
096    
097                    updateFile(companyId, repositoryId, fileName, VERSION_DEFAULT, is);
098            }
099    
100            @Override
101            public void checkRoot(long companyId) {
102            }
103    
104            @Override
105            public void copyFileVersion(
106                            long companyId, long repositoryId, String fileName,
107                            String fromVersionLabel, String toVersionLabel)
108                    throws PortalException {
109    
110                    Folder versioningFolder = getVersioningFolder(
111                            companyId, repositoryId, fileName, false);
112    
113                    ObjectId versioningFolderObjectId = new ObjectIdImpl(
114                            versioningFolder.getId());
115    
116                    Map<String, Object> documentProperties = new HashMap<String, Object>();
117    
118                    String title = String.valueOf(toVersionLabel);
119    
120                    documentProperties.put(PropertyIds.NAME, title);
121    
122                    documentProperties.put(
123                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_DOCUMENT.value());
124    
125                    Document document = getVersionedDocument(
126                            companyId, repositoryId, fileName, fromVersionLabel);
127    
128                    document.copy(
129                            versioningFolderObjectId, documentProperties, null,
130                            document.getPolicies(), null, null, null);
131            }
132    
133            @Override
134            public void deleteDirectory(
135                    long companyId, long repositoryId, String dirName) {
136    
137                    Folder repositoryFolder = getRepositoryFolder(companyId, repositoryId);
138    
139                    Folder directory = getFolder(repositoryFolder, dirName);
140    
141                    if (directory != null) {
142                            directory.deleteTree(true, UnfileObject.DELETE, false);
143                    }
144            }
145    
146            @Override
147            public void deleteFile(long companyId, long repositoryId, String fileName)
148                    throws PortalException {
149    
150                    Folder versioningFolder = getVersioningFolder(
151                            companyId, repositoryId, fileName, false);
152    
153                    if (versioningFolder == null) {
154                            throw new NoSuchFileException();
155                    }
156    
157                    versioningFolder.deleteTree(true, UnfileObject.DELETE, false);
158            }
159    
160            @Override
161            public void deleteFile(
162                            long companyId, long repositoryId, String fileName,
163                            String versionLabel)
164                    throws PortalException {
165    
166                    Document document = getVersionedDocument(
167                            companyId, repositoryId, fileName, versionLabel);
168    
169                    document.delete(true);
170            }
171    
172            @Override
173            public InputStream getFileAsStream(
174                            long companyId, long repositoryId, String fileName,
175                            String versionLabel)
176                    throws PortalException {
177    
178                    if (Validator.isNull(versionLabel)) {
179                            versionLabel = getHeadVersionLabel(
180                                    companyId, repositoryId, fileName);
181                    }
182    
183                    Document document = getVersionedDocument(
184                            companyId, repositoryId, fileName, versionLabel);
185    
186                    return document.getContentStream().getStream();
187            }
188    
189            public String[] getFileNames(long companyId, long repositoryId) {
190                    Folder folder = getRepositoryFolder(companyId, repositoryId);
191    
192                    List<Folder> folders = getFolders(folder);
193    
194                    String[] fileNames = new String[folders.size()];
195    
196                    for (int i = 0; i < folders.size(); i++) {
197                            Folder curFolder = folders.get(i);
198    
199                            fileNames[i] = curFolder.getName();
200                    }
201    
202                    return fileNames;
203            }
204    
205            @Override
206            public String[] getFileNames(
207                    long companyId, long repositoryId, String dirName) {
208    
209                    Folder folder = getRepositoryFolder(companyId, repositoryId);
210    
211                    String[] dirNames = StringUtil.split(dirName, CharPool.SLASH);
212    
213                    for (String curDirName : dirNames) {
214                            Folder subFolder = getFolder(folder, curDirName);
215    
216                            if (subFolder == null) {
217                                    subFolder = createFolder(folder, curDirName);
218                            }
219    
220                            folder = subFolder;
221                    }
222    
223                    List<Folder> folders = getFolders(folder);
224    
225                    String[] fileNames = new String[folders.size()];
226    
227                    for (int i = 0; i < folders.size(); i++) {
228                            Folder curFolder = folders.get(i);
229    
230                            String fileName = curFolder.getName();
231    
232                            fileNames[i] = dirName.concat(StringPool.SLASH).concat(fileName);
233                    }
234    
235                    return fileNames;
236            }
237    
238            @Override
239            public long getFileSize(long companyId, long repositoryId, String fileName)
240                    throws PortalException {
241    
242                    String versionLabel = getHeadVersionLabel(
243                            companyId, repositoryId, fileName);
244    
245                    Document document = getVersionedDocument(
246                            companyId, repositoryId, fileName, versionLabel);
247    
248                    return document.getContentStreamLength();
249            }
250    
251            public String getHeadVersionLabel(
252                            long companyId, long repositoryId, String dirName)
253                    throws NoSuchFileException {
254    
255                    Folder versioningFolder = getVersioningFolder(
256                            companyId, repositoryId, dirName, false);
257    
258                    if (versioningFolder == null) {
259                            throw new NoSuchFileException();
260                    }
261    
262                    List<Folder> folders = getFolders(versioningFolder);
263    
264                    String headVersionLabel = VERSION_DEFAULT;
265    
266                    for (Folder folder : folders) {
267                            String versionLabel = folder.getName();
268    
269                            if (DLUtil.compareVersions(versionLabel, headVersionLabel) > 0) {
270                                    headVersionLabel = versionLabel;
271                            }
272                    }
273    
274                    return headVersionLabel;
275            }
276    
277            @Override
278            public boolean hasDirectory(
279                    long companyId, long repositoryId, String dirName) {
280    
281                    Folder folder = getRepositoryFolder(companyId, repositoryId);
282    
283                    String[] dirNames = StringUtil.split(dirName, CharPool.SLASH);
284    
285                    for (String subdirName : dirNames) {
286                            Folder subfolder = getFolder(folder, subdirName);
287    
288                            if (subfolder == null) {
289                                    return false;
290                            }
291                    }
292    
293                    return true;
294            }
295    
296            @Override
297            public boolean hasFile(
298                    long companyId, long repositoryId, String fileName,
299                    String versionLabel) {
300    
301                    Folder versioningFolder = getVersioningFolder(
302                            companyId, repositoryId, fileName, true);
303    
304                    Document document = getDocument(versioningFolder, versionLabel);
305    
306                    if (document == null) {
307                            return false;
308                    }
309                    else {
310                            return true;
311                    }
312            }
313    
314            @Override
315            public void move(String srcDir, String destDir) {
316            }
317    
318            @Override
319            public void updateFile(
320                    long companyId, long repositoryId, long newRepositoryId,
321                    String fileName) {
322    
323                    Folder oldVersioningFolderEntry = getVersioningFolder(
324                            companyId, repositoryId, fileName, true);
325                    Folder newVersioningFolderEntry = getVersioningFolder(
326                            companyId, newRepositoryId, fileName, true);
327    
328                    List<Folder> folders = getFolders(oldVersioningFolderEntry);
329    
330                    for (Folder folder : folders) {
331                            String curFileName = folder.getName();
332    
333                            Document document = getDocument(
334                                    oldVersioningFolderEntry, curFileName);
335    
336                            InputStream is = document.getContentStream().getStream();
337    
338                            createDocument(newVersioningFolderEntry, curFileName, is);
339                    }
340    
341                    oldVersioningFolderEntry.deleteTree(true, UnfileObject.DELETE, false);
342            }
343    
344            public void updateFile(
345                    long companyId, long repositoryId, String fileName,
346                    String newFileName) {
347    
348                    Folder oldVersioningFolderEntry = getVersioningFolder(
349                            companyId, repositoryId, fileName, true);
350                    Folder newVersioningFolderEntry = getVersioningFolder(
351                            companyId, repositoryId, newFileName, true);
352    
353                    List<Folder> folders = getFolders(oldVersioningFolderEntry);
354    
355                    for (Folder folder : folders) {
356                            String curFileName = folder.getName();
357    
358                            Document document = getDocument(
359                                    oldVersioningFolderEntry, curFileName);
360    
361                            InputStream is = document.getContentStream().getStream();
362    
363                            createDocument(newVersioningFolderEntry, curFileName, is);
364                    }
365    
366                    oldVersioningFolderEntry.deleteTree(true, UnfileObject.DELETE, false);
367            }
368    
369            @Override
370            public void updateFile(
371                            long companyId, long repositoryId, String fileName,
372                            String versionLabel, InputStream is)
373                    throws PortalException {
374    
375                    Folder versioningFolder = getVersioningFolder(
376                            companyId, repositoryId, fileName, true);
377    
378                    String title = String.valueOf(versionLabel);
379    
380                    Document document = getDocument(versioningFolder, title);
381    
382                    if (document != null) {
383                            throw new DuplicateFileException();
384                    }
385    
386                    createDocument(versioningFolder, title, is);
387            }
388    
389            @Override
390            public void updateFileVersion(
391                            long companyId, long repositoryId, String fileName,
392                            String fromVersionLabel, String toVersionLabel)
393                    throws PortalException {
394    
395                    Folder versioningFolder = getVersioningFolder(
396                            companyId, repositoryId, fileName, false);
397    
398                    String title = String.valueOf(toVersionLabel);
399    
400                    Document document = getDocument(versioningFolder, title);
401    
402                    if (document != null) {
403                            throw new DuplicateFileException();
404                    }
405    
406                    document = getVersionedDocument(
407                            companyId, repositoryId, fileName, fromVersionLabel);
408    
409                    Map<String, Object> documentProperties = new HashMap<String, Object>();
410    
411                    documentProperties.put(PropertyIds.NAME, title);
412    
413                    document.updateProperties(documentProperties);
414            }
415    
416            protected Document createDocument(
417                    Folder versioningFolder, String title, InputStream is) {
418    
419                    Map<String, Object> documentProperties = new HashMap<String, Object>();
420    
421                    documentProperties.put(PropertyIds.NAME, title);
422                    documentProperties.put(
423                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_DOCUMENT.value());
424    
425                    ContentStream contentStream = new ContentStreamImpl(
426                            null, null, ContentTypes.APPLICATION_OCTET_STREAM, is);
427    
428                    return versioningFolder.createDocument(
429                            documentProperties, contentStream, null);
430            }
431    
432            protected Folder createFolder(ObjectId parentFolderId, String name) {
433                    Map<String, Object> properties = new HashMap<String, Object>();
434    
435                    properties.put(PropertyIds.NAME, name);
436                    properties.put(
437                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_FOLDER.value());
438    
439                    ObjectId objectId = SessionHolder.session.createFolder(
440                            properties, parentFolderId);
441    
442                    return (Folder)SessionHolder.session.getObject(objectId);
443            }
444    
445            protected Folder getCompanyFolder(long companyId) {
446                    String name = String.valueOf(companyId);
447    
448                    Folder companyFolder = getFolder(_systemRootDir, name);
449    
450                    if (companyFolder == null) {
451                            companyFolder = createFolder(_systemRootDir, name);
452                    }
453    
454                    return companyFolder;
455            }
456    
457            protected Document getDocument(Folder parentFolder, String name) {
458                    ItemIterable<CmisObject> cmisObjects = parentFolder.getChildren();
459    
460                    for (CmisObject cmisObject : cmisObjects) {
461                            if (name.equals(cmisObject.getName()) &&
462                                    cmisObject instanceof Document) {
463    
464                                    return (Document)cmisObject;
465                            }
466                    }
467    
468                    return null;
469            }
470    
471            protected Folder getFolder(Folder parentFolder, String name) {
472                    ItemIterable<CmisObject> cmisObjects = parentFolder.getChildren();
473    
474                    for (CmisObject cmisObject : cmisObjects) {
475                            if (name.equals(cmisObject.getName()) &&
476                                    cmisObject instanceof Folder) {
477    
478                                    return (Folder)cmisObject;
479                            }
480                    }
481    
482                    return null;
483            }
484    
485            protected List<Folder> getFolders(Folder folder) {
486                    List<Folder> folders = new ArrayList<Folder>();
487    
488                    ItemIterable<CmisObject> cmisObjects = folder.getChildren();
489    
490                    for (CmisObject cmisObject : cmisObjects) {
491                            if (cmisObject instanceof Folder) {
492                                    folders.add((Folder)cmisObject);
493                            }
494                    }
495    
496                    return folders;
497            }
498    
499            protected Folder getRepositoryFolder(long companyId, long repositoryId) {
500                    Folder companyFolder = getCompanyFolder(companyId);
501    
502                    String name = String.valueOf(repositoryId);
503    
504                    Folder repositoryFolder = getFolder(companyFolder, name);
505    
506                    if (repositoryFolder == null) {
507                            repositoryFolder = createFolder(companyFolder, name);
508                    }
509    
510                    return repositoryFolder;
511            }
512    
513            protected Document getVersionedDocument(
514                            long companyId, long repositoryId, String fileName,
515                            String versionLabel)
516                    throws NoSuchFileException {
517    
518                    Folder versioningFolder = getVersioningFolder(
519                            companyId, repositoryId, fileName, false);
520    
521                    if (versioningFolder == null) {
522                            throw new NoSuchFileException();
523                    }
524    
525                    Document document = getDocument(versioningFolder, versionLabel);
526    
527                    if (document == null) {
528                            throw new NoSuchFileException();
529                    }
530    
531                    return document;
532            }
533    
534            protected Folder getVersioningFolder(
535                    long companyId, long repositoryId, String fileName, boolean create) {
536    
537                    Folder repositoryFolder = getRepositoryFolder(companyId, repositoryId);
538    
539                    Folder versioningFolder = repositoryFolder;
540    
541                    String[] dirNames = StringUtil.split(fileName, CharPool.SLASH);
542    
543                    for (String dirName : dirNames) {
544                            Folder subFolder = getFolder(versioningFolder, dirName);
545    
546                            if (create && (subFolder == null)) {
547                                    subFolder = createFolder(versioningFolder, dirName);
548                            }
549    
550                            versioningFolder = subFolder;
551                    }
552    
553                    return versioningFolder;
554            }
555    
556            private static Folder _systemRootDir;
557    
558            private static class SessionHolder {
559    
560                    private final static Session session;
561    
562                    static {
563                            Map<String, String> parameters = new HashMap<String, String>();
564    
565                            parameters.put(
566                                    SessionParameter.ATOMPUB_URL,
567                                    PropsValues.DL_STORE_CMIS_REPOSITORY_URL);
568                            parameters.put(
569                                    SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
570                            parameters.put(
571                                    SessionParameter.COMPRESSION, Boolean.TRUE.toString());
572    
573                            Locale locale = LocaleUtil.getDefault();
574    
575                            parameters.put(
576                                    SessionParameter.LOCALE_ISO3166_COUNTRY, locale.getCountry());
577                            parameters.put(
578                                    SessionParameter.LOCALE_ISO639_LANGUAGE, locale.getLanguage());
579                            parameters.put(
580                                    SessionParameter.PASSWORD,
581                                    PropsValues.DL_STORE_CMIS_CREDENTIALS_PASSWORD);
582                            parameters.put(
583                                    SessionParameter.USER,
584                                    PropsValues.DL_STORE_CMIS_CREDENTIALS_USERNAME);
585    
586                            SessionFactory sessionFactory =
587                                    CMISRepositoryUtil.getSessionFactory();
588    
589                            List<Repository> repositories = sessionFactory.getRepositories(
590                                    parameters);
591    
592                            Repository repository = repositories.get(0);
593    
594                            session = repository.createSession();
595    
596                            session.setDefaultContext(CMISRepositoryUtil.getOperationContext());
597                    }
598    
599            }
600    
601    }