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