001/*
002 * (C) Copyright 2008 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 *     Thierry Delprat
018 */
019package org.nuxeo.ecm.platform.indexing.gateway.ws;
020
021import java.io.Serializable;
022import java.util.ArrayList;
023import java.util.List;
024import java.util.Map;
025import java.util.concurrent.ConcurrentHashMap;
026import java.util.concurrent.TimeUnit;
027import java.util.concurrent.locks.ReentrantLock;
028
029import javax.jws.WebMethod;
030import javax.jws.WebParam;
031import javax.jws.WebService;
032import javax.jws.soap.SOAPBinding;
033import javax.jws.soap.SOAPBinding.Style;
034
035import org.apache.commons.logging.Log;
036import org.apache.commons.logging.LogFactory;
037import org.nuxeo.common.utils.ExceptionUtils;
038import org.nuxeo.ecm.core.api.CoreSession;
039import org.nuxeo.ecm.core.api.DocumentModel;
040import org.nuxeo.ecm.core.api.IdRef;
041import org.nuxeo.ecm.core.api.IterableQueryResult;
042import org.nuxeo.ecm.core.api.PathRef;
043import org.nuxeo.ecm.core.api.security.ACL;
044import org.nuxeo.ecm.core.api.security.ACP;
045import org.nuxeo.ecm.core.query.sql.NXQL;
046import org.nuxeo.ecm.core.schema.DocumentType;
047import org.nuxeo.ecm.core.schema.SchemaManager;
048import org.nuxeo.ecm.platform.api.ws.DocumentBlob;
049import org.nuxeo.ecm.platform.api.ws.DocumentDescriptor;
050import org.nuxeo.ecm.platform.api.ws.DocumentProperty;
051import org.nuxeo.ecm.platform.api.ws.DocumentSnapshot;
052import org.nuxeo.ecm.platform.api.ws.NuxeoRemoting;
053import org.nuxeo.ecm.platform.api.ws.WsACE;
054import org.nuxeo.ecm.platform.api.ws.session.WSRemotingSession;
055import org.nuxeo.ecm.platform.audit.ws.EventDescriptorPage;
056import org.nuxeo.ecm.platform.audit.ws.ModifiedDocumentDescriptor;
057import org.nuxeo.ecm.platform.audit.ws.ModifiedDocumentDescriptorPage;
058import org.nuxeo.ecm.platform.audit.ws.WSAuditBean;
059import org.nuxeo.ecm.platform.audit.ws.api.WSAudit;
060import org.nuxeo.ecm.platform.indexing.gateway.adapter.IndexingAdapter;
061import org.nuxeo.ecm.platform.indexing.gateway.ws.api.WSIndexingGateway;
062import org.nuxeo.ecm.platform.ws.AbstractNuxeoWebService;
063import org.nuxeo.ecm.platform.ws.NuxeoRemotingBean;
064import org.nuxeo.runtime.api.Framework;
065
066/**
067 * Base class for WS beans used for external indexers. Implements most of NuxeoRemotingBean trying as hard as possible
068 * no to throw when a requested document is missing but returning empty descriptions instead so as to
069 * make external indexers not view recently deleted documents as applicative errors.
070 *
071 * @author tiry
072 */
073@WebService(name = "WSIndexingGatewayInterface", serviceName = "WSIndexingGatewayService")
074@SOAPBinding(style = Style.DOCUMENT)
075public class WSIndexingGatewayBean extends AbstractNuxeoWebService implements WSIndexingGateway {
076
077    protected static final String ENFORCE_SYNC_PROP_NAME = "nuxeo.indexing.gateway.forceSync";
078
079    protected static Log log = LogFactory.getLog(WSIndexingGatewayBean.class);
080
081    private static final long serialVersionUID = 4696352633818100451L;
082
083    protected transient WSAudit auditBean;
084
085    protected transient NuxeoRemoting platformRemoting;
086
087    protected IndexingAdapter adapter;
088
089    protected ConcurrentHashMap<String, ReentrantLock> sessionIdLocks = new ConcurrentHashMap<String, ReentrantLock>();
090
091    protected Boolean enforceSync = null;
092
093    protected static boolean DEPRECATION_DONE;
094
095    protected static void logDeprecation() {
096        if (!DEPRECATION_DONE) {
097            DEPRECATION_DONE = true;
098            log.warn("The SOAP endpoint /webservices/indexinggateway"
099                    + " is DEPRECATED since Nuxeo 9.3 and will be removed in a future version");
100        }
101    }
102
103    protected boolean forceSync() {
104        if (enforceSync == null) {
105            String value = Framework.getProperty(ENFORCE_SYNC_PROP_NAME, null);
106            enforceSync = false;
107            if (value != null) {
108                enforceSync = Boolean.parseBoolean(value);
109            } else {
110                enforceSync = false;
111            }
112        }
113        return enforceSync;
114    }
115
116    protected void lockSession(String sid) {
117        if (forceSync()) {
118            ReentrantLock lock = sessionIdLocks.putIfAbsent(sid, new ReentrantLock());
119            boolean aquired = false;
120            if (lock == null) {
121                lock = sessionIdLocks.get(sid);
122            }
123            try {
124                aquired = lock.tryLock(10, TimeUnit.SECONDS);
125            } catch (InterruptedException e) {
126                ExceptionUtils.checkInterrupt(e);
127            }
128            if (!aquired) {
129                log.error("Failed to acquire lock (timeout) for sid " + sid);
130            }
131        }
132    }
133
134    protected void releaseSession(String sid) {
135        if (forceSync()) {
136            ReentrantLock lock = sessionIdLocks.get(sid);
137            if (lock != null) {
138                lock.unlock();
139            }
140        }
141    }
142
143    protected WSAudit getWSAudit() {
144        if (auditBean == null) {
145            auditBean = new WSAuditBean();
146        }
147        return auditBean;
148    }
149
150    protected NuxeoRemoting getWSNuxeoRemoting() {
151        if (platformRemoting == null) {
152            platformRemoting = new NuxeoRemotingBean();
153        }
154        return platformRemoting;
155    }
156
157    protected IndexingAdapter getAdapter() {
158        if (adapter == null) {
159            adapter = Framework.getService(IndexingAdapter.class);
160        }
161        return adapter;
162    }
163
164    @WebMethod
165    public DocumentDescriptor[] getChildren(@WebParam(name = "sessionId") String sessionId,
166            @WebParam(name = "uuid") String uuid) {
167        logDeprecation();
168        try {
169            lockSession(sessionId);
170            CoreSession session = initSession(sessionId).getDocumentManager();
171            if (session.exists(new IdRef(uuid))) {
172                return getWSNuxeoRemoting().getChildren(sessionId, uuid);
173            } else {
174                return new DocumentDescriptor[0];
175            }
176        } finally {
177            releaseSession(sessionId);
178        }
179    }
180
181    @WebMethod
182    public DocumentDescriptor getCurrentVersion(@WebParam(name = "sessionId") String sid,
183            @WebParam(name = "uuid") String uid) {
184        logDeprecation();
185        try {
186            lockSession(sid);
187            CoreSession session = initSession(sid).getDocumentManager();
188            if (session.exists(new IdRef(uid))) {
189                return getWSNuxeoRemoting().getCurrentVersion(sid, uid);
190            } else {
191                return missingDocumentDescriptor(uid);
192            }
193        } finally {
194            releaseSession(sid);
195        }
196    }
197
198    @WebMethod
199    public DocumentDescriptor getDocument(@WebParam(name = "sessionId") String sessionId,
200            @WebParam(name = "uuid") String uuid) {
201        logDeprecation();
202        try {
203            lockSession(sessionId);
204            CoreSession session = initSession(sessionId).getDocumentManager();
205            DocumentDescriptor dd;
206            if (session.exists(new IdRef(uuid))) {
207                dd = getWSNuxeoRemoting().getDocument(sessionId, uuid);
208            } else {
209                dd = missingDocumentDescriptor(uuid);
210            }
211            return getAdapter().adaptDocumentDescriptor(session, uuid, dd);
212        } finally {
213            releaseSession(sessionId);
214        }
215    }
216
217    @WebMethod
218    public WsACE[] getDocumentACL(@WebParam(name = "sessionId") String sid, @WebParam(name = "uuid") String uuid)
219            {
220        logDeprecation();
221        try {
222            lockSession(sid);
223            CoreSession session = initSession(sid).getDocumentManager();
224            WsACE[] aces;
225            if (session.exists(new IdRef(uuid))) {
226                aces = getWSNuxeoRemoting().getDocumentACL(sid, uuid);
227            } else {
228                aces = new WsACE[0];
229            }
230            return getAdapter().adaptDocumentACL(session, uuid, aces);
231        } finally {
232            releaseSession(sid);
233        }
234    }
235
236    @WebMethod
237    public WsACE[] getDocumentLocalACL(@WebParam(name = "sessionId") String sid, @WebParam(name = "uuid") String uuid)
238            {
239        logDeprecation();
240        try {
241            lockSession(sid);
242            CoreSession session = initSession(sid).getDocumentManager();
243            WsACE[] aces;
244            if (session.exists(new IdRef(uuid))) {
245                aces = getWSNuxeoRemoting().getDocumentLocalACL(sid, uuid);
246            } else {
247                aces = new WsACE[0];
248            }
249            return getAdapter().adaptDocumentLocalACL(session, uuid, aces);
250        } finally {
251            releaseSession(sid);
252        }
253    }
254
255    public DocumentBlob[] getDocumentBlobsExt(@WebParam(name = "sessionId") String sid,
256            @WebParam(name = "uuid") String uuid, @WebParam(name = "useDownloadUrl") boolean useDownloadUrl)
257            {
258        try {
259            lockSession(sid);
260            CoreSession session = initSession(sid).getDocumentManager();
261            DocumentBlob[] blobs;
262            if (session.exists(new IdRef(uuid))) {
263                blobs = getWSNuxeoRemoting().getDocumentBlobsExt(sid, uuid, useDownloadUrl);
264            } else {
265                blobs = new DocumentBlob[0];
266            }
267            return getAdapter().adaptDocumentBlobs(session, uuid, blobs);
268
269        } finally {
270            releaseSession(sid);
271        }
272    }
273
274    @WebMethod
275    public DocumentBlob[] getDocumentBlobs(@WebParam(name = "sessionId") String sid,
276            @WebParam(name = "uuid") String uuid) {
277        logDeprecation();
278        return getDocumentBlobsExt(sid, uuid, getAdapter().useDownloadUrlForBlob());
279    }
280
281    @WebMethod
282    public DocumentProperty[] getDocumentNoBlobProperties(@WebParam(name = "sessionId") String sid,
283            @WebParam(name = "uuid") String uuid) {
284        logDeprecation();
285
286        try {
287            lockSession(sid);
288            CoreSession session = initSession(sid).getDocumentManager();
289            DocumentProperty[] properties;
290            if (session.exists(new IdRef(uuid))) {
291                properties = getWSNuxeoRemoting().getDocumentNoBlobProperties(sid, uuid);
292            } else {
293                properties = new DocumentProperty[0];
294            }
295            return getAdapter().adaptDocumentNoBlobProperties(session, uuid, properties);
296        } finally {
297            releaseSession(sid);
298        }
299
300    }
301
302    @WebMethod
303    public DocumentProperty[] getDocumentProperties(@WebParam(name = "sessionId") String sid,
304            @WebParam(name = "uuid") String uuid) {
305        logDeprecation();
306        try {
307            lockSession(sid);
308            CoreSession session = initSession(sid).getDocumentManager();
309            DocumentProperty[] properties;
310            if (session.exists(new IdRef(uuid))) {
311                properties = getWSNuxeoRemoting().getDocumentProperties(sid, uuid);
312            } else {
313                properties = new DocumentProperty[0];
314            }
315            return getAdapter().adaptDocumentProperties(session, uuid, properties);
316        } finally {
317            releaseSession(sid);
318        }
319    }
320
321    @WebMethod
322    public String[] getGroups(@WebParam(name = "sessionId") String sid,
323            @WebParam(name = "parentGroup") String parentGroup) {
324        logDeprecation();
325        return getWSNuxeoRemoting().getGroups(sid, parentGroup);
326    }
327
328    @WebMethod
329    public String getRepositoryName(@WebParam(name = "sessionId") String sid) {
330        logDeprecation();
331        return getWSNuxeoRemoting().getRepositoryName(sid);
332    }
333
334    @WebMethod
335    public DocumentDescriptor getRootDocument(@WebParam(name = "sessionId") String sessionId) {
336        logDeprecation();
337        try {
338            lockSession(sessionId);
339            return getWSNuxeoRemoting().getRootDocument(sessionId);
340        } finally {
341            releaseSession(sessionId);
342        }
343    }
344
345    @WebMethod
346    public String resolvePathToUUID(@WebParam(name = "sessionId") String sessionId, @WebParam(name = "path") String path)
347            {
348        logDeprecation();
349        try {
350            lockSession(sessionId);
351            CoreSession session = initSession(sessionId).getDocumentManager();
352            if (session != null) {
353                PathRef pathRef = new PathRef(path);
354                if (session.exists(pathRef)) {
355                    return session.getDocument(pathRef).getId();
356                }
357            }
358            return null;
359        } finally {
360            releaseSession(sessionId);
361        }
362    }
363
364    @WebMethod
365    public UUIDPage getRecursiveChildrenUUIDsByPage(@WebParam(name = "sessionId") String sid,
366            @WebParam(name = "uuid") String uuid, @WebParam(name = "page") int page,
367            @WebParam(name = "pageSize") int pageSize) {
368        logDeprecation();
369
370        try {
371            lockSession(sid);
372            CoreSession session = initSession(sid).getDocumentManager();
373
374            List<String> uuids = new ArrayList<String>();
375            IdRef parentRef = new IdRef(uuid);
376            DocumentModel parent = session.getDocument(parentRef);
377            String path = parent.getPathAsString();
378
379            String query = "select ecm:uuid from Document where ecm:path startswith '" + path + "' order by ecm:uuid";
380
381            IterableQueryResult result = session.queryAndFetch(query, "NXQL");
382            boolean hasMore = false;
383            try {
384                if (page > 1) {
385                    int skip = (page - 1) * pageSize;
386                    result.skipTo(skip);
387                }
388
389                for (Map<String, Serializable> record : result) {
390                    uuids.add((String) record.get(NXQL.ECM_UUID));
391                    if (uuids.size() == pageSize) {
392                        hasMore = true;
393                        break;
394                    }
395                }
396            } finally {
397                result.close();
398            }
399            return new UUIDPage(uuids.toArray(new String[uuids.size()]), page, hasMore);
400        } finally {
401            releaseSession(sid);
402        }
403
404    }
405
406    @WebMethod
407    public String[] getRecursiveChildrenUUIDs(@WebParam(name = "sessionId") String sid,
408            @WebParam(name = "uuid") String uuid) {
409        logDeprecation();
410
411        try {
412            lockSession(sid);
413            CoreSession session = initSession(sid).getDocumentManager();
414
415            List<String> uuids = new ArrayList<String>();
416            IdRef parentRef = new IdRef(uuid);
417            DocumentModel parent = session.getDocument(parentRef);
418            String path = parent.getPathAsString();
419
420            String query = "select ecm:uuid from Document where ecm:path startswith '" + path + "' order by ecm:uuid";
421
422            IterableQueryResult result = session.queryAndFetch(query, "NXQL");
423
424            try {
425                for (Map<String, Serializable> record : result) {
426                    uuids.add((String) record.get(NXQL.ECM_UUID));
427                }
428            } finally {
429                result.close();
430            }
431
432            return uuids.toArray(new String[uuids.size()]);
433        } finally {
434            releaseSession(sid);
435        }
436
437    }
438
439    @WebMethod
440    public DocumentTypeDescriptor[] getTypeDefinitions() {
441        logDeprecation();
442
443        List<DocumentTypeDescriptor> result = new ArrayList<DocumentTypeDescriptor>();
444        SchemaManager sm = Framework.getService(SchemaManager.class);
445
446        for (DocumentType dt : sm.getDocumentTypes()) {
447            result.add(new DocumentTypeDescriptor(dt));
448        }
449
450        return result.toArray(new DocumentTypeDescriptor[result.size()]);
451    }
452
453    @WebMethod
454    public DocumentDescriptor getDocumentFromPath(@WebParam(name = "sessionId") String sessionId,
455            @WebParam(name = "path") String path) {
456        logDeprecation();
457        try {
458            lockSession(sessionId);
459            String uuid = resolvePathToUUID(sessionId, path);
460            if (uuid != null) {
461                return getWSNuxeoRemoting().getDocument(sessionId, uuid);
462            } else {
463                // should we return a missing document with an null uuid
464                // instead?
465                return null;
466            }
467        } finally {
468            releaseSession(sessionId);
469        }
470    }
471
472    @WebMethod
473    public DocumentDescriptor getSourceDocument(@WebParam(name = "sessionId") String sid,
474            @WebParam(name = "uuid") String uid) {
475        logDeprecation();
476        try {
477            lockSession(sid);
478            CoreSession session = initSession(sid).getDocumentManager();
479            if (session.exists(new IdRef(uid))) {
480                return getWSNuxeoRemoting().getSourceDocument(sid, uid);
481            } else {
482                return missingDocumentDescriptor(uid);
483            }
484        } finally {
485            releaseSession(sid);
486        }
487    }
488
489    @WebMethod
490    public String[] getUsers(@WebParam(name = "sessionId") String sid,
491            @WebParam(name = "parentGroup") String parentGroup) {
492        logDeprecation();
493        return getWSNuxeoRemoting().getUsers(sid, parentGroup);
494    }
495
496    @WebMethod
497    public DocumentDescriptor[] getVersions(@WebParam(name = "sessionId") String sid,
498            @WebParam(name = "uuid") String uid) {
499        logDeprecation();
500        try {
501            lockSession(sid);
502            CoreSession session = initSession(sid).getDocumentManager();
503            if (session.exists(new IdRef(uid))) {
504                return getWSNuxeoRemoting().getVersions(sid, uid);
505            } else {
506                return new DocumentDescriptor[0];
507            }
508        } finally {
509            releaseSession(sid);
510        }
511    }
512
513    @WebMethod
514    public String[] listGroups(@WebParam(name = "sessionId") String sid, @WebParam(name = "from") int from,
515            @WebParam(name = "to") int to) {
516        logDeprecation();
517        return getWSNuxeoRemoting().listGroups(sid, from, to);
518    }
519
520    @WebMethod
521    public String[] listUsers(@WebParam(name = "sessionId") String sid, @WebParam(name = "from") int from,
522            @WebParam(name = "to") int to) {
523        logDeprecation();
524        return getWSNuxeoRemoting().listUsers(sid, from, to);
525    }
526
527    @WebMethod
528    public ModifiedDocumentDescriptor[] listModifiedDocuments(@WebParam(name = "sessionId") String sessionId,
529            @WebParam(name = "dateRangeQuery") String dateRangeQuery) {
530        logDeprecation();
531        return getWSAudit().listModifiedDocuments(sessionId, dateRangeQuery);
532    }
533
534    @WebMethod
535    public ModifiedDocumentDescriptorPage listModifiedDocumentsByPage(@WebParam(name = "sessionId") String sessionId,
536            @WebParam(name = "dateRangeQuery") String dateRangeQuery, @WebParam(name = "path") String path,
537            @WebParam(name = "page") int page, @WebParam(name = "pageSize") int pageSize) {
538        logDeprecation();
539        return getWSAudit().listModifiedDocumentsByPage(sessionId, dateRangeQuery, path, page, pageSize);
540    }
541
542    @WebMethod
543    public EventDescriptorPage listEventsByPage(@WebParam(name = "sessionId") String sessionId,
544            @WebParam(name = "dateRangeQuery") String dateRangeQuery, @WebParam(name = "page") int page,
545            @WebParam(name = "pageSize") int pageSize) {
546        logDeprecation();
547        return getWSAudit().listEventsByPage(sessionId, dateRangeQuery, page, pageSize);
548    }
549
550    @WebMethod
551    public EventDescriptorPage listDocumentEventsByPage(@WebParam(name = "sessionId") String sessionId,
552            @WebParam(name = "dateRangeQuery") String dateRangeQuery, @WebParam(name = "startDate") String startDate,
553            @WebParam(name = "path") String path, @WebParam(name = "page") int page,
554            @WebParam(name = "pageSize") int pageSize) {
555        logDeprecation();
556        return getWSAudit().listDocumentEventsByPage(sessionId, dateRangeQuery, startDate, path, page, pageSize);
557    }
558
559    @WebMethod
560    public String getRelativePathAsString(@WebParam(name = "sessionId") String sessionId,
561            @WebParam(name = "uuid") String uuid) {
562        logDeprecation();
563        try {
564            lockSession(sessionId);
565            CoreSession session = initSession(sessionId).getDocumentManager();
566            if (session.exists(new IdRef(uuid))) {
567                return getWSNuxeoRemoting().getRelativePathAsString(sessionId, uuid);
568            } else {
569                return null;
570            }
571        } finally {
572            releaseSession(sessionId);
573        }
574    }
575
576    @WebMethod
577    public boolean hasPermission(@WebParam(name = "sessionId") String sid, @WebParam(name = "uuid") String uuid,
578            @WebParam(name = "permission") String permission) {
579        logDeprecation();
580        try {
581            lockSession(sid);
582            CoreSession session = initSession(sid).getDocumentManager();
583            if (session.exists(new IdRef(uuid))) {
584                return getWSNuxeoRemoting().hasPermission(sid, uuid, permission);
585            } else {
586                return false;
587            }
588        } finally {
589            releaseSession(sid);
590        }
591    }
592
593    @WebMethod
594    public String uploadDocument(@WebParam(name = "sessionId") String sid, String path, String type, String[] properties)
595            {
596        logDeprecation();
597        try {
598            lockSession(sid);
599            return getWSNuxeoRemoting().uploadDocument(sid, path, type, properties);
600        } finally {
601            releaseSession(sid);
602        }
603    }
604
605    @WebMethod
606    public String connect(@WebParam(name = "userName") String username, @WebParam(name = "password") String password)
607            {
608        logDeprecation();
609        return getWSNuxeoRemoting().connect(username, password);
610    }
611
612    @WebMethod
613    public void disconnect(@WebParam(name = "sessionId") String sid) {
614        logDeprecation();
615        getWSNuxeoRemoting().disconnect(sid);
616        if (forceSync()) {
617            ReentrantLock lock = sessionIdLocks.get(sid);
618            if (lock != null) {
619                if (lock.isLocked()) {
620                    lock.unlock();
621                }
622                sessionIdLocks.remove(sid);
623            }
624        }
625    }
626
627    @WebMethod
628    public EventDescriptorPage queryEventsByPage(@WebParam(name = "sessionId") String sessionId,
629            @WebParam(name = "whereClause") String whereClause, @WebParam(name = "pageIndex") int page,
630            @WebParam(name = "pageSize") int pageSize) {
631        logDeprecation();
632        return getWSAudit().queryEventsByPage(sessionId, whereClause, page, pageSize);
633    }
634
635    @WebMethod
636    public boolean validateUserPassword(@WebParam(name = "sessionId") String sessionId,
637            @WebParam(name = "username") String username, @WebParam(name = "password") String password)
638            {
639        logDeprecation();
640        WSRemotingSession rs = initSession(sessionId);
641        return rs.getUserManager().checkUsernamePassword(username, password);
642    }
643
644    @WebMethod
645    public String[] getUserGroups(@WebParam(name = "sessionId") String sessionId,
646            @WebParam(name = "username") String username) {
647        logDeprecation();
648        WSRemotingSession rs = initSession(sessionId);
649        List<String> groups = rs.getUserManager().getPrincipal(username).getAllGroups();
650        String[] groupArray = new String[groups.size()];
651        groups.toArray(groupArray);
652        return groupArray;
653    }
654
655    public DocumentSnapshot getDocumentSnapshotExt(@WebParam(name = "sessionId") String sessionId,
656            @WebParam(name = "uuid") String uuid, @WebParam(name = "useDownloadUrl") boolean useDownloadUrl)
657            {
658
659        try {
660            lockSession(sessionId);
661            WSRemotingSession rs = initSession(sessionId);
662            DocumentModel doc = rs.getDocumentManager().getDocument(new IdRef(uuid));
663
664            DocumentProperty[] props = getDocumentNoBlobProperties(sessionId, uuid);
665            DocumentBlob[] blobs = getDocumentBlobs(sessionId, uuid);
666
667            WsACE[] resACP = null;
668
669            ACP acp = doc.getACP();
670            if (acp != null && acp.getACLs().length > 0) {
671                ACL acl = acp.getMergedACLs("MergedACL");
672                resACP = WsACE.wrap(acl.getACEs());
673            }
674            DocumentSnapshot ds = new DocumentSnapshot(props, blobs, doc.getPathAsString(), resACP);
675            return ds;
676        } finally {
677            releaseSession(sessionId);
678        }
679    }
680
681    @WebMethod
682    public DocumentSnapshot getDocumentSnapshot(@WebParam(name = "sessionId") String sessionId,
683            @WebParam(name = "uuid") String uuid) {
684        logDeprecation();
685        return getDocumentSnapshotExt(sessionId, uuid, getAdapter().useDownloadUrlForBlob());
686    }
687
688    public ModifiedDocumentDescriptorPage listDeletedDocumentsByPage(@WebParam(name = "sessionId") String sessionId,
689            @WebParam(name = "dataRangeQuery") String dateRangeQuery, @WebParam(name = "docPath") String path,
690            @WebParam(name = "pageIndex") int page, @WebParam(name = "pageSize") int pageSize) {
691
692        return getWSAudit().listDeletedDocumentsByPage(sessionId, dateRangeQuery, path, page, pageSize);
693    }
694
695    /**
696     * Utility method to build descriptor for a document that is non longer to be found in the repository.
697     *
698     * @param uuid
699     * @return
700     */
701    protected DocumentDescriptor missingDocumentDescriptor(String uuid) {
702        // TODO: if we have to make the API / WSDL evolve it would be nice to
703        // include an explicit attribute in DocumentDescriptor to mark missing
704        // documents
705        DocumentDescriptor dd = new DocumentDescriptor();
706        dd.setUUID(uuid);
707        return dd;
708    }
709
710}