001    /**
002     * Copyright (c) 2000-2013 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            @Override
190            public String[] getFileNames(long companyId, long repositoryId) {
191                    Folder folder = getRepositoryFolder(companyId, repositoryId);
192    
193                    List<Folder> folders = getFolders(folder);
194    
195                    String[] fileNames = new String[folders.size()];
196    
197                    for (int i = 0; i < folders.size(); i++) {
198                            Folder curFolder = folders.get(i);
199    
200                            fileNames[i] = curFolder.getName();
201                    }
202    
203                    return fileNames;
204            }
205    
206            @Override
207            public String[] getFileNames(
208                    long companyId, long repositoryId, String dirName) {
209    
210                    Folder folder = getRepositoryFolder(companyId, repositoryId);
211    
212                    String[] dirNames = StringUtil.split(dirName, CharPool.SLASH);
213    
214                    for (String curDirName : dirNames) {
215                            Folder subFolder = getFolder(folder, curDirName);
216    
217                            if (subFolder == null) {
218                                    subFolder = createFolder(folder, curDirName);
219                            }
220    
221                            folder = subFolder;
222                    }
223    
224                    List<Folder> folders = getFolders(folder);
225    
226                    String[] fileNames = new String[folders.size()];
227    
228                    for (int i = 0; i < folders.size(); i++) {
229                            Folder curFolder = folders.get(i);
230    
231                            String fileName = curFolder.getName();
232    
233                            fileNames[i] = dirName.concat(StringPool.SLASH).concat(fileName);
234                    }
235    
236                    return fileNames;
237            }
238    
239            @Override
240            public long getFileSize(long companyId, long repositoryId, String fileName)
241                    throws PortalException {
242    
243                    String versionLabel = getHeadVersionLabel(
244                            companyId, repositoryId, fileName);
245    
246                    Document document = getVersionedDocument(
247                            companyId, repositoryId, fileName, versionLabel);
248    
249                    return document.getContentStreamLength();
250            }
251    
252            public String getHeadVersionLabel(
253                            long companyId, long repositoryId, String dirName)
254                    throws NoSuchFileException {
255    
256                    Folder versioningFolder = getVersioningFolder(
257                            companyId, repositoryId, dirName, false);
258    
259                    if (versioningFolder == null) {
260                            throw new NoSuchFileException();
261                    }
262    
263                    List<Folder> folders = getFolders(versioningFolder);
264    
265                    String headVersionLabel = VERSION_DEFAULT;
266    
267                    for (Folder folder : folders) {
268                            String versionLabel = folder.getName();
269    
270                            if (DLUtil.compareVersions(versionLabel, headVersionLabel) > 0) {
271                                    headVersionLabel = versionLabel;
272                            }
273                    }
274    
275                    return headVersionLabel;
276            }
277    
278            @Override
279            public boolean hasDirectory(
280                    long companyId, long repositoryId, String dirName) {
281    
282                    Folder folder = getRepositoryFolder(companyId, repositoryId);
283    
284                    String[] dirNames = StringUtil.split(dirName, CharPool.SLASH);
285    
286                    for (String subdirName : dirNames) {
287                            Folder subfolder = getFolder(folder, subdirName);
288    
289                            if (subfolder == null) {
290                                    return false;
291                            }
292                    }
293    
294                    return true;
295            }
296    
297            @Override
298            public boolean hasFile(
299                    long companyId, long repositoryId, String fileName,
300                    String versionLabel) {
301    
302                    Folder versioningFolder = getVersioningFolder(
303                            companyId, repositoryId, fileName, true);
304    
305                    Document document = getDocument(versioningFolder, versionLabel);
306    
307                    if (document == null) {
308                            return false;
309                    }
310                    else {
311                            return true;
312                    }
313            }
314    
315            @Override
316            public void move(String srcDir, String destDir) {
317            }
318    
319            @Override
320            public void updateFile(
321                    long companyId, long repositoryId, long newRepositoryId,
322                    String fileName) {
323    
324                    Folder oldVersioningFolderEntry = getVersioningFolder(
325                            companyId, repositoryId, fileName, true);
326                    Folder newVersioningFolderEntry = getVersioningFolder(
327                            companyId, newRepositoryId, fileName, true);
328    
329                    List<Folder> folders = getFolders(oldVersioningFolderEntry);
330    
331                    for (Folder folder : folders) {
332                            String curFileName = folder.getName();
333    
334                            Document document = getDocument(
335                                    oldVersioningFolderEntry, curFileName);
336    
337                            InputStream is = document.getContentStream().getStream();
338    
339                            createDocument(newVersioningFolderEntry, curFileName, is);
340                    }
341    
342                    oldVersioningFolderEntry.deleteTree(true, UnfileObject.DELETE, false);
343            }
344    
345            @Override
346            public void updateFile(
347                    long companyId, long repositoryId, String fileName,
348                    String newFileName) {
349    
350                    Folder oldVersioningFolderEntry = getVersioningFolder(
351                            companyId, repositoryId, fileName, true);
352                    Folder newVersioningFolderEntry = getVersioningFolder(
353                            companyId, repositoryId, newFileName, true);
354    
355                    List<Folder> folders = getFolders(oldVersioningFolderEntry);
356    
357                    for (Folder folder : folders) {
358                            String curFileName = folder.getName();
359    
360                            Document document = getDocument(
361                                    oldVersioningFolderEntry, curFileName);
362    
363                            InputStream is = document.getContentStream().getStream();
364    
365                            createDocument(newVersioningFolderEntry, curFileName, is);
366                    }
367    
368                    oldVersioningFolderEntry.deleteTree(true, UnfileObject.DELETE, false);
369            }
370    
371            @Override
372            public void updateFile(
373                            long companyId, long repositoryId, String fileName,
374                            String versionLabel, InputStream is)
375                    throws PortalException {
376    
377                    Folder versioningFolder = getVersioningFolder(
378                            companyId, repositoryId, fileName, true);
379    
380                    String title = String.valueOf(versionLabel);
381    
382                    Document document = getDocument(versioningFolder, title);
383    
384                    if (document != null) {
385                            throw new DuplicateFileException();
386                    }
387    
388                    createDocument(versioningFolder, title, is);
389            }
390    
391            @Override
392            public void updateFileVersion(
393                            long companyId, long repositoryId, String fileName,
394                            String fromVersionLabel, String toVersionLabel)
395                    throws PortalException {
396    
397                    Folder versioningFolder = getVersioningFolder(
398                            companyId, repositoryId, fileName, false);
399    
400                    String title = String.valueOf(toVersionLabel);
401    
402                    Document document = getDocument(versioningFolder, title);
403    
404                    if (document != null) {
405                            throw new DuplicateFileException();
406                    }
407    
408                    document = getVersionedDocument(
409                            companyId, repositoryId, fileName, fromVersionLabel);
410    
411                    Map<String, Object> documentProperties = new HashMap<String, Object>();
412    
413                    documentProperties.put(PropertyIds.NAME, title);
414    
415                    document.updateProperties(documentProperties);
416            }
417    
418            protected Document createDocument(
419                    Folder versioningFolder, String title, InputStream is) {
420    
421                    Map<String, Object> documentProperties = new HashMap<String, Object>();
422    
423                    documentProperties.put(PropertyIds.NAME, title);
424                    documentProperties.put(
425                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_DOCUMENT.value());
426    
427                    ContentStream contentStream = new ContentStreamImpl(
428                            null, null, ContentTypes.APPLICATION_OCTET_STREAM, is);
429    
430                    return versioningFolder.createDocument(
431                            documentProperties, contentStream, null);
432            }
433    
434            protected Folder createFolder(ObjectId parentFolderId, String name) {
435                    Map<String, Object> properties = new HashMap<String, Object>();
436    
437                    properties.put(PropertyIds.NAME, name);
438                    properties.put(
439                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_FOLDER.value());
440    
441                    ObjectId objectId = SessionHolder.session.createFolder(
442                            properties, parentFolderId);
443    
444                    return (Folder)SessionHolder.session.getObject(objectId);
445            }
446    
447            protected Folder getCompanyFolder(long companyId) {
448                    String name = String.valueOf(companyId);
449    
450                    Folder companyFolder = getFolder(_systemRootDir, name);
451    
452                    if (companyFolder == null) {
453                            companyFolder = createFolder(_systemRootDir, name);
454                    }
455    
456                    return companyFolder;
457            }
458    
459            protected Document getDocument(Folder parentFolder, String name) {
460                    ItemIterable<CmisObject> cmisObjects = parentFolder.getChildren();
461    
462                    for (CmisObject cmisObject : cmisObjects) {
463                            if (name.equals(cmisObject.getName()) &&
464                                    cmisObject instanceof Document) {
465    
466                                    return (Document)cmisObject;
467                            }
468                    }
469    
470                    return null;
471            }
472    
473            protected Folder getFolder(Folder parentFolder, String name) {
474                    ItemIterable<CmisObject> cmisObjects = parentFolder.getChildren();
475    
476                    for (CmisObject cmisObject : cmisObjects) {
477                            if (name.equals(cmisObject.getName()) &&
478                                    cmisObject instanceof Folder) {
479    
480                                    return (Folder)cmisObject;
481                            }
482                    }
483    
484                    return null;
485            }
486    
487            protected List<Folder> getFolders(Folder folder) {
488                    List<Folder> folders = new ArrayList<Folder>();
489    
490                    ItemIterable<CmisObject> cmisObjects = folder.getChildren();
491    
492                    for (CmisObject cmisObject : cmisObjects) {
493                            if (cmisObject instanceof Folder) {
494                                    folders.add((Folder)cmisObject);
495                            }
496                    }
497    
498                    return folders;
499            }
500    
501            protected Folder getRepositoryFolder(long companyId, long repositoryId) {
502                    Folder companyFolder = getCompanyFolder(companyId);
503    
504                    String name = String.valueOf(repositoryId);
505    
506                    Folder repositoryFolder = getFolder(companyFolder, name);
507    
508                    if (repositoryFolder == null) {
509                            repositoryFolder = createFolder(companyFolder, name);
510                    }
511    
512                    return repositoryFolder;
513            }
514    
515            protected Document getVersionedDocument(
516                            long companyId, long repositoryId, String fileName,
517                            String versionLabel)
518                    throws NoSuchFileException {
519    
520                    Folder versioningFolder = getVersioningFolder(
521                            companyId, repositoryId, fileName, false);
522    
523                    if (versioningFolder == null) {
524                            throw new NoSuchFileException();
525                    }
526    
527                    Document document = getDocument(versioningFolder, versionLabel);
528    
529                    if (document == null) {
530                            throw new NoSuchFileException();
531                    }
532    
533                    return document;
534            }
535    
536            protected Folder getVersioningFolder(
537                    long companyId, long repositoryId, String fileName, boolean create) {
538    
539                    Folder repositoryFolder = getRepositoryFolder(companyId, repositoryId);
540    
541                    Folder versioningFolder = repositoryFolder;
542    
543                    String[] dirNames = StringUtil.split(fileName, CharPool.SLASH);
544    
545                    for (String dirName : dirNames) {
546                            Folder subFolder = getFolder(versioningFolder, dirName);
547    
548                            if (create && (subFolder == null)) {
549                                    subFolder = createFolder(versioningFolder, dirName);
550                            }
551    
552                            versioningFolder = subFolder;
553                    }
554    
555                    return versioningFolder;
556            }
557    
558            private static Folder _systemRootDir;
559    
560            private static class SessionHolder {
561    
562                    private final static Session session;
563    
564                    static {
565                            Map<String, String> parameters = new HashMap<String, String>();
566    
567                            parameters.put(
568                                    SessionParameter.ATOMPUB_URL,
569                                    PropsValues.DL_STORE_CMIS_REPOSITORY_URL);
570                            parameters.put(
571                                    SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
572                            parameters.put(
573                                    SessionParameter.COMPRESSION, Boolean.TRUE.toString());
574    
575                            Locale locale = LocaleUtil.getDefault();
576    
577                            parameters.put(
578                                    SessionParameter.LOCALE_ISO3166_COUNTRY, locale.getCountry());
579                            parameters.put(
580                                    SessionParameter.LOCALE_ISO639_LANGUAGE, locale.getLanguage());
581                            parameters.put(
582                                    SessionParameter.PASSWORD,
583                                    PropsValues.DL_STORE_CMIS_CREDENTIALS_PASSWORD);
584                            parameters.put(
585                                    SessionParameter.USER,
586                                    PropsValues.DL_STORE_CMIS_CREDENTIALS_USERNAME);
587    
588                            SessionFactory sessionFactory =
589                                    CMISRepositoryUtil.getSessionFactory();
590    
591                            List<Repository> repositories = sessionFactory.getRepositories(
592                                    parameters);
593    
594                            Repository repository = repositories.get(0);
595    
596                            session = repository.createSession();
597    
598                            session.setDefaultContext(CMISRepositoryUtil.getOperationContext());
599                    }
600    
601            }
602    
603    }