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.Iterator;
035    import java.util.List;
036    import java.util.Locale;
037    import java.util.Map;
038    
039    import org.apache.chemistry.opencmis.client.api.CmisObject;
040    import org.apache.chemistry.opencmis.client.api.Document;
041    import org.apache.chemistry.opencmis.client.api.Folder;
042    import org.apache.chemistry.opencmis.client.api.ItemIterable;
043    import org.apache.chemistry.opencmis.client.api.ObjectId;
044    import org.apache.chemistry.opencmis.client.api.Repository;
045    import org.apache.chemistry.opencmis.client.api.Session;
046    import org.apache.chemistry.opencmis.client.api.SessionFactory;
047    import org.apache.chemistry.opencmis.client.runtime.ObjectIdImpl;
048    import org.apache.chemistry.opencmis.commons.PropertyIds;
049    import org.apache.chemistry.opencmis.commons.SessionParameter;
050    import org.apache.chemistry.opencmis.commons.data.ContentStream;
051    import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
052    import org.apache.chemistry.opencmis.commons.enums.BindingType;
053    import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
054    import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
055    
056    /**
057     * @author Alexander Chow
058     * @author Edward Han
059     */
060    public class CMISStore extends BaseStore {
061    
062            public CMISStore() {
063                    _systemRootDir = getFolder(
064                            SessionHolder.session.getRootFolder(),
065                            PropsValues.DL_STORE_CMIS_SYSTEM_ROOT_DIR);
066    
067                    if (_systemRootDir == null) {
068                            _systemRootDir = createFolder(
069                                    SessionHolder.session.getRootFolder(),
070                                    PropsValues.DL_STORE_CMIS_SYSTEM_ROOT_DIR);
071                    }
072            }
073    
074            @Override
075            public void addDirectory(
076                    long companyId, long repositoryId, String dirName) {
077    
078                    Folder folder = getRepositoryFolder(companyId, repositoryId);
079    
080                    String[] dirNames = StringUtil.split(dirName, CharPool.SLASH);
081    
082                    for (String curDirName : dirNames) {
083                            Folder subFolder = getFolder(folder, curDirName);
084    
085                            if (subFolder == null) {
086                                    subFolder = createFolder(folder, curDirName);
087                            }
088    
089                            folder = subFolder;
090                    }
091            }
092    
093            @Override
094            public void addFile(
095                            long companyId, long repositoryId, String fileName, InputStream is)
096                    throws PortalException {
097    
098                    updateFile(companyId, repositoryId, fileName, VERSION_DEFAULT, is);
099            }
100    
101            @Override
102            public void checkRoot(long companyId) {
103            }
104    
105            @Override
106            public void copyFileVersion(
107                            long companyId, long repositoryId, String fileName,
108                            String fromVersionLabel, String toVersionLabel)
109                    throws PortalException {
110    
111                    Folder versioningFolder = getVersioningFolder(
112                            companyId, repositoryId, fileName, false);
113    
114                    ObjectId versioningFolderObjectId = new ObjectIdImpl(
115                            versioningFolder.getId());
116    
117                    Map<String, Object> documentProperties = new HashMap<String, Object>();
118    
119                    String title = String.valueOf(toVersionLabel);
120    
121                    documentProperties.put(PropertyIds.NAME, title);
122    
123                    documentProperties.put(
124                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_DOCUMENT.value());
125    
126                    Document document = getVersionedDocument(
127                            companyId, repositoryId, fileName, fromVersionLabel);
128    
129                    document.copy(
130                            versioningFolderObjectId, documentProperties, null,
131                            document.getPolicies(), null, null, null);
132            }
133    
134            @Override
135            public void deleteDirectory(
136                    long companyId, long repositoryId, String dirName) {
137    
138                    Folder repositoryFolder = getRepositoryFolder(companyId, repositoryId);
139    
140                    Folder directory = getFolder(repositoryFolder, dirName);
141    
142                    if (directory != null) {
143                            directory.deleteTree(true, UnfileObject.DELETE, false);
144                    }
145            }
146    
147            @Override
148            public void deleteFile(long companyId, long repositoryId, String fileName)
149                    throws PortalException {
150    
151                    Folder versioningFolder = getVersioningFolder(
152                            companyId, repositoryId, fileName, false);
153    
154                    if (versioningFolder == null) {
155                            throw new NoSuchFileException();
156                    }
157    
158                    versioningFolder.deleteTree(true, UnfileObject.DELETE, false);
159            }
160    
161            @Override
162            public void deleteFile(
163                            long companyId, long repositoryId, String fileName,
164                            String versionLabel)
165                    throws PortalException {
166    
167                    Document document = getVersionedDocument(
168                            companyId, repositoryId, fileName, versionLabel);
169    
170                    document.delete(true);
171            }
172    
173            @Override
174            public InputStream getFileAsStream(
175                            long companyId, long repositoryId, String fileName,
176                            String versionLabel)
177                    throws PortalException {
178    
179                    if (Validator.isNull(versionLabel)) {
180                            versionLabel = getHeadVersionLabel(
181                                    companyId, repositoryId, fileName);
182                    }
183    
184                    Document document = getVersionedDocument(
185                            companyId, repositoryId, fileName, versionLabel);
186    
187                    return document.getContentStream().getStream();
188            }
189    
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            public void updateFile(
346                    long companyId, long repositoryId, String fileName,
347                    String newFileName) {
348    
349                    Folder oldVersioningFolderEntry = getVersioningFolder(
350                            companyId, repositoryId, fileName, true);
351                    Folder newVersioningFolderEntry = getVersioningFolder(
352                            companyId, repositoryId, newFileName, true);
353    
354                    List<Folder> folders = getFolders(oldVersioningFolderEntry);
355    
356                    for (Folder folder : folders) {
357                            String curFileName = folder.getName();
358    
359                            Document document = getDocument(
360                                    oldVersioningFolderEntry, curFileName);
361    
362                            InputStream is = document.getContentStream().getStream();
363    
364                            createDocument(newVersioningFolderEntry, curFileName, is);
365                    }
366    
367                    oldVersioningFolderEntry.deleteTree(true, UnfileObject.DELETE, false);
368            }
369    
370            @Override
371            public void updateFile(
372                            long companyId, long repositoryId, String fileName,
373                            String versionLabel, InputStream is)
374                    throws PortalException {
375    
376                    Folder versioningFolder = getVersioningFolder(
377                            companyId, repositoryId, fileName, true);
378    
379                    String title = String.valueOf(versionLabel);
380    
381                    Document document = getDocument(versioningFolder, title);
382    
383                    if (document != null) {
384                            throw new DuplicateFileException();
385                    }
386    
387                    createDocument(versioningFolder, title, is);
388            }
389    
390            @Override
391            public void updateFileVersion(
392                            long companyId, long repositoryId, String fileName,
393                            String fromVersionLabel, String toVersionLabel)
394                    throws PortalException {
395    
396                    Folder versioningFolder = getVersioningFolder(
397                            companyId, repositoryId, fileName, false);
398    
399                    String title = String.valueOf(toVersionLabel);
400    
401                    Document document = getDocument(versioningFolder, title);
402    
403                    if (document != null) {
404                            throw new DuplicateFileException();
405                    }
406    
407                    document = getVersionedDocument(
408                            companyId, repositoryId, fileName, fromVersionLabel);
409    
410                    Map<String, Object> documentProperties = new HashMap<String, Object>();
411    
412                    documentProperties.put(PropertyIds.NAME, title);
413    
414                    document.updateProperties(documentProperties);
415            }
416    
417            protected Document createDocument(
418                    Folder versioningFolder, String title, InputStream is) {
419    
420                    Map<String, Object> documentProperties = new HashMap<String, Object>();
421    
422                    documentProperties.put(PropertyIds.NAME, title);
423                    documentProperties.put(
424                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_DOCUMENT.value());
425    
426                    ContentStream contentStream = new ContentStreamImpl(
427                            null, null, ContentTypes.APPLICATION_OCTET_STREAM, is);
428    
429                    return versioningFolder.createDocument(
430                            documentProperties, contentStream, null);
431            }
432    
433            protected Folder createFolder(ObjectId parentFolderId, String name) {
434                    Map<String, Object> properties = new HashMap<String, Object>();
435    
436                    properties.put(PropertyIds.NAME, name);
437                    properties.put(
438                            PropertyIds.OBJECT_TYPE_ID, BaseTypeId.CMIS_FOLDER.value());
439    
440                    ObjectId objectId = SessionHolder.session.createFolder(
441                            properties, parentFolderId);
442    
443                    return (Folder)SessionHolder.session.getObject(objectId);
444            }
445    
446            protected Folder getCompanyFolder(long companyId) {
447                    String name = String.valueOf(companyId);
448    
449                    Folder companyFolder = getFolder(_systemRootDir, name);
450    
451                    if (companyFolder == null) {
452                            companyFolder = createFolder(_systemRootDir, name);
453                    }
454    
455                    return companyFolder;
456            }
457    
458            protected Document getDocument(Folder parentFolder, String name) {
459                    ItemIterable<CmisObject> cmisObjects = parentFolder.getChildren();
460    
461                    Iterator<CmisObject> itr = cmisObjects.iterator();
462    
463                    while (itr.hasNext()) {
464                            CmisObject cmisObject = itr.next();
465    
466                            if (name.equals(cmisObject.getName()) &&
467                                    cmisObject instanceof Document) {
468    
469                                    return (Document)cmisObject;
470                            }
471                    }
472    
473                    return null;
474            }
475    
476            protected Folder getFolder(Folder parentFolder, String name) {
477                    ItemIterable<CmisObject> cmisObjects = parentFolder.getChildren();
478    
479                    Iterator<CmisObject> itr = cmisObjects.iterator();
480    
481                    while (itr.hasNext()) {
482                            CmisObject cmisObject = itr.next();
483    
484                            if (name.equals(cmisObject.getName()) &&
485                                    cmisObject instanceof Folder) {
486    
487                                    return (Folder)cmisObject;
488                            }
489                    }
490    
491                    return null;
492            }
493    
494            protected List<Folder> getFolders(Folder folder) {
495                    List<Folder> folders = new ArrayList<Folder>();
496    
497                    ItemIterable<CmisObject> cmisObjects = folder.getChildren();
498    
499                    Iterator<CmisObject> itr = cmisObjects.iterator();
500    
501                    while (itr.hasNext()) {
502                            CmisObject cmisObject = itr.next();
503    
504                            if (cmisObject instanceof Folder) {
505                                    folders.add((Folder)cmisObject);
506                            }
507                    }
508    
509                    return folders;
510            }
511    
512            protected Folder getRepositoryFolder(long companyId, long repositoryId) {
513                    Folder companyFolder = getCompanyFolder(companyId);
514    
515                    String name = String.valueOf(repositoryId);
516    
517                    Folder repositoryFolder = getFolder(companyFolder, name);
518    
519                    if (repositoryFolder == null) {
520                            repositoryFolder = createFolder(companyFolder, name);
521                    }
522    
523                    return repositoryFolder;
524            }
525    
526            protected Document getVersionedDocument(
527                            long companyId, long repositoryId, String fileName,
528                            String versionLabel)
529                    throws NoSuchFileException {
530    
531                    Folder versioningFolder = getVersioningFolder(
532                            companyId, repositoryId, fileName, false);
533    
534                    if (versioningFolder == null) {
535                            throw new NoSuchFileException();
536                    }
537    
538                    Document document = getDocument(versioningFolder, versionLabel);
539    
540                    if (document == null) {
541                            throw new NoSuchFileException();
542                    }
543    
544                    return document;
545            }
546    
547            protected Folder getVersioningFolder(
548                    long companyId, long repositoryId, String fileName, boolean create) {
549    
550                    Folder repositoryFolder = getRepositoryFolder(companyId, repositoryId);
551    
552                    Folder versioningFolder = repositoryFolder;
553    
554                    String[] dirNames = StringUtil.split(fileName, CharPool.SLASH);
555    
556                    for (String dirName : dirNames) {
557                            Folder subFolder = getFolder(versioningFolder, dirName);
558    
559                            if (create && (subFolder == null)) {
560                                    subFolder = createFolder(versioningFolder, dirName);
561                            }
562    
563                            versioningFolder = subFolder;
564                    }
565    
566                    return versioningFolder;
567            }
568    
569            private static Folder _systemRootDir;
570    
571            private static class SessionHolder {
572    
573                    private final static Session session;
574    
575                    static {
576                            Map<String, String> parameters = new HashMap<String, String>();
577    
578                            parameters.put(
579                                    SessionParameter.ATOMPUB_URL,
580                                    PropsValues.DL_STORE_CMIS_REPOSITORY_URL);
581                            parameters.put(
582                                    SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
583                            parameters.put(
584                                    SessionParameter.COMPRESSION, Boolean.TRUE.toString());
585    
586                            Locale locale = LocaleUtil.getDefault();
587    
588                            parameters.put(
589                                    SessionParameter.LOCALE_ISO3166_COUNTRY, locale.getCountry());
590                            parameters.put(
591                                    SessionParameter.LOCALE_ISO639_LANGUAGE, locale.getLanguage());
592                            parameters.put(
593                                    SessionParameter.PASSWORD,
594                                    PropsValues.DL_STORE_CMIS_CREDENTIALS_PASSWORD);
595                            parameters.put(
596                                    SessionParameter.USER,
597                                    PropsValues.DL_STORE_CMIS_CREDENTIALS_USERNAME);
598    
599                            SessionFactory sessionFactory =
600                                    CMISRepositoryUtil.getSessionFactory();
601    
602                            List<Repository> repositories = sessionFactory.getRepositories(
603                                    parameters);
604    
605                            Repository repository = repositories.get(0);
606    
607                            session = repository.createSession();
608    
609                            session.setDefaultContext(CMISRepositoryUtil.getOperationContext());
610                    }
611    
612            }
613    
614    }