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