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