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