001/*
002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Vladimir Pasquier <vpasquier@nuxeo.com>
018 */
019package org.nuxeo.box.api.adapter;
020
021import org.nuxeo.box.api.marshalling.dao.BoxCollection;
022import org.nuxeo.box.api.marshalling.dao.BoxFile;
023import org.nuxeo.box.api.marshalling.dao.BoxFolder;
024import org.nuxeo.box.api.marshalling.dao.BoxItem;
025import org.nuxeo.box.api.marshalling.dao.BoxTypedObject;
026import org.nuxeo.box.api.marshalling.dao.BoxUser;
027import org.nuxeo.box.api.marshalling.exceptions.BoxJSONException;
028import org.nuxeo.box.api.service.BoxService;
029import org.joda.time.DateTime;
030import org.joda.time.format.ISODateTimeFormat;
031import org.nuxeo.ecm.core.api.CoreSession;
032import org.nuxeo.ecm.core.api.DocumentModel;
033import org.nuxeo.ecm.core.api.IdRef;
034import org.nuxeo.ecm.core.api.NuxeoPrincipal;
035import org.nuxeo.ecm.platform.tag.Tag;
036import org.nuxeo.ecm.platform.tag.TagService;
037import org.nuxeo.ecm.platform.usermanager.UserManager;
038import org.nuxeo.ecm.quota.size.QuotaAware;
039import org.nuxeo.ecm.quota.size.QuotaAwareDocument;
040import org.nuxeo.runtime.api.Framework;
041
042import java.lang.reflect.InvocationTargetException;
043import java.text.ParseException;
044import java.util.ArrayList;
045import java.util.Collections;
046import java.util.HashMap;
047import java.util.List;
048import java.util.Map;
049
050/**
051 * Abstract Box Adapter
052 *
053 * @since 5.9.2
054 */
055public abstract class BoxAdapter {
056
057    protected final DocumentModel doc;
058
059    protected final Map<String, Object> boxProperties = new HashMap<>();
060
061    protected BoxItem boxItem;
062
063    protected final BoxService boxService = Framework.getLocalService(BoxService.class);
064
065    public BoxAdapter(DocumentModel doc) {
066        this.doc = doc;
067        CoreSession session = doc.getCoreSession();
068
069        boxProperties.put(BoxItem.FIELD_ID, boxService.getBoxId(doc));
070        boxProperties.put(BoxItem.FIELD_SEQUENCE_ID, boxService.getBoxSequenceId(doc));
071        boxProperties.put(BoxItem.FIELD_ETAG, boxService.getBoxEtag(doc));
072
073        boxProperties.put(BoxItem.FIELD_NAME, doc.getName());
074        boxProperties.put(BoxItem.FIELD_CREATED_AT,
075                ISODateTimeFormat.dateTime().print(new DateTime(doc.getPropertyValue("dc:created"))));
076        boxProperties.put(BoxItem.FIELD_MODIFIED_AT,
077                ISODateTimeFormat.dateTime().print(new DateTime(doc.getPropertyValue("dc:modified"))));
078        boxProperties.put(BoxItem.FIELD_DESCRIPTION, doc.getPropertyValue("dc:description"));
079
080        // size
081        QuotaAwareDocument quotaAwareDocument = null;
082        if (Framework.getRuntime().getBundle("org.nuxeo.ecm.quota.core") != null) {
083            quotaAwareDocument = (QuotaAwareDocument) doc.getAdapter(QuotaAware.class);
084        }
085        boxProperties.put(BoxItem.FIELD_SIZE, quotaAwareDocument != null ? quotaAwareDocument.getInnerSize() : -1.0);
086
087        // path_collection
088        final DocumentModel parentDoc = session.getParentDocument(doc.getRef());
089        final Map<String, Object> pathCollection = new HashMap<>();
090        List<BoxTypedObject> hierarchy = getParentsHierarchy(session, parentDoc);
091        pathCollection.put(BoxCollection.FIELD_ENTRIES, hierarchy);
092        pathCollection.put(BoxCollection.FIELD_TOTAL_COUNT, hierarchy.size());
093        BoxCollection boxPathCollection = new BoxCollection(Collections.unmodifiableMap(pathCollection));
094        boxProperties.put(BoxItem.FIELD_PATH_COLLECTION, boxPathCollection);
095
096        // parent
097        final Map<String, Object> parentProperties = new HashMap<>();
098        parentProperties.put(BoxItem.FIELD_ID, boxService.getBoxId(parentDoc));
099        parentProperties.put(BoxItem.FIELD_SEQUENCE_ID, boxService.getBoxSequenceId(parentDoc));
100        parentProperties.put(BoxItem.FIELD_NAME, boxService.getBoxName(parentDoc));
101        parentProperties.put(BoxItem.FIELD_ETAG, boxService.getBoxEtag(parentDoc));
102        BoxFolder parentFolder = new BoxFolder(Collections.unmodifiableMap(parentProperties));
103        boxProperties.put(BoxItem.FIELD_PARENT, parentFolder);
104
105        // Users
106        // Creator
107        final UserManager userManager = Framework.getLocalService(UserManager.class);
108        String creator = doc.getPropertyValue("dc:creator") != null ? (String) doc.getPropertyValue("dc:creator")
109                : "system";
110        NuxeoPrincipal principalCreator = userManager.getPrincipal(creator);
111        final BoxUser boxCreator = boxService.fillUser(principalCreator);
112        boxProperties.put(BoxItem.FIELD_CREATED_BY, boxCreator);
113
114        // Last Contributor
115        String lastContributor = doc.getPropertyValue("dc:lastContributor") != null ? (String) doc.getPropertyValue("dc:lastContributor")
116                : "system";
117        final NuxeoPrincipal principalLastContributor = userManager.getPrincipal(lastContributor);
118        final BoxUser boxContributor = boxService.fillUser(principalLastContributor);
119        boxProperties.put(BoxItem.FIELD_MODIFIED_BY, boxContributor);
120
121        // Owner
122        boxProperties.put(BoxItem.FIELD_OWNED_BY, boxCreator);
123
124        // Shared Link
125        boxProperties.put(BoxItem.FIELD_SHARED_LINK, null);
126
127        // Status
128        boxProperties.put(BoxItem.FIELD_ITEM_STATUS, doc.getCurrentLifeCycleState());
129
130        // Tags
131        boxProperties.put(BoxItem.FIELD_TAGS, getTags(session));
132
133    }
134
135    public BoxItem getBoxItem() {
136        return boxItem;
137    }
138
139    abstract public BoxItem getMiniItem();
140
141    /**
142     * Update the box item properties
143     *
144     * @param boxItem containing values updated
145     */
146    public void setBoxItem(BoxItem boxItem) {
147        for (String field : boxItem.getKeySet()) {
148            this.boxItem.put(field, boxItem.getValue(field));
149        }
150    }
151
152    public DocumentModel getDoc() {
153        return doc;
154    }
155
156    protected List<BoxTypedObject> getParentsHierarchy(CoreSession session, DocumentModel parentDoc)
157            {
158        final List<BoxTypedObject> pathCollection = new ArrayList<>();
159        while (parentDoc != null) {
160            final Map<String, Object> parentCollectionProperties = new HashMap<>();
161            parentCollectionProperties.put(BoxItem.FIELD_ID, boxService.getBoxId(parentDoc));
162            parentCollectionProperties.put(BoxItem.FIELD_SEQUENCE_ID, boxService.getBoxSequenceId(parentDoc));
163            parentCollectionProperties.put(BoxItem.FIELD_ETAG, boxService.getBoxEtag(parentDoc));
164            parentCollectionProperties.put(BoxItem.FIELD_NAME, boxService.getBoxName(parentDoc));
165            BoxTypedObject boxParent;
166            // This different instantiation is related to the param type
167            // which is automatically added in json payload by Box marshaller
168            // following the box object type
169            if (parentDoc.isFolder()) {
170                boxParent = new BoxFolder(Collections.unmodifiableMap(parentCollectionProperties));
171            } else {
172                boxParent = new BoxFile(Collections.unmodifiableMap(parentCollectionProperties));
173            }
174            pathCollection.add(boxParent);
175            parentDoc = session.getParentDocument(parentDoc.getRef());
176        }
177        return pathCollection;
178    }
179
180    protected String[] getTags(CoreSession session) {
181        final TagService tagService = Framework.getLocalService(TagService.class);
182        final List<Tag> tags = tagService.getDocumentTags(session, doc.getId(), session.getPrincipal().getName());
183        final String[] tagNames = new String[tags.size()];
184        int index = 0;
185        for (Tag tag : tags) {
186            tagNames[index] = tag.getLabel();
187            index++;
188        }
189        return tagNames;
190    }
191
192    /**
193     * Update the document (nx/box sides) thanks to a box item
194     */
195    public void save(CoreSession session) throws ParseException, InvocationTargetException,
196            IllegalAccessException, BoxJSONException {
197
198        setDescription(boxItem.getDescription());
199        setCreator(boxItem.getOwnedBy().getId());
200
201        String id = boxItem.getParent().getId();
202        // check if id is root's one
203        String newParentId = "0".equals(id) ? session.getRootDocument().getId() : id;
204        IdRef documentIdRef = new IdRef(doc.getId());
205
206        // If the name has changed, update location in Nuxeo repository
207        // OR if parent id has been updated -> move the document
208        String oldParentId = session.getParentDocument(documentIdRef).getId();
209        if (!oldParentId.equals(newParentId) || !doc.getName().equals(boxItem.getName())) {
210
211            session.move(documentIdRef, new IdRef(newParentId), boxItem.getName());
212            // Title and name are same here
213            setTitle(boxItem.getName());
214        }
215
216        // Tags
217        TagService tagService = Framework.getLocalService(TagService.class);
218        if (tagService != null) {
219            if (boxItem.getTags().length != 0) {
220                tagService.removeTags(session, doc.getId());
221                for (String tag : boxItem.getTags()) {
222                    tagService.tag(session, doc.getId(), tag, session.getPrincipal().getName());
223                }
224            }
225        }
226        session.saveDocument(doc);
227        session.save();
228    }
229
230    public void setTitle(String value) {
231        doc.setPropertyValue("dc:title", value);
232    }
233
234    public void setDescription(String value) {
235        doc.setPropertyValue("dc:description", value);
236    }
237
238    public void setCreator(String value) {
239        doc.setPropertyValue("dc:creator", value);
240    }
241}