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