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