001/* 002 * (C) Copyright 2017-2018 Nuxeo (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 * Funsho David 018 * Kevin Leturc 019 * 020 */ 021 022package org.nuxeo.ecm.core.versioning; 023 024import static org.nuxeo.ecm.platform.el.ELConstants.CURRENT_DOCUMENT; 025import static org.nuxeo.ecm.platform.el.ELConstants.CURRENT_USER; 026import static org.nuxeo.ecm.platform.el.ELConstants.DOCUMENT; 027import static org.nuxeo.ecm.platform.el.ELConstants.PREVIOUS_DOCUMENT; 028import static org.nuxeo.ecm.platform.el.ELConstants.PRINCIPAL; 029 030import java.util.Collection; 031 032import javax.el.ELContext; 033import javax.el.ExpressionFactory; 034import javax.el.ValueExpression; 035import javax.el.VariableMapper; 036 037import org.apache.commons.lang3.StringUtils; 038import org.jboss.el.ExpressionFactoryImpl; 039import org.nuxeo.ecm.core.api.DocumentModel; 040import org.nuxeo.ecm.core.api.NuxeoPrincipal; 041import org.nuxeo.ecm.core.schema.DocumentType; 042import org.nuxeo.ecm.platform.el.ELService; 043import org.nuxeo.runtime.api.Framework; 044 045/** 046 * @since 9.1 047 */ 048public class StandardVersioningPolicyFilter implements VersioningPolicyFilter { 049 050 protected Collection<String> types; 051 052 protected Collection<String> facets; 053 054 protected Collection<String> schemas; 055 056 protected String condition; 057 058 public StandardVersioningPolicyFilter(Collection<String> types, Collection<String> facets, 059 Collection<String> schemas, String condition) { 060 this.types = types; 061 this.facets = facets; 062 this.schemas = schemas; 063 this.condition = condition; 064 } 065 066 @Override 067 public boolean test(DocumentModel previousDocument, DocumentModel currentDocument) { 068 if (!types.isEmpty() && !types.contains(currentDocument.getType())) { 069 return false; 070 } 071 DocumentType docType = currentDocument.getDocumentType(); 072 if (!schemas.isEmpty() && schemas.stream().noneMatch(docType::hasSchema)) { 073 return false; 074 } 075 if (!facets.isEmpty() && facets.stream().noneMatch(docType::hasFacet)) { 076 return false; 077 } 078 if (!StringUtils.isBlank(condition)) { 079 080 String cond = evaluateCondition(condition); 081 082 ELContext context = Framework.getService(ELService.class).createELContext(); 083 ExpressionFactory expressionFactory = new ExpressionFactoryImpl(); 084 085 VariableMapper vm = context.getVariableMapper(); 086 087 // init default variables 088 ValueExpression previousDocExpr = expressionFactory.createValueExpression(previousDocument, 089 DocumentModel.class); 090 ValueExpression currentDocExpr = expressionFactory.createValueExpression(currentDocument, 091 DocumentModel.class); 092 ValueExpression userExpr = expressionFactory.createValueExpression(NuxeoPrincipal.getCurrent(), 093 NuxeoPrincipal.class); 094 vm.setVariable(PREVIOUS_DOCUMENT, previousDocExpr); 095 vm.setVariable(CURRENT_DOCUMENT, currentDocExpr); 096 vm.setVariable(DOCUMENT, currentDocExpr); 097 vm.setVariable(PRINCIPAL, userExpr); 098 vm.setVariable(CURRENT_USER, userExpr); 099 100 // evaluate expression 101 ValueExpression ve = expressionFactory.createValueExpression(context, cond, Boolean.class); 102 return Boolean.TRUE.equals(ve.getValue(context)); 103 } 104 return true; 105 } 106 107 /** 108 * Evaluate and build a valid condition 109 * 110 * @param condition the initial condition 111 */ 112 public static String evaluateCondition(String condition) { 113 114 String cond = condition.trim(); 115 // compatibility code, as JEXL could resolve that kind of expression: 116 // detect if expression is in brackets #{}, otherwise add it 117 if (!cond.startsWith("#{") && !cond.startsWith("${") && !cond.endsWith("}")) { 118 cond = "#{" + cond + "}"; 119 } 120 121 // Check if there is a null/not-null evaluation on previousDocument, if not 122 // Add a not-null evaluation on it to prevent NPE 123 String p1 = ".*" + PREVIOUS_DOCUMENT + "\\..+"; 124 String p2 = ".*" + PREVIOUS_DOCUMENT + "\\s*[!=]=\\s*null.*"; 125 if (cond.matches(p1) && !cond.matches(p2)) { 126 cond = "#{" + PREVIOUS_DOCUMENT + " != null && (" + cond.substring(2, cond.length() - 1) + ")}"; 127 } 128 return cond; 129 } 130}