/*
* (C) Copyright 2007-2013 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Narcis Paslaru
* Florent Guillaume
* Thierry Martins
* Thomas Roger
*/
package org.nuxeo.ecm.platform.publisher.web;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.faces.context.FacesContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.core.Events;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.international.StatusMessage;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentRef;
import org.nuxeo.ecm.core.api.IdRef;
import org.nuxeo.ecm.core.api.NuxeoException;
import org.nuxeo.ecm.core.api.PathRef;
import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner;
import org.nuxeo.ecm.core.api.event.CoreEventConstants;
import org.nuxeo.ecm.core.api.event.DocumentEventCategories;
import org.nuxeo.ecm.core.api.impl.DocumentLocationImpl;
import org.nuxeo.ecm.core.api.security.SecurityConstants;
import org.nuxeo.ecm.core.event.Event;
import org.nuxeo.ecm.core.event.EventProducer;
import org.nuxeo.ecm.core.event.impl.DocumentEventContext;
import org.nuxeo.ecm.core.schema.FacetNames;
import org.nuxeo.ecm.core.schema.SchemaManager;
import org.nuxeo.ecm.platform.publisher.api.PublicationNode;
import org.nuxeo.ecm.platform.publisher.api.PublicationTree;
import org.nuxeo.ecm.platform.publisher.api.PublishedDocument;
import org.nuxeo.ecm.platform.publisher.api.PublisherService;
import org.nuxeo.ecm.platform.publisher.api.PublishingEvent;
import org.nuxeo.ecm.platform.ui.web.util.ComponentUtils;
import org.nuxeo.ecm.webapp.documentsLists.DocumentsListsManager;
import org.nuxeo.ecm.webapp.helpers.EventManager;
import org.nuxeo.ecm.webapp.helpers.EventNames;
import org.nuxeo.runtime.api.Framework;
/**
* This Seam bean manages the publishing tab.
*
* @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
*/
@Name("publishActions")
@Scope(ScopeType.CONVERSATION)
public class PublishActionsBean extends AbstractPublishActions implements Serializable {
public static class PublicationTreeInformation {
private final String name;
private final String title;
public PublicationTreeInformation(String treeName, String treeTitle) {
this.name = treeName;
this.title = treeTitle;
}
public String getName() {
return name;
}
public String getTitle() {
return title;
}
}
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(PublishActionsBean.class);
/**
* @since 7.3
*/
public static final List<String> TREE_TYPES_TO_FILTER = Arrays.asList("RootSectionsPublicationTree", "RenditionPublicationCoreTree");
@In(create = true)
protected transient DocumentsListsManager documentsListsManager;
@In(create = true, required = false)
protected transient FacesMessages facesMessages;
protected transient PublisherService publisherService;
protected String currentPublicationTreeNameForPublishing;
protected PublicationTree currentPublicationTree;
protected String publishingComment;
protected static Set<String> sectionTypes;
protected Map<String, String> publicationParameters = new HashMap<>();
@Create
public void create() {
publisherService = Framework.getService(PublisherService.class);
}
@Destroy
public void destroy() {
if (currentPublicationTree != null) {
currentPublicationTree.release();
currentPublicationTree = null;
}
}
protected Map<String, String> filterEmptyTrees(Map<String, String> trees) {
Map<String, String> filteredTrees = new HashMap<>();
List<String> prefilteredTrees = filterEmptyTrees(trees.keySet());
for (String ptree : prefilteredTrees) {
filteredTrees.put(ptree, trees.get(ptree));
}
return filteredTrees;
}
protected List<String> filterEmptyTrees(Collection<String> trees) {
List<String> filteredTrees = new ArrayList<>();
for (String tree : trees) {
PublicationTree pTree = publisherService.getPublicationTree(tree, documentManager, null,
navigationContext.getCurrentDocument());
if (pTree != null) {
if (TREE_TYPES_TO_FILTER.contains(pTree.getTreeType())) {
if (pTree.getChildrenNodes().size() > 0) {
filteredTrees.add(tree);
}
} else {
filteredTrees.add(tree);
}
}
}
return filteredTrees;
}
@Factory(value = "availablePublicationTrees", scope = ScopeType.EVENT)
public List<PublicationTreeInformation> getAvailablePublicationTrees() {
Map<String, String> trees = publisherService.getAvailablePublicationTrees();
// remove empty trees
trees = filterEmptyTrees(trees);
List<PublicationTreeInformation> treesInformation = new ArrayList<>();
for (Map.Entry<String, String> entry : trees.entrySet()) {
treesInformation.add(new PublicationTreeInformation(entry.getKey(), entry.getValue()));
}
return treesInformation;
}
public String doPublish(PublicationNode publicationNode) {
PublicationTree tree = getCurrentPublicationTreeForPublishing();
return doPublish(tree, publicationNode);
}
public String doPublish(PublicationTree tree, PublicationNode publicationNode) {
if (tree == null) {
return null;
}
DocumentModel currentDocument = navigationContext.getCurrentDocument();
PublishedDocument publishedDocument;
try {
publishedDocument = tree.publish(currentDocument, publicationNode, publicationParameters);
} catch (NuxeoException e) {
log.error(e, e);
facesMessages.add(StatusMessage.Severity.ERROR, messages.get(e.getMessage()));
return null;
}
FacesContext context = FacesContext.getCurrentInstance();
if (publishedDocument.isPending()) {
String comment = ComponentUtils.translate(context, "publishing.waiting", publicationNode.getPath(),
tree.getConfigName());
// Log event on live version
notifyEvent(PublishingEvent.documentWaitingPublication.name(), null, comment, null, currentDocument);
Events.instance().raiseEvent(EventNames.DOCUMENT_SUBMITED_FOR_PUBLICATION);
facesMessages.add(StatusMessage.Severity.INFO, messages.get("document_submitted_for_publication"),
messages.get(currentDocument.getType()));
} else {
String comment = ComponentUtils.translate(context, "publishing.done", publicationNode.getPath(),
tree.getConfigName());
// Log event on live version
notifyEvent(PublishingEvent.documentPublished.name(), null, comment, null, currentDocument);
Events.instance().raiseEvent(EventNames.DOCUMENT_PUBLISHED);
// publish may checkin the document -> change
Events.instance().raiseEvent(EventNames.DOCUMENT_CHANGED);
facesMessages.add(StatusMessage.Severity.INFO, messages.get("document_published"),
messages.get(currentDocument.getType()));
}
navigationContext.invalidateCurrentDocument();
currentPublicationTree = null;
resetCache();
return null;
}
/**
* @since 5.9.3
*/
protected void resetCache() {
Contexts.getEventContext().remove("availablePublicationTrees");
Contexts.getEventContext().remove("publishedDocuments");
}
public void setCurrentPublicationTreeNameForPublishing(String currentPublicationTreeNameForPublishing)
{
this.currentPublicationTreeNameForPublishing = currentPublicationTreeNameForPublishing;
if (currentPublicationTree != null) {
currentPublicationTree.release();
currentPublicationTree = null;
}
currentPublicationTree = getCurrentPublicationTreeForPublishing();
}
public String getCurrentPublicationTreeNameForPublishing() {
if (currentPublicationTreeNameForPublishing == null) {
List<String> publicationTrees = new ArrayList<>(publisherService.getAvailablePublicationTree());
publicationTrees = filterEmptyTrees(publicationTrees);
if (!publicationTrees.isEmpty()) {
currentPublicationTreeNameForPublishing = publicationTrees.get(0);
}
}
return currentPublicationTreeNameForPublishing;
}
/**
* Returns a list of publication trees.
* <p>
* Needed on top of {@link #getCurrentPublicationTreeForPublishing()} because RichFaces tree now requires roots to
* be a list.
*
* @since 6.0
*/
public List<PublicationTree> getCurrentPublicationTreesForPublishing() {
List<PublicationTree> trees = new ArrayList<>();
PublicationTree tree = getCurrentPublicationTreeForPublishing();
if (tree != null) {
trees.add(tree);
}
return trees;
}
public PublicationTree getCurrentPublicationTreeForPublishing() {
if (currentPublicationTree == null) {
if (getCurrentPublicationTreeNameForPublishing() == null) {
return currentPublicationTree;
}
currentPublicationTree = publisherService.getPublicationTree(currentPublicationTreeNameForPublishing,
documentManager, null, navigationContext.getCurrentDocument());
}
return currentPublicationTree;
}
public String getCurrentPublicationTreeIconExpanded() {
PublicationTree tree = getCurrentPublicationTreeForPublishing();
return tree != null ? tree.getIconExpanded() : "";
}
public String getCurrentPublicationTreeIconCollapsed() {
PublicationTree tree = getCurrentPublicationTreeForPublishing();
return tree != null ? tree.getIconCollapsed() : "";
}
@Factory(value = "publishedDocuments", scope = ScopeType.EVENT)
public List<PublishedDocument> getPublishedDocuments() {
PublicationTree tree = getCurrentPublicationTreeForPublishing();
if (tree == null) {
return Collections.emptyList();
}
DocumentModel currentDocument = navigationContext.getCurrentDocument();
return tree.getExistingPublishedDocument(new DocumentLocationImpl(currentDocument));
}
public List<PublishedDocument> getPublishedDocumentsFor(String treeName) {
if (treeName == null || "".equals(treeName)) {
return null;
}
DocumentModel currentDocument = navigationContext.getCurrentDocument();
PublicationTree tree = publisherService.getPublicationTree(treeName, documentManager, null);
return tree.getExistingPublishedDocument(new DocumentLocationImpl(currentDocument));
}
public String unPublish(PublishedDocument publishedDocument) {
PublicationTree tree = getCurrentPublicationTreeForPublishing();
if (tree != null) {
tree.unpublish(publishedDocument);
}
// raise event without the container document as user may not have read
// rights on it
Events.instance().raiseEvent(EventNames.DOCUMENT_CHILDREN_CHANGED);
resetCache();
return null;
}
public String rePublish(PublishedDocument publishedDocument) {
PublicationTree tree = getCurrentPublicationTreeForPublishing();
if (tree == null) {
log.error("Publication tree is null - cannot republish");
facesMessages.add(StatusMessage.Severity.ERROR, messages.get("error.document_republished"));
return null;
}
PublicationNode node = tree.getNodeByPath(publishedDocument.getParentPath());
return doPublish(tree, node);
}
public boolean canPublishTo(PublicationNode publicationNode) {
DocumentModel doc = navigationContext.getCurrentDocument();
if (doc == null || documentManager.getLockInfo(doc.getRef()) != null) {
return false;
}
PublicationTree tree = getCurrentPublicationTreeForPublishing();
return tree != null ? tree.canPublishTo(publicationNode) : false;
}
public boolean canUnpublish(PublishedDocument publishedDocument) {
PublicationTree tree = getCurrentPublicationTreeForPublishing();
return tree != null ? tree.canUnpublish(publishedDocument) : false;
}
public boolean canRepublish(PublishedDocument publishedDocument) {
if (!canUnpublish(publishedDocument)) {
return false;
}
DocumentModel doc = navigationContext.getCurrentDocument();
// version label is different, what means it is a previous version
if (!publishedDocument.getSourceVersionLabel().equals(doc.getVersionLabel())) {
return true;
}
// in case it is the same version, we have to check if the current
// document has been modified since last publishing
if (doc.isDirty()) {
return true;
}
return false;
}
public boolean isPublishedDocument() {
return publisherService.isPublishedDocument(navigationContext.getCurrentDocument());
}
public boolean canManagePublishing() {
PublicationTree tree = publisherService.getPublicationTreeFor(navigationContext.getCurrentDocument(),
documentManager);
PublishedDocument publishedDocument = tree.wrapToPublishedDocument(navigationContext.getCurrentDocument());
return tree.canManagePublishing(publishedDocument);
}
public boolean hasValidationTask() {
PublicationTree tree = publisherService.getPublicationTreeFor(navigationContext.getCurrentDocument(),
documentManager);
PublishedDocument publishedDocument = tree.wrapToPublishedDocument(navigationContext.getCurrentDocument());
return tree.hasValidationTask(publishedDocument);
}
public boolean isPending() {
PublicationTree tree = publisherService.getPublicationTreeFor(navigationContext.getCurrentDocument(),
documentManager);
PublishedDocument publishedDocument = tree.wrapToPublishedDocument(navigationContext.getCurrentDocument());
return publishedDocument.isPending();
}
public String getPublishingComment() {
return publishingComment;
}
public void setPublishingComment(String publishingComment) {
this.publishingComment = publishingComment;
}
public class ApproverWithoutRestriction extends UnrestrictedSessionRunner {
public DocumentModel sourceDocument;
public DocumentModel liveDocument;
public String comment;
public PublishedDocument doc;
public ApproverWithoutRestriction(PublishedDocument doc, String comment, CoreSession session) {
super(session);
this.doc = doc;
this.comment = comment;
}
@Override
public void run() {
sourceDocument = session.getDocument(doc.getSourceDocumentRef());
// soft dependency on Rendition system
if (sourceDocument.hasFacet("Rendition")) {
String uid = (String) sourceDocument.getPropertyValue("rend:sourceId");
liveDocument = session.getDocument(new IdRef(uid));
} else {
liveDocument = session.getSourceDocument(sourceDocument.getRef());
}
sendApprovalEventToSourceDocument(session, sourceDocument, liveDocument, comment);
}
protected void sendApprovalEventToSourceDocument(CoreSession session, DocumentModel sourceDocument,
DocumentModel liveVersion, String comment) {
notifyEvent(session, PublishingEvent.documentPublicationApproved.name(), null, comment, null,
sourceDocument);
if (!sourceDocument.getRef().equals(liveVersion.getRef())) {
notifyEvent(session, PublishingEvent.documentPublicationApproved.name(), null, comment, null,
liveVersion);
}
}
}
public String approveDocument() {
DocumentModel currentDocument = navigationContext.getCurrentDocument();
PublicationTree tree = publisherService.getPublicationTreeFor(currentDocument, documentManager);
PublishedDocument publishedDocument = tree.wrapToPublishedDocument(currentDocument);
tree.validatorPublishDocument(publishedDocument, publishingComment);
FacesContext context = FacesContext.getCurrentInstance();
String comment = publishingComment != null && publishingComment.length() > 0 ? ComponentUtils.translate(
context, "publishing.approved.with.comment", publishedDocument.getParentPath(), tree.getConfigName(),
publishingComment) : ComponentUtils.translate(context, "publishing.approved.without.comment",
publishedDocument.getParentPath(), tree.getConfigName());
ApproverWithoutRestriction approver = new ApproverWithoutRestriction(publishedDocument, comment,
documentManager);
if (documentManager.hasPermission(publishedDocument.getSourceDocumentRef(), SecurityConstants.WRITE)) {
approver.run();
} else {
approver.runUnrestricted();
}
Events.instance().raiseEvent(EventNames.DOCUMENT_PUBLISHED);
Events.instance().raiseEvent(EventNames.DOCUMENT_PUBLICATION_APPROVED);
return null;
}
public String rejectDocument() {
if (publishingComment == null || "".equals(publishingComment)) {
facesMessages.addToControl("publishingComment", StatusMessage.Severity.ERROR,
messages.get("label.publishing.reject.user.comment.mandatory"));
return null;
}
DocumentModel currentDocument = navigationContext.getCurrentDocument();
PublicationTree tree = publisherService.getPublicationTreeFor(currentDocument, documentManager);
PublishedDocument publishedDocument = tree.wrapToPublishedDocument(currentDocument);
tree.validatorRejectPublication(publishedDocument, publishingComment);
FacesContext context = FacesContext.getCurrentInstance();
String comment = publishingComment != null && publishingComment.length() > 0 ? ComponentUtils.translate(
context, "publishing.rejected.with.comment", publishedDocument.getParentPath(), tree.getConfigName(),
publishingComment) : ComponentUtils.translate(context, "publishing.rejected.without.comment",
publishedDocument.getParentPath(), tree.getConfigName());
RejectWithoutRestrictionRunner runner = new RejectWithoutRestrictionRunner(documentManager, publishedDocument,
comment);
if (documentManager.hasPermission(publishedDocument.getSourceDocumentRef(), SecurityConstants.READ)) {
runner.run();
} else {
runner.runUnrestricted();
}
Events.instance().raiseEvent(EventNames.DOCUMENT_PUBLICATION_REJECTED);
return navigationContext.navigateToRef(navigationContext.getCurrentDocument().getParentRef());
}
public void unpublishDocumentsFromCurrentSelection() {
if (!documentsListsManager.isWorkingListEmpty(DocumentsListsManager.CURRENT_DOCUMENT_SECTION_SELECTION)) {
unpublish(documentsListsManager.getWorkingList(DocumentsListsManager.CURRENT_DOCUMENT_SECTION_SELECTION));
} else {
log.debug("No selectable Documents in context to process unpublish on...");
}
log.debug("Unpublish the selected document(s) ...");
}
protected void unpublish(List<DocumentModel> documentModels) {
for (DocumentModel documentModel : documentModels) {
PublicationTree tree = publisherService.getPublicationTreeFor(documentModel, documentManager);
PublishedDocument publishedDocument = tree.wrapToPublishedDocument(documentModel);
tree.unpublish(publishedDocument);
}
Events.instance().raiseEvent(EventNames.DOCUMENT_CHILDREN_CHANGED);
Object[] params = { documentModels.size() };
// remove from the current selection list
documentsListsManager.resetWorkingList(DocumentsListsManager.CURRENT_DOCUMENT_SECTION_SELECTION);
facesMessages.add(StatusMessage.Severity.INFO, messages.get("n_unpublished_docs"), params);
}
public boolean isRemotePublishedDocument(PublishedDocument publishedDocument) {
return false;
}
public boolean isFileSystemPublishedDocument(PublishedDocument publishedDocument) {
return false;
}
public boolean isLocalPublishedDocument(PublishedDocument publishedDocument) {
return true;
}
public String publishWorkList() {
return publishDocumentList(DocumentsListsManager.DEFAULT_WORKING_LIST);
}
public DocumentModel getDocumentModelFor(String path) {
DocumentRef docRef = new PathRef(path);
if (documentManager.exists(docRef) && hasReadRight(path)) {
return documentManager.getDocument(docRef);
}
return null;
}
public boolean hasReadRight(String documentPath) {
return documentManager.hasPermission(new PathRef(documentPath), SecurityConstants.READ);
}
public String getFormattedPath(String path) {
DocumentModel docModel = getDocumentModelFor(path);
return docModel != null ? getFormattedPath(docModel) : path;
}
public String publishDocumentList(String listName) {
List<DocumentModel> docs2Publish = documentsListsManager.getWorkingList(listName);
DocumentModel target = navigationContext.getCurrentDocument();
if (!getSectionTypes().contains(target.getType())) {
return null;
}
PublicationNode targetNode = publisherService.wrapToPublicationNode(target, documentManager);
if (targetNode == null) {
return null;
}
int nbPublishedDocs = 0;
for (DocumentModel doc : docs2Publish) {
if (!documentManager.hasPermission(doc.getRef(), SecurityConstants.READ_PROPERTIES)) {
continue;
}
if (doc.isProxy()) {
// TODO copy also copies security. just recreate a proxy.
documentManager.copy(doc.getRef(), target.getRef(), doc.getName());
nbPublishedDocs++;
} else {
if (doc.hasFacet(FacetNames.PUBLISHABLE)) {
publisherService.publish(doc, targetNode);
nbPublishedDocs++;
} else {
log.info("Attempted to publish non-publishable document " + doc.getTitle());
}
}
}
Object[] params = { nbPublishedDocs };
facesMessages.add(StatusMessage.Severity.INFO, "#0 " + messages.get("n_published_docs"), params);
if (nbPublishedDocs < docs2Publish.size()) {
facesMessages.add(StatusMessage.Severity.WARN, messages.get("selection_contains_non_publishable_docs"));
}
EventManager.raiseEventsOnDocumentChildrenChange(target);
return null;
}
public Set<String> getSectionTypes() {
if (sectionTypes == null) {
sectionTypes = getTypeNamesForFacet(FacetNames.PUBLISH_SPACE);
if (sectionTypes == null) {
sectionTypes = new HashSet<>();
}
}
return sectionTypes;
}
protected static Set<String> getTypeNamesForFacet(String facetName) {
SchemaManager schemaManager = Framework.getService(SchemaManager.class);
Set<String> publishRoots = schemaManager.getDocumentTypeNamesForFacet(facetName);
if (publishRoots == null || publishRoots.isEmpty()) {
return null;
}
return publishRoots;
}
public Map<String, String> getPublicationParameters() {
return publicationParameters;
}
public void notifyEvent(String eventId, Map<String, Serializable> properties, String comment, String category,
DocumentModel dm) {
notifyEvent(documentManager, eventId, properties, comment, category, dm);
}
public static void notifyEvent(CoreSession session, String eventId, Map<String, Serializable> properties,
String comment, String category, DocumentModel dm) {
// Default category
if (category == null) {
category = DocumentEventCategories.EVENT_DOCUMENT_CATEGORY;
}
if (properties == null) {
properties = new HashMap<>();
}
properties.put(CoreEventConstants.REPOSITORY_NAME, session.getRepositoryName());
properties.put(CoreEventConstants.SESSION_ID, session.getSessionId());
properties.put(CoreEventConstants.DOC_LIFE_CYCLE, dm.getCurrentLifeCycleState());
DocumentEventContext ctx = new DocumentEventContext(session, session.getPrincipal(), dm);
ctx.setProperties(properties);
ctx.setComment(comment);
ctx.setCategory(category);
EventProducer evtProducer = Framework.getService(EventProducer.class);
Event event = ctx.newEvent(eventId);
evtProducer.fireEvent(event);
}
public String getDomainName(String treeName) {
PublicationTree tree = publisherService.getPublicationTree(treeName, documentManager, null);
Map<String, String> parameters = publisherService.getParametersFor(tree.getConfigName());
String domainName = parameters.get(PublisherService.DOMAIN_NAME_KEY);
return domainName != null ? " (" + domainName + ")" : "";
}
@Observer(value = { EventNames.DOCUMENT_SELECTION_CHANGED }, create = false)
@BypassInterceptors
public void documentChanged() {
currentPublicationTreeNameForPublishing = null;
currentPublicationTree = null;
publishingComment = null;
}
/**
* @since 9.2
*/
public void reset() {
navigationContext.invalidateCurrentDocument();
currentPublicationTreeNameForPublishing = null;
currentPublicationTree = null;
}
class RejectWithoutRestrictionRunner extends UnrestrictedSessionRunner {
PublishedDocument publishedDocument;
DocumentModel sourceDocument;
DocumentModel liveDocument;
String comment;
DocumentModel liveVersion;
public RejectWithoutRestrictionRunner(CoreSession session, PublishedDocument publishedDocument, String comment) {
super(session);
this.publishedDocument = publishedDocument;
this.comment = comment;
}
@Override
public void run() {
sourceDocument = session.getDocument(publishedDocument.getSourceDocumentRef());
String sourceId = sourceDocument.getSourceId();
// source may be null if the version is placeless (rendition)
liveVersion = sourceId == null ? null : session.getDocument(new IdRef(sourceId));
notifyRejectToSourceDocument();
}
private void notifyRejectToSourceDocument() {
notifyEvent(PublishingEvent.documentPublicationRejected.name(), null, comment, null, sourceDocument);
if (liveVersion != null && !sourceDocument.getRef().equals(liveVersion.getRef())) {
notifyEvent(PublishingEvent.documentPublicationRejected.name(), null, comment, null, liveVersion);
}
}
}
}