001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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                    if (fromVersionLabel.equals(toVersionLabel)) {
111                            throw new DuplicateFileException(
112                                    String.format(
113                                            "{companyId=%s, fileName=%s, repositoryId=%s, version=%s}",
114                                            companyId, fileName, repositoryId, toVersionLabel));
115                    }
116    
117                    Folder versioningFolder = getVersioningFolder(
118                            companyId, repositoryId, fileName, false);
119    
120                    ObjectId versioningFolderObjectId = new ObjectIdImpl(
121                            versioningFolder.getId());
122    
123                    Map<String, Object> documentProperties = new HashMap<String, Object>();
124    
125                    String title = String.valueOf(toVersionLabel);
126    
127                    documentProperties.put(PropertyIds.NAME, title);
128    
129                    documentProperties.put(
130                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_DOCUMENT.value());
131    
132                    Document document = getVersionedDocument(
133                            companyId, repositoryId, fileName, fromVersionLabel);
134    
135                    document.copy(
136                            versioningFolderObjectId, documentProperties, null,
137                            document.getPolicies(), null, null, null);
138            }
139    
140            @Override
141            public void deleteDirectory(
142                    long companyId, long repositoryId, String dirName) {
143    
144                    Folder repositoryFolder = getRepositoryFolder(companyId, repositoryId);
145    
146                    Folder directory = getFolder(repositoryFolder, dirName);
147    
148                    if (directory != null) {
149                            directory.deleteTree(true, UnfileObject.DELETE, false);
150                    }
151            }
152    
153            @Override
154            public void deleteFile(long companyId, long repositoryId, String fileName)
155                    throws PortalException {
156    
157                    Folder versioningFolder = getVersioningFolder(
158                            companyId, repositoryId, fileName, false);
159    
160                    if (versioningFolder == null) {
161                            throw new NoSuchFileException();
162                    }
163    
164                    versioningFolder.deleteTree(true, UnfileObject.DELETE, false);
165            }
166    
167            @Override
168            public void deleteFile(
169                            long companyId, long repositoryId, String fileName,
170                            String versionLabel)
171                    throws PortalException {
172    
173                    Document document = getVersionedDocument(
174                            companyId, repositoryId, fileName, versionLabel);
175    
176                    document.delete(true);
177            }
178    
179            @Override
180            public InputStream getFileAsStream(
181                            long companyId, long repositoryId, String fileName,
182                            String versionLabel)
183                    throws PortalException {
184    
185                    if (Validator.isNull(versionLabel)) {
186                            versionLabel = getHeadVersionLabel(
187                                    companyId, repositoryId, fileName);
188                    }
189    
190                    Document document = getVersionedDocument(
191                            companyId, repositoryId, fileName, versionLabel);
192    
193                    return document.getContentStream().getStream();
194            }
195    
196            @Override
197            public String[] getFileNames(long companyId, long repositoryId) {
198                    Folder folder = getRepositoryFolder(companyId, repositoryId);
199    
200                    List<Folder> folders = getFolders(folder);
201    
202                    String[] fileNames = new String[folders.size()];
203    
204                    for (int i = 0; i < folders.size(); i++) {
205                            Folder curFolder = folders.get(i);
206    
207                            fileNames[i] = curFolder.getName();
208                    }
209    
210                    return fileNames;
211            }
212    
213            @Override
214            public String[] getFileNames(
215                    long companyId, long repositoryId, String dirName) {
216    
217                    Folder folder = getRepositoryFolder(companyId, repositoryId);
218    
219                    String[] dirNames = StringUtil.split(dirName, CharPool.SLASH);
220    
221                    for (String curDirName : dirNames) {
222                            Folder subFolder = getFolder(folder, curDirName);
223    
224                            if (subFolder == null) {
225                                    subFolder = createFolder(folder, curDirName);
226                            }
227    
228                            folder = subFolder;
229                    }
230    
231                    List<Folder> folders = getFolders(folder);
232    
233                    String[] fileNames = new String[folders.size()];
234    
235                    for (int i = 0; i < folders.size(); i++) {
236                            Folder curFolder = folders.get(i);
237    
238                            String fileName = curFolder.getName();
239    
240                            fileNames[i] = dirName.concat(StringPool.SLASH).concat(fileName);
241                    }
242    
243                    return fileNames;
244            }
245    
246            @Override
247            public long getFileSize(long companyId, long repositoryId, String fileName)
248                    throws PortalException {
249    
250                    String versionLabel = getHeadVersionLabel(
251                            companyId, repositoryId, fileName);
252    
253                    Document document = getVersionedDocument(
254                            companyId, repositoryId, fileName, versionLabel);
255    
256                    return document.getContentStreamLength();
257            }
258    
259            public String getHeadVersionLabel(
260                            long companyId, long repositoryId, String dirName)
261                    throws NoSuchFileException {
262    
263                    Folder versioningFolder = getVersioningFolder(
264                            companyId, repositoryId, dirName, false);
265    
266                    if (versioningFolder == null) {
267                            throw new NoSuchFileException();
268                    }
269    
270                    List<Folder> folders = getFolders(versioningFolder);
271    
272                    String headVersionLabel = VERSION_DEFAULT;
273    
274                    for (Folder folder : folders) {
275                            String versionLabel = folder.getName();
276    
277                            if (DLUtil.compareVersions(versionLabel, headVersionLabel) > 0) {
278                                    headVersionLabel = versionLabel;
279                            }
280                    }
281    
282                    return headVersionLabel;
283            }
284    
285            @Override
286            public boolean hasDirectory(
287                    long companyId, long repositoryId, String dirName) {
288    
289                    Folder folder = getRepositoryFolder(companyId, repositoryId);
290    
291                    String[] dirNames = StringUtil.split(dirName, CharPool.SLASH);
292    
293                    for (String subdirName : dirNames) {
294                            Folder subfolder = getFolder(folder, subdirName);
295    
296                            if (subfolder == null) {
297                                    return false;
298                            }
299                    }
300    
301                    return true;
302            }
303    
304            @Override
305            public boolean hasFile(
306                    long companyId, long repositoryId, String fileName,
307                    String versionLabel) {
308    
309                    Folder versioningFolder = getVersioningFolder(
310                            companyId, repositoryId, fileName, true);
311    
312                    Document document = getDocument(versioningFolder, versionLabel);
313    
314                    if (document == null) {
315                            return false;
316                    }
317                    else {
318                            return true;
319                    }
320            }
321    
322            @Override
323            public void move(String srcDir, String destDir) {
324            }
325    
326            @Override
327            public void updateFile(
328                            long companyId, long repositoryId, long newRepositoryId,
329                            String fileName)
330                    throws PortalException {
331    
332                    if (repositoryId == newRepositoryId) {
333                            throw new DuplicateFileException(
334                                    String.format(
335                                            "{companyId=%s, fileName=%s, repositoryId=%s}", companyId,
336                                            fileName, repositoryId));
337                    }
338    
339                    Folder oldVersioningFolderEntry = getVersioningFolder(
340                            companyId, repositoryId, fileName, true);
341                    Folder newVersioningFolderEntry = getVersioningFolder(
342                            companyId, newRepositoryId, fileName, true);
343    
344                    List<Folder> folders = getFolders(oldVersioningFolderEntry);
345    
346                    for (Folder folder : folders) {
347                            String curFileName = folder.getName();
348    
349                            Document document = getDocument(
350                                    oldVersioningFolderEntry, curFileName);
351    
352                            InputStream is = document.getContentStream().getStream();
353    
354                            createDocument(newVersioningFolderEntry, curFileName, is);
355                    }
356    
357                    oldVersioningFolderEntry.deleteTree(true, UnfileObject.DELETE, false);
358            }
359    
360            @Override
361            public void updateFile(
362                            long companyId, long repositoryId, String fileName,
363                            String newFileName)
364                    throws PortalException {
365    
366                    if (fileName.equals(newFileName)) {
367                            throw new DuplicateFileException(
368                                    String.format(
369                                            "{companyId=%s, fileName=%s, repositoryId=%s}", companyId,
370                                            fileName, repositoryId));
371                    }
372    
373                    Folder oldVersioningFolderEntry = getVersioningFolder(
374                            companyId, repositoryId, fileName, true);
375                    Folder newVersioningFolderEntry = getVersioningFolder(
376                            companyId, repositoryId, newFileName, true);
377    
378                    List<Folder> folders = getFolders(oldVersioningFolderEntry);
379    
380                    for (Folder folder : folders) {
381                            String curFileName = folder.getName();
382    
383                            Document document = getDocument(
384                                    oldVersioningFolderEntry, curFileName);
385    
386                            InputStream is = document.getContentStream().getStream();
387    
388                            createDocument(newVersioningFolderEntry, curFileName, is);
389                    }
390    
391                    oldVersioningFolderEntry.deleteTree(true, UnfileObject.DELETE, false);
392            }
393    
394            @Override
395            public void updateFile(
396                            long companyId, long repositoryId, String fileName,
397                            String versionLabel, InputStream is)
398                    throws PortalException {
399    
400                    Folder versioningFolder = getVersioningFolder(
401                            companyId, repositoryId, fileName, true);
402    
403                    String title = String.valueOf(versionLabel);
404    
405                    Document document = getDocument(versioningFolder, title);
406    
407                    if (document != null) {
408                            throw new DuplicateFileException();
409                    }
410    
411                    createDocument(versioningFolder, title, is);
412            }
413    
414            @Override
415            public void updateFileVersion(
416                            long companyId, long repositoryId, String fileName,
417                            String fromVersionLabel, String toVersionLabel)
418                    throws PortalException {
419    
420                    Folder versioningFolder = getVersioningFolder(
421                            companyId, repositoryId, fileName, false);
422    
423                    String title = String.valueOf(toVersionLabel);
424    
425                    Document document = getDocument(versioningFolder, title);
426    
427                    if (document != null) {
428                            throw new DuplicateFileException();
429                    }
430    
431                    document = getVersionedDocument(
432                            companyId, repositoryId, fileName, fromVersionLabel);
433    
434                    Map<String, Object> documentProperties = new HashMap<String, Object>();
435    
436                    documentProperties.put(PropertyIds.NAME, title);
437    
438                    document.updateProperties(documentProperties);
439            }
440    
441            protected Document createDocument(
442                    Folder versioningFolder, String title, InputStream is) {
443    
444                    Map<String, Object> documentProperties = new HashMap<String, Object>();
445    
446                    documentProperties.put(PropertyIds.NAME, title);
447                    documentProperties.put(
448                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_DOCUMENT.value());
449    
450                    ContentStream contentStream = new ContentStreamImpl(
451                            null, null, ContentTypes.APPLICATION_OCTET_STREAM, is);
452    
453                    return versioningFolder.createDocument(
454                            documentProperties, contentStream, null);
455            }
456    
457            protected Folder createFolder(ObjectId parentFolderId, String name) {
458                    Map<String, Object> properties = new HashMap<String, Object>();
459    
460                    properties.put(PropertyIds.NAME, name);
461                    properties.put(
462                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_FOLDER.value());
463    
464                    ObjectId objectId = SessionHolder.session.createFolder(
465                            properties, parentFolderId);
466    
467                    return (Folder)SessionHolder.session.getObject(objectId);
468            }
469    
470            protected Folder getCompanyFolder(long companyId) {
471                    String name = String.valueOf(companyId);
472    
473                    Folder companyFolder = getFolder(_systemRootDir, name);
474    
475                    if (companyFolder == null) {
476                            companyFolder = createFolder(_systemRootDir, name);
477                    }
478    
479                    return companyFolder;
480            }
481    
482            protected Document getDocument(Folder parentFolder, String name) {
483                    ItemIterable<CmisObject> cmisObjects = parentFolder.getChildren();
484    
485                    for (CmisObject cmisObject : cmisObjects) {
486                            if (name.equals(cmisObject.getName()) &&
487                                    cmisObject instanceof Document) {
488    
489                                    return (Document)cmisObject;
490                            }
491                    }
492    
493                    return null;
494            }
495    
496            protected Folder getFolder(Folder parentFolder, String name) {
497                    ItemIterable<CmisObject> cmisObjects = parentFolder.getChildren();
498    
499                    for (CmisObject cmisObject : cmisObjects) {
500                            if (name.equals(cmisObject.getName()) &&
501                                    cmisObject instanceof Folder) {
502    
503                                    return (Folder)cmisObject;
504                            }
505                    }
506    
507                    return null;
508            }
509    
510            protected List<Folder> getFolders(Folder folder) {
511                    List<Folder> folders = new ArrayList<Folder>();
512    
513                    ItemIterable<CmisObject> cmisObjects = folder.getChildren();
514    
515                    for (CmisObject cmisObject : cmisObjects) {
516                            if (cmisObject instanceof Folder) {
517                                    folders.add((Folder)cmisObject);
518                            }
519                    }
520    
521                    return folders;
522            }
523    
524            protected Folder getRepositoryFolder(long companyId, long repositoryId) {
525                    Folder companyFolder = getCompanyFolder(companyId);
526    
527                    String name = String.valueOf(repositoryId);
528    
529                    Folder repositoryFolder = getFolder(companyFolder, name);
530    
531                    if (repositoryFolder == null) {
532                            repositoryFolder = createFolder(companyFolder, name);
533                    }
534    
535                    return repositoryFolder;
536            }
537    
538            protected Document getVersionedDocument(
539                            long companyId, long repositoryId, String fileName,
540                            String versionLabel)
541                    throws NoSuchFileException {
542    
543                    Folder versioningFolder = getVersioningFolder(
544                            companyId, repositoryId, fileName, false);
545    
546                    if (versioningFolder == null) {
547                            throw new NoSuchFileException();
548                    }
549    
550                    Document document = getDocument(versioningFolder, versionLabel);
551    
552                    if (document == null) {
553                            throw new NoSuchFileException();
554                    }
555    
556                    return document;
557            }
558    
559            protected Folder getVersioningFolder(
560                    long companyId, long repositoryId, String fileName, boolean create) {
561    
562                    Folder repositoryFolder = getRepositoryFolder(companyId, repositoryId);
563    
564                    Folder versioningFolder = repositoryFolder;
565    
566                    String[] dirNames = StringUtil.split(fileName, CharPool.SLASH);
567    
568                    for (String dirName : dirNames) {
569                            Folder subFolder = getFolder(versioningFolder, dirName);
570    
571                            if (create && (subFolder == null)) {
572                                    subFolder = createFolder(versioningFolder, dirName);
573                            }
574    
575                            versioningFolder = subFolder;
576                    }
577    
578                    return versioningFolder;
579            }
580    
581            private static Folder _systemRootDir;
582    
583            private static class SessionHolder {
584    
585                    private final static Session session;
586    
587                    static {
588                            Map<String, String> parameters = new HashMap<String, String>();
589    
590                            parameters.put(
591                                    SessionParameter.ATOMPUB_URL,
592                                    PropsValues.DL_STORE_CMIS_REPOSITORY_URL);
593                            parameters.put(
594                                    SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
595                            parameters.put(
596                                    SessionParameter.COMPRESSION, Boolean.TRUE.toString());
597    
598                            Locale locale = LocaleUtil.getDefault();
599    
600                            parameters.put(
601                                    SessionParameter.LOCALE_ISO3166_COUNTRY, locale.getCountry());
602                            parameters.put(
603                                    SessionParameter.LOCALE_ISO639_LANGUAGE, locale.getLanguage());
604                            parameters.put(
605                                    SessionParameter.PASSWORD,
606                                    PropsValues.DL_STORE_CMIS_CREDENTIALS_PASSWORD);
607                            parameters.put(
608                                    SessionParameter.USER,
609                                    PropsValues.DL_STORE_CMIS_CREDENTIALS_USERNAME);
610    
611                            SessionFactory sessionFactory =
612                                    CMISRepositoryUtil.getSessionFactory();
613    
614                            List<Repository> repositories = sessionFactory.getRepositories(
615                                    parameters);
616    
617                            Repository repository = repositories.get(0);
618    
619                            session = repository.createSession();
620    
621                            session.setDefaultContext(CMISRepositoryUtil.getOperationContext());
622                    }
623    
624            }
625    
626    }