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