001/*
002 * (C) Copyright 2006-2011 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 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.core.opencmis.tests;
020
021import java.io.ByteArrayOutputStream;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.Serializable;
025import java.util.Calendar;
026import java.util.GregorianCalendar;
027import java.util.HashMap;
028import java.util.Map;
029import java.util.TimeZone;
030
031import org.apache.commons.codec.digest.DigestUtils;
032import org.nuxeo.ecm.core.api.Blob;
033import org.nuxeo.ecm.core.api.Blobs;
034import org.nuxeo.ecm.core.api.CoreSession;
035import org.nuxeo.ecm.core.api.DocumentModel;
036import org.nuxeo.ecm.core.api.DocumentRef;
037import org.nuxeo.ecm.core.api.NuxeoException;
038import org.nuxeo.ecm.core.api.PathRef;
039import org.nuxeo.ecm.core.api.VersioningOption;
040import org.nuxeo.ecm.core.api.impl.DocumentModelImpl;
041import org.nuxeo.ecm.core.api.security.ACE;
042import org.nuxeo.ecm.core.api.security.ACL;
043import org.nuxeo.ecm.core.api.security.ACP;
044import org.nuxeo.ecm.core.api.security.SecurityConstants;
045import org.nuxeo.ecm.core.api.security.impl.ACLImpl;
046import org.nuxeo.ecm.core.api.security.impl.ACPImpl;
047import org.nuxeo.ecm.core.api.trash.TrashService;
048import org.nuxeo.ecm.platform.thumbnail.ThumbnailConstants;
049import org.nuxeo.runtime.api.Framework;
050import org.nuxeo.runtime.transaction.TransactionHelper;
051
052/**
053 * Various static methods used in several test cases.
054 */
055public class Helper {
056
057    public static final String FILE1_CONTENT = "Noodles with rice";
058
059    /**
060     * Reads a stream into a string.
061     */
062    public static String read(InputStream in, String charset) throws IOException {
063        ByteArrayOutputStream os = new ByteArrayOutputStream();
064        byte[] buf = new byte[256];
065        try {
066            int n;
067            while ((n = in.read(buf)) != -1) {
068                os.write(buf, 0, n);
069            }
070        } finally {
071            in.close();
072        }
073        return os.toString(charset);
074    }
075
076    /**
077     * Gets a Calendar object.
078     */
079    public static GregorianCalendar getCalendar(int year, int month, int day, int hours, int minutes, int seconds) {
080        TimeZone tz = TimeZone.getTimeZone("GMT-02:00"); // in the Atlantic
081        return getCalendar(year, month, day, hours, minutes, seconds, tz);
082    }
083
084    /**
085     * Gets a Calendar object with a specific timezone
086     */
087    public static GregorianCalendar getCalendar(int year, int month, int day, int hours, int minutes, int seconds,
088            TimeZone tz) {
089        GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance(tz);
090        cal.set(Calendar.YEAR, year);
091        cal.set(Calendar.MONTH, month - 1); // 0-based
092        cal.set(Calendar.DAY_OF_MONTH, day);
093        cal.set(Calendar.HOUR_OF_DAY, hours);
094        cal.set(Calendar.MINUTE, minutes);
095        cal.set(Calendar.SECOND, seconds);
096        cal.set(Calendar.MILLISECOND, 0);
097        return cal;
098    }
099
100    public static Map<String, String> makeNuxeoRepository(CoreSession session) {
101        return makeNuxeoRepository(session, false);
102    }
103
104    /**
105     * Creates data in the repository using the Nuxeo API. This is then used as a starting point by unit tests.
106     */
107    public static Map<String, String> makeNuxeoRepository(CoreSession session, boolean addProxy) {
108        // remove default-domain
109        DocumentRef defaultDomain = new PathRef("/default-domain");
110        if (session.exists(defaultDomain)) {
111            session.removeDocument(defaultDomain);
112        }
113
114        Map<String, String> info = new HashMap<>();
115
116        DocumentModel folder1 = session.createDocumentModel("/", "testfolder1", "Folder");
117        folder1.setPropertyValue("dc:title", "testfolder1_Title");
118        folder1 = createDocument(session, folder1);
119
120        DocumentModel file1 = session.createDocumentModel("/testfolder1", "testfile1", "File");
121        file1.setPropertyValue("dc:title", "testfile1_Title");
122        file1.setPropertyValue("dc:description", "testfile1_description");
123        String content = FILE1_CONTENT;
124        String filename = "testfile.txt";
125        Blob blob1 = Blobs.createBlob(content);
126        blob1.setDigest(DigestUtils.md5Hex(content));
127        blob1.setFilename(filename);
128        file1.setPropertyValue("content", (Serializable) blob1);
129        Calendar cal1 = getCalendar(2007, 3, 1, 12, 0, 0, TimeZone.getDefault());
130        file1.setPropertyValue("dc:created", cal1);
131        file1.setPropertyValue("dc:modified", cal1);
132        file1.setPropertyValue("dc:creator", "michael");
133        file1.setPropertyValue("dc:lastContributor", "john");
134        file1.setPropertyValue("dc:coverage", "foo/bar");
135        file1.setPropertyValue("dc:subjects", new String[] { "foo", "gee/moo" });
136        file1.addFacet(ThumbnailConstants.THUMBNAIL_FACET);
137        Blob thumbnailBlob;
138        String digest;
139        try {
140            thumbnailBlob = Blobs.createBlob(Helper.class.getResource("/text.png").openStream(), "image/png");
141            try (InputStream stream = thumbnailBlob.getStream()) {
142                digest = DigestUtils.md5Hex(stream);
143            }
144        } catch (IOException e) {
145            throw new RuntimeException(e);
146        }
147        thumbnailBlob.setDigest(digest);
148        thumbnailBlob.setFilename("test.png");
149        file1.setPropertyValue(ThumbnailConstants.THUMBNAIL_PROPERTY_NAME, (Serializable) thumbnailBlob);
150        file1 = createDocument(session, file1);
151
152        ACPImpl acp;
153        ACL acl;
154        acl = new ACLImpl();
155        acl.add(new ACE("bob", SecurityConstants.BROWSE, true));
156        acp = new ACPImpl();
157        acp.addACL(acl);
158        file1.setACP(acp, true);
159
160        DocumentModel file2 = session.createDocumentModel("/testfolder1", "testfile2", "File");
161        file2.setPropertyValue("dc:title", "testfile2_Title");
162        file2.setPropertyValue("dc:description", "something");
163        Calendar cal2 = getCalendar(2007, 4, 1, 12, 0, 0);
164        file2.setPropertyValue("dc:created", cal2);
165        file2.setPropertyValue("dc:creator", "pete");
166        file2.setPropertyValue("dc:contributors", new String[] { "pete", "bob" });
167        file2.setPropertyValue("dc:lastContributor", "bob");
168        file2.setPropertyValue("dc:coverage", "football");
169        file2 = createDocument(session, file2);
170
171        acl = new ACLImpl();
172        acl.add(new ACE("bob", SecurityConstants.BROWSE, true));
173        acp = new ACPImpl();
174        acp.addACL(acl);
175        file2.setACP(acp, true);
176
177        DocumentModel file3 = session.createDocumentModel("/testfolder1", "testfile3", "Note");
178        file3.setPropertyValue("note", "this is a note");
179        file3.setPropertyValue("dc:title", "testfile3_Title");
180        file3.setPropertyValue("dc:description", "testfile3_desc1 testfile3_desc2,  testfile3_desc3");
181        file3.setPropertyValue("dc:contributors", new String[] { "bob", "john" });
182        file3.setPropertyValue("dc:lastContributor", "john");
183        file3 = createDocument(session, file3);
184
185        DocumentModel folder2 = session.createDocumentModel("/", "testfolder2", "Folder");
186        folder2.setPropertyValue("dc:title", "testfolder2_Title");
187        folder2 = createDocument(session, folder2);
188
189        DocumentModel folder3 = session.createDocumentModel("/testfolder2", "testfolder3", "Folder");
190        folder3.setPropertyValue("dc:title", "testfolder3_Title");
191        folder3 = createDocument(session, folder3);
192
193        DocumentModel folder4 = session.createDocumentModel("/testfolder2", "testfolder4", "Folder");
194        folder4.setPropertyValue("dc:title", "testfolder4_Title");
195        folder4 = createDocument(session, folder4);
196
197        DocumentModel file4 = session.createDocumentModel("/testfolder2/testfolder3", "testfile4", "File");
198        file4.setPropertyValue("dc:title", "testfile4_Title");
199        file4.setPropertyValue("dc:description", "something");
200        file4 = createDocument(session, file4);
201
202        DocumentModel file5 = session.createDocumentModel("/testfolder1", "testfile5", "File");
203        file5.setPropertyValue("dc:title", "title5");
204        file5 = createDocument(session, file5);
205        sleepForAuditGranularity();
206        Framework.getService(TrashService.class).trashDocument(file5);
207        file5 = saveDocument(session, file5);
208        info.put("file5id", file5.getId());
209
210        DocumentModel file6 = session.createDocumentModel("/testfolder2/testfolder3", "testfile6", "Note");
211        file6.setPropertyValue("dc:title", "title6");
212        file6 = createDocument(session, file6);
213
214        if (addProxy) {
215            sleepForAuditGranularity();
216            file6.putContextData("disableDublinCoreListener", Boolean.TRUE);
217            DocumentRef file6verref = file6.checkIn(VersioningOption.MINOR, null);
218
219            sleepForAuditGranularity();
220            DocumentModel proxy = session.createProxy(file6verref, folder2.getRef());
221            info.put("file6verid", proxy.getSourceId());
222            info.put("proxyid", proxy.getId());
223        }
224
225        return info;
226    }
227
228    /**
229     * For audit, make sure event dates don't have the same millisecond.
230     */
231    public static void sleepForAuditGranularity() {
232        try {
233            Thread.sleep(2);
234        } catch (InterruptedException e) {
235            Thread.currentThread().interrupt();
236            throw new NuxeoException(e);
237        }
238    }
239
240    public static DocumentModel createDocument(CoreSession session, DocumentModel doc) {
241        sleepForAuditGranularity();
242        // avoid changes in last contributor in these tests
243        doc.putContextData("disableDublinCoreListener", Boolean.TRUE);
244        return session.createDocument(doc);
245    }
246
247    public static DocumentModel saveDocument(CoreSession session, DocumentModel doc) {
248        sleepForAuditGranularity();
249        return session.saveDocument(doc);
250    }
251
252    public static String createUserWorkspace(CoreSession repo, String username) {
253
254        DocumentModel container = repo.createDocumentModel("/", "UserWorkspaceRoot", "UserWorkspaceRoot");
255        container = repo.createDocument(container);
256        {
257            ACP acp = new ACPImpl();
258            ACL acl = new ACLImpl();
259            acl.setACEs(new ACE[] { new ACE(SecurityConstants.EVERYONE, SecurityConstants.EVERYTHING, false) });
260            acp.addACL(acl);
261            container.setACP(acp, true);
262        }
263
264        DocumentModel ws = new DocumentModelImpl(container.getPathAsString(), username, "Workspace");
265        ws = repo.createDocument(ws);
266        ACP acp = new ACPImpl();
267        {
268            ACL acl = new ACLImpl();
269            acl.setACEs(new ACE[] { new ACE(username, SecurityConstants.EVERYTHING, true) });
270            acp.addACL(acl);
271            ws.setACP(acp, true);
272        }
273
274        repo.save();
275        if (TransactionHelper.isTransactionActive()) {
276            TransactionHelper.commitOrRollbackTransaction();
277            TransactionHelper.startTransaction();
278        }
279        return ws.getPathAsString();
280    }
281}