001/* 002 * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * 017 * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $ 018 */ 019 020package org.nuxeo.ecm.webapp.context; 021 022import static org.jboss.seam.ScopeType.CONVERSATION; 023import static org.jboss.seam.ScopeType.EVENT; 024import static org.jboss.seam.annotations.Install.FRAMEWORK; 025import static org.nuxeo.ecm.webapp.helpers.EventNames.NAVIGATE_TO_DOCUMENT; 026 027import java.io.Serializable; 028import java.util.ArrayList; 029import java.util.Collections; 030import java.util.List; 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033import org.jboss.seam.Component; 034import org.jboss.seam.annotations.Begin; 035import org.jboss.seam.annotations.Create; 036import org.jboss.seam.annotations.Factory; 037import org.jboss.seam.annotations.In; 038import org.jboss.seam.annotations.Install; 039import org.jboss.seam.annotations.Name; 040import org.jboss.seam.annotations.Scope; 041import org.jboss.seam.annotations.intercept.BypassInterceptors; 042import org.jboss.seam.annotations.web.RequestParameter; 043import org.jboss.seam.contexts.Context; 044import org.jboss.seam.contexts.Contexts; 045import org.jboss.seam.core.Events; 046import org.nuxeo.common.utils.Path; 047import org.nuxeo.ecm.core.api.CoreSession; 048import org.nuxeo.ecm.core.api.DocumentLocation; 049import org.nuxeo.ecm.core.api.DocumentModel; 050import org.nuxeo.ecm.core.api.DocumentModelList; 051import org.nuxeo.ecm.core.api.DocumentRef; 052import org.nuxeo.ecm.core.api.IdRef; 053import org.nuxeo.ecm.core.api.NuxeoException; 054import org.nuxeo.ecm.core.api.VersionModel; 055import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl; 056import org.nuxeo.ecm.core.api.security.SecurityConstants; 057import org.nuxeo.ecm.core.schema.FacetNames; 058import org.nuxeo.ecm.core.schema.SchemaManager; 059import org.nuxeo.ecm.platform.types.Type; 060import org.nuxeo.ecm.platform.types.adapter.TypeInfo; 061import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; 062import org.nuxeo.ecm.platform.ui.web.api.UserAction; 063import org.nuxeo.ecm.platform.ui.web.pathelements.ArchivedVersionsPathElement; 064import org.nuxeo.ecm.platform.ui.web.pathelements.DocumentPathElement; 065import org.nuxeo.ecm.platform.ui.web.pathelements.HiddenDocumentPathElement; 066import org.nuxeo.ecm.platform.ui.web.pathelements.PathElement; 067import org.nuxeo.ecm.platform.ui.web.pathelements.VersionDocumentPathElement; 068import org.nuxeo.ecm.platform.ui.web.util.BadDocumentUriException; 069import org.nuxeo.ecm.platform.ui.web.util.DocumentLocator; 070import org.nuxeo.ecm.platform.ui.web.util.DocumentsListsUtils; 071import org.nuxeo.ecm.platform.util.RepositoryLocation; 072import org.nuxeo.ecm.webapp.action.TypesTool; 073import org.nuxeo.ecm.webapp.delegate.DocumentManagerBusinessDelegate; 074import org.nuxeo.ecm.webapp.helpers.ApplicationControllerHelper; 075import org.nuxeo.ecm.webapp.helpers.EventManager; 076import org.nuxeo.ecm.webapp.helpers.EventNames; 077import org.nuxeo.runtime.api.Framework; 078 079/** 080 * Implementation for the navigationContext component available on the session. 081 */ 082@Name("navigationContext") 083@Scope(CONVERSATION) 084@Install(precedence = FRAMEWORK) 085public class NavigationContextBean implements NavigationContext, Serializable { 086 087 private static final long serialVersionUID = -3708768859028774906L; 088 089 private static final Log log = LogFactory.getLog(NavigationContextBean.class); 090 091 // -------------------------------------------- 092 // fields managed by this class 093 // These fields can be accessed by 2 ways 094 // - simple getters 095 // - via the context thanks to @Factory 096 097 private DocumentModel currentDomain; 098 099 private DocumentModel currentContentRoot; 100 101 private DocumentModel currentWorkspace; 102 103 protected DocumentModel currentDocument; 104 105 protected DocumentModel currentSuperSpace; 106 107 protected DocumentModelList currentDocumentChildren; 108 109 protected List<DocumentModel> currentDocumentParents; 110 111 // document model that is not persisted yet (used for creation) 112 private DocumentModel changeableDocument; 113 114 private List<PathElement> parents; 115 116 private SchemaManager schemaManager; 117 118 @In(create = true, required = false) 119 protected transient CoreSession documentManager; 120 121 @Override 122 @Create 123 public void init() { 124 parents = null; 125 } 126 127 @Override 128 @BypassInterceptors 129 public DocumentModel getCurrentDocument() { 130 return currentDocument; 131 } 132 133 @Override 134 public String getCurrentDomainPath() { 135 if (currentDomain != null) { 136 return currentDomain.getPathAsString(); 137 } 138 Path path; 139 if (currentDocument != null) { 140 path = currentDocument.getPath(); 141 } else { 142 // Find any document, and lookup its domain. 143 DocumentModelList docs = documentManager.query("SELECT * FROM Document", 1); 144 if (docs.size() < 1) { 145 log.debug("Could not find a single document readable by current user."); 146 return null; 147 } 148 path = docs.get(0).getPath(); 149 } 150 if (path.segmentCount() > 0) { 151 String[] segs = { path.segment(0) }; 152 return Path.createFromSegments(segs).toString(); 153 } else { 154 return null; 155 } 156 } 157 158 @Override 159 public void setCurrentDocument(DocumentModel documentModel) { 160 if (log.isDebugEnabled()) { 161 log.debug("Setting current document to " + documentModel); 162 } 163 164 if (!checkIfUpdateNeeded(currentDocument, documentModel)) { 165 if (log.isDebugEnabled()) { 166 log.debug(String.format("Current document already set to %s => give up updates", documentModel)); 167 } 168 return; 169 } 170 171 currentSuperSpace = null; 172 currentDocument = documentModel; 173 // update all depending variables 174 updateContextVariables(); 175 resetCurrentPath(); 176 Contexts.getEventContext().remove("currentDocument"); 177 178 EventManager.raiseEventsOnDocumentSelected(currentDocument); 179 180 if (log.isDebugEnabled()) { 181 log.debug("Current document set to: " + changeableDocument); 182 } 183 } 184 185 @Override 186 @BypassInterceptors 187 public DocumentModel getChangeableDocument() { 188 return changeableDocument; 189 } 190 191 @Override 192 public void setChangeableDocument(DocumentModel changeableDocument) { 193 if (log.isDebugEnabled()) { 194 log.debug("Setting changeable document to: " + changeableDocument); 195 } 196 this.changeableDocument = changeableDocument; 197 Contexts.getEventContext().set("changeableDocument", changeableDocument); 198 } 199 200 @Override 201 public DocumentModelList getCurrentPath() { 202 DocumentModelList parentDocsList = new DocumentModelListImpl(); 203 204 List<DocumentModel> fromRoot = documentManager.getParentDocuments(currentDocument.getRef()); 205 // add in reverse order 206 parentDocsList.addAll(fromRoot); 207 Collections.reverse(parentDocsList); 208 209 return parentDocsList; 210 } 211 212 @Override 213 public DocumentModel getCurrentSuperSpace() { 214 if (currentSuperSpace == null && currentDocument != null) { 215 if (currentDocument.hasFacet(FacetNames.SUPER_SPACE)) { 216 currentSuperSpace = currentDocument; 217 } else if (documentManager != null) { 218 currentSuperSpace = documentManager.getSuperSpace(currentDocument); 219 } 220 } 221 return currentSuperSpace; 222 } 223 224 @Override 225 public void invalidateCurrentDocument() { 226 if (currentDocument != null) { 227 currentDocument = documentManager.getDocument(currentDocument.getRef()); 228 updateContextVariables(); 229 } 230 } 231 232 @Override 233 @BypassInterceptors 234 public DocumentModel getCurrentDomain() { 235 return currentDomain; 236 } 237 238 @Override 239 public void setCurrentDomain(DocumentModel domainDocModel) { 240 if (!checkIfUpdateNeeded(currentDomain, domainDocModel)) { 241 return; 242 } 243 244 currentDomain = domainDocModel; 245 Contexts.getEventContext().remove("currentDomain"); 246 247 if (domainDocModel == null) { 248 Events.instance().raiseEvent(EventNames.DOMAIN_SELECTION_CHANGED, currentDomain); 249 return; 250 } 251 252 if (currentDocument == null) { 253 setCurrentDocument(null); 254 } 255 256 // if we switched branch then realign currentDocument 257 if (currentDocumentParents != null 258 && !DocumentsListsUtils.isDocumentInList(domainDocModel, currentDocumentParents)) { 259 setCurrentDocument(domainDocModel); 260 } 261 262 Events.instance().raiseEvent(EventNames.DOMAIN_SELECTION_CHANGED, currentDomain); 263 } 264 265 protected boolean checkIfUpdateNeeded(DocumentModel ctxDoc, DocumentModel newDoc) { 266 if (log.isDebugEnabled()) { 267 log.debug(String.format("Check if update needed: compare context " + "doc '%s' to new doc '%s'", ctxDoc, 268 newDoc)); 269 } 270 if (ctxDoc == null && newDoc != null || ctxDoc != null && newDoc == null) { 271 return true; 272 } 273 if (ctxDoc == null && newDoc == null) { 274 return false; 275 } 276 if (log.isDebugEnabled()) { 277 log.debug(String.format( 278 "Check if update needed: compare cache key on " + "context doc '%s' with new doc '%s'", 279 ctxDoc.getCacheKey(), newDoc.getCacheKey())); 280 } 281 return !ctxDoc.getCacheKey().equals(newDoc.getCacheKey()); 282 } 283 284 @Override 285 public void saveCurrentDocument() { 286 if (currentDocument == null) { 287 // cannot call saveDocument with null arg => nasty stateful bean 288 // de-serialization error 289 throw new IllegalStateException("null currentDocument"); 290 } 291 currentDocument = documentManager.saveDocument(currentDocument); 292 documentManager.save(); 293 } 294 295 @Override 296 public List<PathElement> getCurrentPathList() { 297 if (parents == null) { 298 resetCurrentPath(); 299 } 300 return parents; 301 } 302 303 protected ServerContextBean getServerLocator() { 304 return (ServerContextBean) Component.getInstance("serverLocator"); 305 } 306 307 @Override 308 public RepositoryLocation getCurrentServerLocation() { 309 return getServerLocator().getCurrentServerLocation(); 310 } 311 312 /** 313 * @deprecated use getCurrentServerLocation() instead 314 */ 315 @Override 316 @Deprecated 317 public RepositoryLocation getSelectedServerLocation() { 318 return getServerLocator().getCurrentServerLocation(); 319 } 320 321 /** 322 * Switches to a new server location by updating the context and updating to the CoreSession (DocumentManager). 323 */ 324 @Override 325 public void setCurrentServerLocation(RepositoryLocation serverLocation) { 326 if (serverLocation == null) { 327 log.warn("Setting ServerLocation to null, is this normal ?"); 328 } 329 330 RepositoryLocation currentServerLocation = serverLocation; 331 getServerLocator().setRepositoryLocation(serverLocation); 332 resetCurrentContext(); 333 Contexts.getEventContext().set("currentServerLocation", currentServerLocation); 334 335 // update the documentManager 336 documentManager = null; 337 documentManager = getOrCreateDocumentManager(); 338 Events.instance().raiseEvent(EventNames.LOCATION_SELECTION_CHANGED); 339 340 DocumentModel rootDocument = documentManager.getRootDocument(); 341 if (documentManager.hasPermission(rootDocument.getRef(), SecurityConstants.READ)) { 342 currentDocument = rootDocument; 343 updateContextVariables(); 344 } 345 } 346 347 /** 348 * Returns the current documentManager if any or create a new session to the current location. 349 */ 350 @Override 351 public CoreSession getOrCreateDocumentManager() { 352 if (documentManager != null) { 353 return documentManager; 354 } 355 // protect for unexpected wrong cast 356 Object supposedDocumentManager = Contexts.lookupInStatefulContexts("documentManager"); 357 DocumentManagerBusinessDelegate documentManagerBD = null; 358 if (supposedDocumentManager != null) { 359 if (supposedDocumentManager instanceof DocumentManagerBusinessDelegate) { 360 documentManagerBD = (DocumentManagerBusinessDelegate) supposedDocumentManager; 361 } else { 362 log.error("Found the documentManager being " + supposedDocumentManager.getClass() 363 + " instead of DocumentManagerBusinessDelegate. This is wrong."); 364 } 365 } 366 if (documentManagerBD == null) { 367 // this is the first time we select the location, create a 368 // DocumentManagerBusinessDelegate instance 369 documentManagerBD = new DocumentManagerBusinessDelegate(); 370 Contexts.getConversationContext().set("documentManager", documentManagerBD); 371 } 372 documentManager = documentManagerBD.getDocumentManager(getCurrentServerLocation()); 373 return documentManager; 374 } 375 376 @Override 377 @BypassInterceptors 378 public DocumentModel getCurrentWorkspace() { 379 return currentWorkspace; 380 } 381 382 // Factories to make navigation related data 383 // available in the context 384 385 @Override 386 @Factory(value = "currentDocument", scope = EVENT) 387 public DocumentModel factoryCurrentDocument() { 388 return currentDocument; 389 } 390 391 @Override 392 @Factory(value = "changeableDocument", scope = EVENT) 393 public DocumentModel factoryChangeableDocument() { 394 return changeableDocument; 395 } 396 397 @Override 398 @Factory(value = "currentDomain", scope = EVENT) 399 public DocumentModel factoryCurrentDomain() { 400 return currentDomain; 401 } 402 403 @Override 404 @Factory(value = "currentWorkspace", scope = EVENT) 405 public DocumentModel factoryCurrentWorkspace() { 406 return currentWorkspace; 407 } 408 409 @Override 410 @Factory(value = "currentContentRoot", scope = EVENT) 411 public DocumentModel factoryCurrentContentRoot() { 412 return currentContentRoot; 413 } 414 415 // @Factory(value = "currentServerLocation", scope = EVENT) 416 @Override 417 public RepositoryLocation factoryCurrentServerLocation() { 418 return getCurrentServerLocation(); 419 } 420 421 @Override 422 @Factory(value = "currentSuperSpace", scope = EVENT) 423 public DocumentModel factoryCurrentSuperSpace() { 424 return getCurrentSuperSpace(); 425 } 426 427 public void setCurrentWorkspace(DocumentModel workspaceDocModel) { 428 429 if (!checkIfUpdateNeeded(currentWorkspace, workspaceDocModel)) { 430 return; 431 } 432 currentWorkspace = workspaceDocModel; 433 434 if (workspaceDocModel == null) { 435 return; 436 } 437 438 if (currentDocument == null) { 439 setCurrentDocument(workspaceDocModel); 440 return; 441 } 442 443 // if we switched branch then realign currentDocument 444 if (currentDocumentParents != null 445 && !DocumentsListsUtils.isDocumentInList(workspaceDocModel, currentDocumentParents)) { 446 setCurrentDocument(workspaceDocModel); 447 return; 448 } 449 } 450 451 @Override 452 public void updateDocumentContext(DocumentModel doc) { 453 setCurrentDocument(doc); 454 } 455 456 /** 457 * Updates variables according to hierarchy rules and to the new currentDocument. 458 */ 459 protected void updateContextVariables() { 460 461 // XXX flush method is not implemented for Event context :) 462 Contexts.getEventContext().set("currentDocument", currentDocument); 463 464 // Don't flush changeable document with a null id (NXP-10732) 465 if ((getChangeableDocument() != null) && (getChangeableDocument().getId() != null)) { 466 setChangeableDocument(null); 467 } 468 469 if (currentDocument == null) { 470 currentDocumentParents = null; 471 return; 472 } 473 474 DocumentRef ref = currentDocument.getRef(); 475 if (ref == null) { 476 throw new NuxeoException("DocumentRef is null for currentDocument: " + currentDocument.getName()); 477 } 478 // Recompute document parents 479 currentDocumentParents = documentManager.getParentDocuments(ref); 480 481 // iterate in reverse list order to go down the tree 482 // set all navigation variables according to docType 483 // => update to tree 484 String docType; 485 if (currentDocumentParents != null) { 486 for (int i = currentDocumentParents.size() - 1; i >= 0; i--) { 487 DocumentModel docModel = currentDocumentParents.get(i); 488 docType = docModel.getType(); 489 490 if (docType != null && hasSuperType(docType, "Workspace")) { 491 setCurrentWorkspace(docModel); 492 } 493 494 if (docType == null || hasSuperType(docType, "WorkspaceRoot") || hasSuperType(docType, "SectionRoot")) { 495 setCurrentContentRoot(docModel); 496 } 497 498 if (docType != null && hasSuperType(docType, "Domain")) { 499 setCurrentDomain(docModel); 500 } 501 } 502 } 503 504 // reinit lower tree 505 docType = currentDocument.getType(); 506 if (docType.equals("Root")) { 507 setCurrentDomain(null); 508 setCurrentContentRoot(null); 509 setCurrentWorkspace(null); 510 } else if (hasSuperType(docType, "Domain")) { 511 setCurrentDomain(currentDocument); 512 setCurrentContentRoot(null); 513 setCurrentWorkspace(null); 514 } else if (hasSuperType(docType, "WorkspaceRoot") || hasSuperType(docType, "SectionRoot")) { 515 setCurrentContentRoot(currentDocument); 516 setCurrentWorkspace(null); 517 } else if (hasSuperType(docType, "Workspace")) { 518 setCurrentWorkspace(currentDocument); 519 } 520 521 // lazily recompute some fields 522 currentSuperSpace = null; 523 parents = null; 524 } 525 526 private boolean hasSuperType(String targetDocType, String superType) { 527 SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class); 528 return schemaManager.hasSuperType(targetDocType, superType); 529 } 530 531 @Override 532 public void resetCurrentContext() { 533 // flush event context 534 Context eventContext = Contexts.getEventContext(); 535 eventContext.remove("currentDocument"); 536 eventContext.remove("changeableDocument"); 537 eventContext.remove("currentDocumentChildren"); 538 eventContext.remove("currentDomain"); 539 eventContext.remove("currentServerLocation"); 540 eventContext.remove("currentWorkspace"); 541 eventContext.remove("currentContentRoot"); 542 eventContext.remove("currentSuperSpace"); 543 } 544 545 // XXX AT: we should let each action listener raise specific events 546 // (edition) and decide what's the next view, let's just handle context 547 // setting and redirection + this should be callable from templates i.e use 548 // view as a string. 549 @Override 550 public String getActionResult(DocumentModel doc, UserAction action) { 551 552 TypesTool typesTool = (TypesTool) Component.getInstance("typesTool"); 553 554 if (doc == null) { 555 return null; 556 } 557 if (UserAction.CREATE == action) { 558 // the given document is a changeable document 559 setChangeableDocument(doc); 560 } else { 561 updateDocumentContext(doc); 562 } 563 564 final Type type = typesTool.getType(doc.getType()); 565 566 final String result; 567 if (UserAction.VIEW == action) { 568 assert currentDocument != null; 569 EventManager.raiseEventsOnDocumentSelected(currentDocument); 570 result = ApplicationControllerHelper.getPageOnSelectedDocumentType(type); 571 } else if (UserAction.EDIT == action) { 572 throw new UnsupportedOperationException("for action " + action); 573 } else if (UserAction.AFTER_EDIT == action) { 574 assert currentDocument != null; 575 EventManager.raiseEventsOnDocumentChange(currentDocument); 576 result = ApplicationControllerHelper.getPageOnEditedDocumentType(type); 577 } else if (UserAction.CREATE == action) { 578 EventManager.raiseEventsOnDocumentCreate(changeableDocument); 579 result = ApplicationControllerHelper.getPageOnCreateDocumentType(type); 580 } else if (UserAction.AFTER_CREATE == action) { 581 assert currentDocument != null; 582 EventManager.raiseEventsOnDocumentSelected(currentDocument); 583 result = ApplicationControllerHelper.getPageOnCreatedDocumentType(type); 584 } else if (UserAction.GO_HOME == action) { 585 EventManager.raiseEventsOnGoingHome(); 586 result = "home"; 587 } else { 588 log.error(String.format("Unknown action '%s' for navigation on " + "document '%s' with title '%s': ", 589 action.name(), doc.getId(), doc.getTitle())); 590 result = null; 591 } 592 return result; 593 } 594 595 @Override 596 public String goHome() { 597 resetCurrentContext(); 598 EventManager.raiseEventsOnGoingHome(); 599 return "home"; 600 } 601 602 @Override 603 public String goBack() { 604 if (currentDocument != null) { 605 setChangeableDocument(null); 606 return navigateToDocument(currentDocument); 607 } else { 608 return goHome(); 609 } 610 } 611 612 @Override 613 public String navigateToId(String documentId) { 614 if (documentManager == null) { 615 throw new IllegalStateException("documentManager not initialized"); 616 } 617 DocumentRef docRef = new IdRef(documentId); 618 final DocumentModel doc = documentManager.getDocument(docRef); 619 return navigateToDocument(doc, "view"); 620 } 621 622 @Override 623 public String navigateToRef(DocumentRef docRef) { 624 if (documentManager == null) { 625 throw new IllegalStateException("documentManager not initialized"); 626 } 627 628 final DocumentModel doc = documentManager.getDocument(docRef); 629 630 return navigateToDocument(doc, "view"); 631 } 632 633 @Override 634 public String navigateToDocument(DocumentModel doc) { 635 return navigateToDocument(doc, "view"); 636 } 637 638 @Override 639 public String navigateToDocument(DocumentModel doc, String viewId) { 640 if (doc != null) { 641 updateDocumentContext(doc); 642 } 643 assert currentDocument != null; 644 TypeInfo typeInfo = currentDocument.getAdapter(TypeInfo.class); 645 String chosenView = null; 646 if (typeInfo != null) { 647 String defaultView = typeInfo.getDefaultView(); 648 // hardcoded default views 649 if ("view".equals(viewId)) { 650 chosenView = defaultView; 651 } else if ("create".equals(viewId)) { 652 chosenView = typeInfo.getCreateView(); 653 } else if ("edit".equals(viewId)) { 654 chosenView = typeInfo.getEditView(); 655 } else { 656 chosenView = typeInfo.getView(viewId); 657 } 658 if (chosenView == null) { 659 chosenView = defaultView; 660 } 661 } 662 663 Events.instance().raiseEvent(NAVIGATE_TO_DOCUMENT, currentDocument); 664 665 return chosenView; 666 } 667 668 @Override 669 public String navigateToDocumentWithView(DocumentModel doc, String viewId) { 670 return navigateToDocument(doc, viewId); 671 } 672 673 @Override 674 public String navigateToDocument(DocumentModel docModel, VersionModel versionModel) { 675 DocumentModel docVersion = documentManager.getDocumentWithVersion(docModel.getRef(), versionModel); 676 return navigateToDocument(docVersion); 677 } 678 679 @Override 680 public void selectionChanged() { 681 resetCurrentPath(); 682 } 683 684 @Override 685 public String getCurrentDocumentUrl() { 686 if (currentDocument == null) { 687 log.error("current document is null"); 688 return null; 689 } 690 return DocumentLocator.getDocumentUrl(getCurrentServerLocation(), currentDocument.getRef()); 691 } 692 693 @Override 694 public String getCurrentDocumentFullUrl() { 695 if (currentDocument == null) { 696 log.error("current document is null"); 697 return null; 698 } 699 return DocumentLocator.getFullDocumentUrl(getCurrentServerLocation(), currentDocument.getRef()); 700 } 701 702 // start a new conversation if needed, join main if possible 703 @Override 704 @Begin(id = "#{conversationIdGenerator.currentOrNewMainConversationId}", join = true) 705 public String navigateTo(RepositoryLocation serverLocation, DocumentRef docRef) { 706 // re-connect only if there is another repository specified 707 if (!serverLocation.equals(getCurrentServerLocation())) { 708 setCurrentServerLocation(serverLocation); 709 } 710 return navigateToRef(docRef); 711 } 712 713 // start a new conversation if needed, join main if possible 714 @Override 715 @Begin(id = "#{conversationIdGenerator.currentOrNewMainConversationId}", join = true) 716 public String navigateToURL(String documentUrl) { 717 final DocumentLocation docLoc; 718 try { 719 docLoc = DocumentLocator.parseDocRef(documentUrl); 720 } catch (BadDocumentUriException e) { 721 log.error("Cannot get document ref from uri " + documentUrl + ". " + e.getMessage(), e); 722 return null; 723 } 724 final DocumentRef docRef = docLoc.getDocRef(); 725 RepositoryLocation repLoc = new RepositoryLocation(docLoc.getServerName()); 726 return navigateTo(repLoc, docRef); 727 } 728 729 @RequestParameter 730 String docRef; 731 732 /** 733 * @see NavigationContext#navigateToURL() 734 */ 735 @Override 736 @Begin(id = "#{conversationIdGenerator.currentOrNewMainConversationId}", join = true) 737 public String navigateToURL() { 738 if (docRef == null) { 739 return null; 740 } 741 return navigateToURL(docRef); 742 } 743 744 protected void resetCurrentPath() { 745 final String logPrefix = "<resetCurrentPath> "; 746 747 parents = new ArrayList<PathElement>(); 748 749 if (documentManager == null) { 750 log.error(logPrefix + "documentManager not initialized"); 751 return; 752 } 753 754 if (currentDocument != null) { 755 if (currentDocument.isVersion()) { 756 DocumentModel sourceDocument = documentManager.getSourceDocument(currentDocument.getRef()); 757 758 List<DocumentModel> parentList = documentManager.getParentDocuments(sourceDocument.getRef()); 759 for (DocumentModel docModel : parentList) { 760 parents.add(getDocumentPathElement(docModel)); 761 } 762 763 parents.add(new ArchivedVersionsPathElement(sourceDocument)); 764 parents.add(new VersionDocumentPathElement(currentDocument)); 765 } else { 766 if (currentDocumentParents != null) { 767 for (DocumentModel docModel : currentDocumentParents) { 768 parents.add(getDocumentPathElement(docModel)); 769 } 770 } 771 } 772 } 773 } 774 775 protected PathElement getDocumentPathElement(DocumentModel doc) { 776 if (doc != null && doc.hasFacet(FacetNames.HIDDEN_IN_NAVIGATION)) { 777 return new HiddenDocumentPathElement(doc); 778 } 779 return new DocumentPathElement(doc); 780 } 781 782 @Override 783 public DocumentModel getCurrentContentRoot() { 784 return currentContentRoot; 785 } 786 787 @Override 788 public void setCurrentContentRoot(DocumentModel crDocumentModel) { 789 790 if (!checkIfUpdateNeeded(currentContentRoot, crDocumentModel)) { 791 return; 792 } 793 currentContentRoot = crDocumentModel; 794 Contexts.getEventContext().remove("currentContentRoot"); 795 796 if (crDocumentModel == null) { 797 return; 798 } 799 800 if (currentDocument == null) { 801 setCurrentDocument(null); 802 return; 803 } 804 805 // if we switched branch then realign currentDocument 806 if (currentDocumentParents != null 807 && !DocumentsListsUtils.isDocumentInList(crDocumentModel, currentDocumentParents)) { 808 setCurrentDocument(crDocumentModel); 809 } 810 } 811 812}