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