/*
* (C) Copyright 2017 Nuxeo (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Funsho David
* Kevin Leturc
*
*/
package org.nuxeo.ecm.core.versioning;
import org.apache.commons.lang.StringUtils;
import org.jboss.el.ExpressionFactoryImpl;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.NuxeoPrincipal;
import org.nuxeo.ecm.core.api.local.ClientLoginModule;
import org.nuxeo.ecm.core.schema.DocumentType;
import org.nuxeo.ecm.platform.el.ELService;
import org.nuxeo.runtime.api.Framework;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
import java.util.Collection;
import static org.nuxeo.ecm.platform.el.ELConstants.CURRENT_DOCUMENT;
import static org.nuxeo.ecm.platform.el.ELConstants.CURRENT_USER;
import static org.nuxeo.ecm.platform.el.ELConstants.DOCUMENT;
import static org.nuxeo.ecm.platform.el.ELConstants.PREVIOUS_DOCUMENT;
import static org.nuxeo.ecm.platform.el.ELConstants.PRINCIPAL;
/**
* @since 9.1
*/
public class StandardVersioningPolicyFilter implements VersioningPolicyFilter {
protected Collection<String> types;
protected Collection<String> facets;
protected Collection<String> schemas;
protected String condition;
public StandardVersioningPolicyFilter(Collection<String> types, Collection<String> facets,
Collection<String> schemas, String condition) {
this.types = types;
this.facets = facets;
this.schemas = schemas;
this.condition = condition;
}
@Override
public boolean test(DocumentModel previousDocument, DocumentModel currentDocument) {
if (!types.isEmpty() && !types.contains(currentDocument.getType())) {
return false;
}
DocumentType docType = currentDocument.getDocumentType();
if (!schemas.isEmpty() && schemas.stream().noneMatch(docType::hasSchema)) {
return false;
}
if (!facets.isEmpty() && facets.stream().noneMatch(docType::hasFacet)) {
return false;
}
if (!StringUtils.isBlank(condition)) {
String cond = evaluateCondition(condition);
ELContext context = Framework.getService(ELService.class).createELContext();
ExpressionFactory expressionFactory = new ExpressionFactoryImpl();
VariableMapper vm = context.getVariableMapper();
// init default variables
ValueExpression previousDocExpr = expressionFactory.createValueExpression(previousDocument,
DocumentModel.class);
ValueExpression currentDocExpr = expressionFactory.createValueExpression(currentDocument,
DocumentModel.class);
ValueExpression userExpr = expressionFactory.createValueExpression(ClientLoginModule.getCurrentPrincipal(),
NuxeoPrincipal.class);
vm.setVariable(PREVIOUS_DOCUMENT, previousDocExpr);
vm.setVariable(CURRENT_DOCUMENT, currentDocExpr);
vm.setVariable(DOCUMENT, currentDocExpr);
vm.setVariable(PRINCIPAL, userExpr);
vm.setVariable(CURRENT_USER, userExpr);
// evaluate expression
ValueExpression ve = expressionFactory.createValueExpression(context, cond, Boolean.class);
return Boolean.TRUE.equals(ve.getValue(context));
}
return true;
}
/**
* Evaluate and build a valid condition
*
* @param condition the initial condition
*/
public static String evaluateCondition(String condition) {
String cond = condition.trim();
// compatibility code, as JEXL could resolve that kind of expression:
// detect if expression is in brackets #{}, otherwise add it
if (!cond.startsWith("#{") && !cond.startsWith("${") && !cond.endsWith("}")) {
cond = "#{" + cond + "}";
}
// Check if there is a null/not-null evaluation on previousDocument, if not
// Add a not-null evaluation on it to prevent NPE
String p1 = ".*" + PREVIOUS_DOCUMENT + "\\..+";
String p2 = ".*" + PREVIOUS_DOCUMENT + "\\s*[!=]=\\s*null.*";
if (cond.matches(p1) && !cond.matches(p2)) {
cond = "#{" + PREVIOUS_DOCUMENT + " != null && (" + cond.substring(2, cond.length() - 1) + ")}";
}
return cond;
}
}