/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/
package org.olat.course.condition.interpreter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.olat.core.id.Identity;
import org.olat.core.id.IdentityEnvironment;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.Tracing;
import org.olat.course.editor.CourseEditorEnv;
import org.olat.course.run.userview.UserCourseEnvironment;
/**
* @author Felix Jost
*/
public class EvalAttributeFunction extends AbstractFunction {
/***************************************************************
* Function types *
* *
* ATTENTION: Don't change the order! *
* *
***************************************************************/
// user must have exaktly this expression in one of the values of given attribute
public static final int FUNCTION_TYPE_HAS_ATTRIBUTE = 0;
private static final String FUNCTION_NAME_HAS_ATTRIBUTE = "hasAttribute";
// one of the values of given attribute must start with the given expression
public static final int FUNCTION_TYPE_ATTRIBUTE_STARTS_WITH = 1;
private static final String FUNCTION_NAME_ATTRIBUTE_STARTS_WITH = "attributeStartswith";
// one of the values of given attribute must end with the given expression
public static final int FUNCTION_TYPE_ATTRIBUTE_ENDS_WITH = 2;
private static final String FUNCTION_NAME_ATTRIBUTE_ENDS_WITH = "attributeEndswith";
// given expression must be part of one of the values of given attribute
public static final int FUNCTION_TYPE_IS_IN_ATTRIBUTE = 3;
private static final String FUNCTION_NAME_IS_IN_ATTRIBUTE = "isInAttribute";
// neither of the values of given attribute may contain the given expression
public static final int FUNCTION_TYPE_IS_NOT_IN_ATTRIBUTE = 4;
private static final String FUNCTION_NAME_IS_NOT_IN_ATTRIBUTE = "isNotInAttribute";
// neither of the values of given attribute may match the given expression
public static final int FUNCTION_TYPE_HAS_NOT_ATTRIBUTE = 5;
private static final String FUNCTION_NAME_HAS_NOT_ATTRIBUTE = "hasNotAttribute";
private int functionType;
public String name;
//private static final Pattern multiValueSeparatorValue = Pattern.compile(ShibbolethModule.MULTIVALUE_SEPARATOR);
/**
* @param userCourseEnv
* @param functionType the type of function (use defined constants)
*/
public EvalAttributeFunction(UserCourseEnvironment userCourseEnv, int functionType) {
super(userCourseEnv);
this.functionType = functionType;
if (functionType == FUNCTION_TYPE_HAS_ATTRIBUTE) {
this.name = FUNCTION_NAME_HAS_ATTRIBUTE;
} else if (functionType == FUNCTION_TYPE_ATTRIBUTE_STARTS_WITH) {
this.name = FUNCTION_NAME_ATTRIBUTE_STARTS_WITH;
} else if (functionType == FUNCTION_TYPE_ATTRIBUTE_ENDS_WITH) {
this.name = FUNCTION_NAME_ATTRIBUTE_ENDS_WITH;
} else if (functionType == FUNCTION_TYPE_IS_IN_ATTRIBUTE) {
this.name = FUNCTION_NAME_IS_IN_ATTRIBUTE;
} else if (functionType == FUNCTION_TYPE_HAS_NOT_ATTRIBUTE) {
this.name = FUNCTION_NAME_HAS_NOT_ATTRIBUTE;
} else if (functionType == FUNCTION_TYPE_IS_NOT_IN_ATTRIBUTE) {
this.name = FUNCTION_NAME_IS_NOT_IN_ATTRIBUTE;
} else {
throw new OLATRuntimeException("This function type index is undefined: " + functionType, null);
}
}
/**
* Searches expression <code>ex</code> in multivalue enabled attribute value <code>values</code>
* @param ex The expression to search for.
* @param values The attribute value(s), separated by ,
* @return true if found, false otherwise
* @author Lars Eberle (<a href="http://www.bps-system.de/">BPS Bildungsportal Sachsen GmbH</a>)
*/
private boolean findExpressionInMultiValue(String ex, String values, int type) {
try {
if (ex == null || values == null) return false; // empty params?
Pattern multiValueSeparatorEx = Pattern.compile(",");
String[] a = multiValueSeparatorEx.split(ex); // split on ,
Pattern multiValueSeparatorValue = Pattern.compile(";");
String[] b = multiValueSeparatorValue.split(values); // split on ;
if (a == null || (a.length == 1 && a[0] == "")) return false; // empty array?
if (b == null || (b.length == 1 && b[0] == "")) return false; // empty array?
if (Tracing.isDebugEnabled(EvalAttributeFunction.class)) {
Tracing.logDebug("a: " + Arrays.toString(a), EvalAttributeFunction.class);
Tracing.logDebug("b: " + Arrays.toString(b), EvalAttributeFunction.class);
}
if (type == FUNCTION_TYPE_HAS_ATTRIBUTE) {
List<String> l = Arrays.asList(a);
if (l.retainAll(Arrays.asList(b))) return true; // all values are the same -> excellent :-)
if (!l.isEmpty()) return true; // some equally values found, return true
// l now contains all values which were also contained in values param, so if you want to work with that...
} else if (type == FUNCTION_TYPE_ATTRIBUTE_STARTS_WITH) {
for (int i = 0; i < a.length; ++i) { // for every attribute value
for (int j = 0; j < b.length; ++j) {
if ((b[j].startsWith(a[i]))) return true; // if match then return true
}
}
} else if (type == FUNCTION_TYPE_ATTRIBUTE_ENDS_WITH) {
for (int i = 0; i < a.length; ++i) { // for every attribute value
for (int j = 0; j < b.length; ++j) {
if ((b[j].endsWith(a[i]))) return true; // if match then return true
}
}
} else if (type == FUNCTION_TYPE_IS_IN_ATTRIBUTE) {
for (int i = 0; i < a.length; ++i) { // for every attribute value
for (int j = 0; j < b.length; ++j) {
if ((b[j].indexOf(a[i])) > -1 ) return true; // if match then return true
}
}
} else if (type == FUNCTION_TYPE_IS_NOT_IN_ATTRIBUTE) {
boolean somethingFound = false;
for (int i = 0; i < a.length; ++i) { // for every attribute value
for (int j = 0; j < b.length; ++j) {
if ((b[j].indexOf(a[i])) > -1) somethingFound = true; // if match then return true
}
}
return !somethingFound;
}
return false; // only return false if nothing found
} catch (Exception e) {
return false; // some String was null or something else unexpected
}
}
/**
* @see com.neemsoft.jmep.FunctionCB#call(java.lang.Object[])
*/
public Object call(Object[] inStack) {
/*
* argument check
*/
if (inStack.length > 2) {
return handleException( new ArgumentParseException(ArgumentParseException.NEEDS_FEWER_ARGUMENTS, name, "", "error.fewerargs",
"solution.providetwo.attrvalue"));
} else if (inStack.length < 2) { return handleException( new ArgumentParseException(ArgumentParseException.NEEDS_MORE_ARGUMENTS, name, "",
"error.moreargs", "solution.providetwo.attrvalue")); }
/*
* argument type check
*/
if (!(inStack[0] instanceof String)) return handleException( new ArgumentParseException(ArgumentParseException.WRONG_ARGUMENT_FORMAT, name, "",
"error.argtype.attributename", "solution.example.name.infunction"));
if (!(inStack[1] instanceof String)) return handleException( new ArgumentParseException(ArgumentParseException.WRONG_ARGUMENT_FORMAT, name, "",
"error.argtype.attribvalue", "solution.example.name.infunction"));
String attributeId = (String) inStack[0];
/*
* check reference integrity
*/
CourseEditorEnv cev = getUserCourseEnv().getCourseEditorEnv();
if (cev != null) {
// remember the reference to the attribute for this condtion
cev.addSoftReference("attribute", attributeId);
// return a valid value to continue with condition evaluation test
return defaultValue();
}
/*
* the real function evaluation which is used during run time
*/
String attName = (String) inStack[0];
String attValue = (String) inStack[1];
IdentityEnvironment ienv = getUserCourseEnv().getIdentityEnvironment();
Identity ident = ienv.getIdentity();
Map attributes = ienv.getAttributes();
if (attributes == null) return ConditionInterpreter.INT_FALSE;
String value = (String)attributes.get(attName);
boolean match = false;
if (Tracing.isDebugEnabled(EvalAttributeFunction.class)) {
Tracing.logDebug("value : " + value, EvalAttributeFunction.class);
Tracing.logDebug("attrValue: " + attValue, EvalAttributeFunction.class);
Tracing.logDebug("fT : " + functionType, EvalAttributeFunction.class);
}
if (value != null) {
if (functionType <= FUNCTION_TYPE_IS_NOT_IN_ATTRIBUTE) {
match = findExpressionInMultiValue(attValue, value, functionType);
} else if (functionType == FUNCTION_TYPE_HAS_NOT_ATTRIBUTE) {
match = !findExpressionInMultiValue(attValue, value, FUNCTION_TYPE_HAS_ATTRIBUTE);
}
}
if (Tracing.isDebugEnabled(EvalAttributeFunction.class)) {
Tracing.logDebug("identity '" + ident.getName() + "' tested on attribute '" + attName + "' to have value '" +
attValue + "' user's value was '" + value + "', match=" + match, EvalAttributeFunction.class);
}
return match ? ConditionInterpreter.INT_TRUE : ConditionInterpreter.INT_FALSE;
}
protected Object defaultValue() {
return ConditionInterpreter.INT_TRUE;
}
}