001/* 002 * (C) Copyright 2009 Nuxeo SA (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 * arussel 016 */ 017package org.nuxeo.ecm.platform.routing.core.impl; 018 019import java.io.Serializable; 020import java.util.ArrayList; 021import java.util.List; 022import java.util.Map; 023 024import org.nuxeo.ecm.core.api.CoreSession; 025import org.nuxeo.ecm.core.api.DocumentModel; 026import org.nuxeo.ecm.core.api.DocumentModelList; 027import org.nuxeo.ecm.core.api.DocumentRef; 028import org.nuxeo.ecm.core.api.IdRef; 029import org.nuxeo.ecm.core.api.UnrestrictedSessionRunner; 030import org.nuxeo.ecm.core.api.security.ACE; 031import org.nuxeo.ecm.core.api.security.ACL; 032import org.nuxeo.ecm.core.api.security.ACP; 033import org.nuxeo.ecm.core.api.security.SecurityConstants; 034import org.nuxeo.ecm.core.api.security.impl.ACPImpl; 035import org.nuxeo.ecm.platform.routing.api.DocumentRoute; 036import org.nuxeo.ecm.platform.routing.api.DocumentRouteElement; 037import org.nuxeo.ecm.platform.routing.api.DocumentRouteStep; 038import org.nuxeo.ecm.platform.routing.api.DocumentRoutingConstants; 039import org.nuxeo.runtime.api.Framework; 040 041/** 042 * @author arussel 043 */ 044public class DocumentRouteElementImpl implements DocumentRouteElement, DocumentRouteStep { 045 046 private static final long serialVersionUID = 1L; 047 048 protected DocumentModel document; 049 050 protected ElementRunner runner; 051 052 public DocumentRouteElementImpl(DocumentModel doc, ElementRunner runner) { 053 this.document = doc; 054 this.runner = runner; 055 } 056 057 @Override 058 public DocumentModelList getAttachedDocuments(CoreSession session) { 059 List<String> docIds = getDocumentRoute(session).getAttachedDocuments(); 060 List<DocumentRef> refs = new ArrayList<DocumentRef>(); 061 for (String id : docIds) { 062 refs.add(new IdRef(id)); 063 } 064 return session.getDocuments(refs.toArray(new DocumentRef[] {})); 065 } 066 067 @Override 068 public void run(CoreSession session) { 069 runner.run(session, this); 070 } 071 072 @Override 073 public void run(CoreSession session, Map<String, Serializable> map) { 074 runner.run(session, this, map); 075 } 076 077 @Override 078 public void resume(CoreSession session, String nodeId, String taskId, Map<String, Object> data, String status) { 079 runner.resume(session, this, nodeId, taskId, data, status); 080 } 081 082 @Override 083 public DocumentRoute getDocumentRoute(CoreSession session) { 084 DocumentModel parent = document; 085 while (true) { 086 if (parent.hasFacet(DocumentRoutingConstants.DOCUMENT_ROUTE_DOCUMENT_FACET)) { 087 break; 088 } 089 parent = session.getParentDocument(parent.getRef()); 090 } 091 return parent.getAdapter(DocumentRoute.class); 092 } 093 094 @Override 095 public DocumentModel getDocument() { 096 return document; 097 } 098 099 protected Object getProperty(String propertyName) { 100 return document.getPropertyValue(propertyName); 101 } 102 103 @Override 104 public String getName() { 105 return getDocument().getName(); 106 } 107 108 /** 109 * @since 7.2 110 */ 111 @Override 112 public String getTitle() { 113 return (String) getProperty(DocumentRoutingConstants.TITLE_PROPERTY_NAME); 114 } 115 116 @Override 117 public boolean isValidated() { 118 return checkLifeCycleState(ElementLifeCycleState.validated); 119 } 120 121 @Override 122 public boolean isReady() { 123 return checkLifeCycleState(ElementLifeCycleState.ready); 124 } 125 126 @Override 127 public boolean isDone() { 128 return checkLifeCycleState(ElementLifeCycleState.done); 129 } 130 131 protected boolean checkLifeCycleState(ElementLifeCycleState state) { 132 return document.getCurrentLifeCycleState().equalsIgnoreCase(state.name()); 133 } 134 135 @Override 136 public String getDescription() { 137 return (String) getProperty(DocumentRoutingConstants.DESCRIPTION_PROPERTY_NAME); 138 } 139 140 @Override 141 public boolean isRunning() { 142 return checkLifeCycleState(ElementLifeCycleState.running); 143 } 144 145 @Override 146 public boolean isCanceled() { 147 return checkLifeCycleState(ElementLifeCycleState.canceled); 148 } 149 150 @Override 151 public boolean isDraft() { 152 return checkLifeCycleState(ElementLifeCycleState.draft); 153 } 154 155 @Override 156 public void setRunning(CoreSession session) { 157 followTransition(ElementLifeCycleTransistion.toRunning, session, false); 158 } 159 160 @Override 161 public void followTransition(ElementLifeCycleTransistion transition, CoreSession session, boolean recursive) { 162 if (document.followTransition(transition.name())) { 163 if (Framework.isTestModeSet()) { 164 session.save(); 165 } 166 document = session.getDocument(document.getRef()); 167 } 168 if (recursive) { 169 DocumentModelList children = session.getChildren(document.getRef()); 170 for (DocumentModel child : children) { 171 DocumentRouteElement element = child.getAdapter(DocumentRouteElement.class); 172 element.followTransition(transition, session, recursive); 173 } 174 175 } 176 } 177 178 @Override 179 public void save(CoreSession session) { 180 session.saveDocument(document); 181 } 182 183 @Override 184 public void setDone(CoreSession session) { 185 followTransition(ElementLifeCycleTransistion.toDone, session, false); 186 EventFirer.fireEvent(session, this, null, DocumentRoutingConstants.Events.afterStepRunning.name()); 187 } 188 189 @Override 190 public void setValidated(CoreSession session) { 191 followTransition(ElementLifeCycleTransistion.toValidated, session, true); 192 } 193 194 @Override 195 public void setReady(CoreSession session) { 196 followTransition(ElementLifeCycleTransistion.toReady, session, true); 197 } 198 199 @Override 200 public void validate(CoreSession session) { 201 setValidated(session); 202 setReadOnly(session); 203 } 204 205 @Override 206 public void setReadOnly(CoreSession session) { 207 SetDocumentOnReadOnlyUnrestrictedSessionRunner readOnlySetter = new SetDocumentOnReadOnlyUnrestrictedSessionRunner( 208 session, document.getRef()); 209 readOnlySetter.runUnrestricted(); 210 } 211 212 protected class SetDocumentOnReadOnlyUnrestrictedSessionRunner extends UnrestrictedSessionRunner { 213 214 public SetDocumentOnReadOnlyUnrestrictedSessionRunner(CoreSession session, DocumentRef ref) { 215 super(session); 216 this.ref = ref; 217 } 218 219 protected DocumentRef ref; 220 221 @Override 222 public void run() { 223 DocumentModel doc = session.getDocument(ref); 224 ACP acp = new ACPImpl(); 225 // add new ACL to set READ permission to everyone 226 ACL routingACL = acp.getOrCreateACL(DocumentRoutingConstants.DOCUMENT_ROUTING_ACL); 227 routingACL.add(new ACE(SecurityConstants.EVERYONE, SecurityConstants.READ, true)); 228 // block rights inheritance 229 ACL localACL = acp.getOrCreateACL(ACL.LOCAL_ACL); 230 localACL.add(new ACE(SecurityConstants.EVERYONE, SecurityConstants.EVERYTHING, false)); 231 doc.setACP(acp, true); 232 session.saveDocument(doc); 233 } 234 } 235 236 @Override 237 public boolean canValidateStep(CoreSession session) { 238 return hasPermissionOnDocument(session, SecurityConstants.WRITE_LIFE_CYCLE); 239 } 240 241 protected boolean hasPermissionOnDocument(CoreSession session, String permission) { 242 return session.hasPermission(document.getRef(), permission); 243 } 244 245 @Override 246 public void setCanValidateStep(CoreSession session, String userOrGroup) { 247 setPermissionOnDocument(session, userOrGroup, SecurityConstants.WRITE_LIFE_CYCLE); 248 } 249 250 protected void setPermissionOnDocument(CoreSession session, String userOrGroup, String permission) { 251 ACP acp = document.getACP(); 252 ACL routingACL = acp.getOrCreateACL(DocumentRoutingConstants.DOCUMENT_ROUTING_ACL); 253 routingACL.add(new ACE(userOrGroup, permission, true)); 254 document.setACP(acp, true); 255 session.saveDocument(document); 256 } 257 258 @Override 259 public boolean canUpdateStep(CoreSession session) { 260 return hasPermissionOnDocument(session, SecurityConstants.WRITE_PROPERTIES); 261 } 262 263 @Override 264 public void setCanUpdateStep(CoreSession session, String userOrGroup) { 265 setPermissionOnDocument(session, userOrGroup, SecurityConstants.WRITE_PROPERTIES); 266 } 267 268 @Override 269 public void setCanReadStep(CoreSession session, String userOrGroup) { 270 setPermissionOnDocument(session, userOrGroup, SecurityConstants.READ); 271 } 272 273 @Override 274 public boolean canDeleteStep(CoreSession session) { 275 return hasPermissionOnDocument(session, SecurityConstants.REMOVE); 276 } 277 278 @Override 279 public void setCanDeleteStep(CoreSession session, String userOrGroup) { 280 setPermissionOnDocument(session, userOrGroup, SecurityConstants.REMOVE); 281 } 282 283 @Override 284 public void backToReady(CoreSession session) { 285 EventFirer.fireEvent(session, this, null, DocumentRoutingConstants.Events.beforeStepBackToReady.name()); 286 followTransition(ElementLifeCycleTransistion.backToReady, session, false); 287 EventFirer.fireEvent(session, this, null, DocumentRoutingConstants.Events.afterStepBackToReady.name()); 288 } 289 290 @Override 291 public DocumentRouteStep undo(CoreSession session) { 292 runner.undo(session, this); 293 document = session.getDocument(document.getRef()); 294 return this; 295 } 296 297 @Override 298 public boolean canUndoStep(CoreSession session) { 299 GetIsParentRunningUnrestricted runner = new GetIsParentRunningUnrestricted(session); 300 runner.runUnrestricted(); 301 return runner.isRunning(); 302 } 303 304 protected class GetIsParentRunningUnrestricted extends UnrestrictedSessionRunner { 305 public GetIsParentRunningUnrestricted(CoreSession session) { 306 super(session); 307 } 308 309 protected boolean isRunning; 310 311 @Override 312 public void run() { 313 DocumentModel parent = session.getDocument(document.getParentRef()); 314 DocumentRouteElement parentElement = parent.getAdapter(DocumentRouteElement.class); 315 isRunning = parentElement.isRunning(); 316 } 317 318 public boolean isRunning() { 319 return isRunning; 320 } 321 } 322 323 @Override 324 public void cancel(CoreSession session) { 325 runner.cancel(session, this); 326 } 327 328 @Override 329 public void setCanceled(CoreSession session) { 330 followTransition(ElementLifeCycleTransistion.toCanceled, session, false); 331 } 332 333 @Override 334 public boolean isModifiable() { 335 return (isDraft() || isReady() || isRunning()); 336 } 337}