/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/content/trunk/content-tool/tool/src/java/org/sakaiproject/content/tool/ResourceTypeLabeler.java $
* $Id: ResourceTypeLabeler.java 59674 2009-04-03 23:05:58Z arwhyte@umich.edu $
***********************************************************************************
*
* Copyright (c) 2007, 2008, 2009, 2010 The Sakai Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.
*
**********************************************************************************/
package org.sakaiproject.content.tool;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.cheftool.Context;
import org.sakaiproject.cheftool.VelocityPortletPaneledAction;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.conditions.api.Condition;
import org.sakaiproject.conditions.api.ConditionService;
import org.sakaiproject.conditions.api.Rule;
import org.sakaiproject.entity.api.Entity;
import org.sakaiproject.event.api.Notification;
import org.sakaiproject.event.api.NotificationEdit;
import org.sakaiproject.event.api.NotificationLockedException;
import org.sakaiproject.event.api.NotificationNotDefinedException;
import org.sakaiproject.event.api.SessionState;
import org.sakaiproject.event.cover.EventTrackingService;
import org.sakaiproject.event.cover.NotificationService;
import org.sakaiproject.tool.cover.ToolManager;
import org.sakaiproject.util.ParameterParser;
import org.sakaiproject.util.ResourceLoader;
public class ResourceConditionsHelper {
/**
*
*/
private static final long serialVersionUID = -3875833398687224551L;
static final Log logger = LogFactory.getLog(ResourceConditionsHelper.class);
static final ConditionService conditionService = (ConditionService)ComponentManager.get("org.sakaiproject.conditions.api.ConditionService");
/** Resource bundle using current language locale */
private static ResourceLoader rb = new ResourceLoader("content");
static void saveCondition(ListItem item, ParameterParser params, SessionState state, int index) {
if (! conditionsEnabled()) {
return;
}
boolean cbSelected = Boolean.valueOf(params.get("cbCondition" + ListItem.DOT + index));
String selectedConditionValue = params.get("selectCondition" + ListItem.DOT + index);
if (selectedConditionValue == null) return;
logger.debug("Selected condition value: " + selectedConditionValue);
//The selectCondition value must be broken up so we can get at the values
//that make up the index, submittedFunctionName, missingTermQuery, and operatorValue in that order
String[] conditionTokens = selectedConditionValue.split("\\|");
int selectedIndex = Integer.valueOf(conditionTokens[0]);
String submittedFunctionName = conditionTokens[1];
String missingTermQuery = conditionTokens[2];
String operatorValue = conditionTokens[3];
logger.debug("submittedFunctionName: " + submittedFunctionName);
logger.debug("missingTermQuery: " + missingTermQuery);
logger.debug("operatorValue: " + operatorValue);
String submittedResourceFilter = params.get("selectResource" + ListItem.DOT + index);
// the number of grade points are tagging along for the ride. chop this off.
String[] resourceTokens = submittedResourceFilter.split("/");
String assignmentPointsString = resourceTokens[4];
submittedResourceFilter = "/" + resourceTokens[1] + "/" + resourceTokens[2] + "/" + resourceTokens[3];
String additionalAssignmentInfo = "/" + resourceTokens[4] + "/" + resourceTokens[5] + "/" + resourceTokens[6] + "/" + resourceTokens[7];
logger.debug("submittedResourceFilter: " + submittedResourceFilter);
String eventDataClass = conditionService.getClassNameForEvent(submittedFunctionName);
Object argument = null;
if ((selectedIndex == 1) || (selectedIndex == 2)) {
argument = "dateMillis:"+resourceTokens[5];
}
if ((selectedIndex == 9) || (selectedIndex == 10)) {
try {
argument = Double.valueOf(params.get("assignment_grade" + ListItem.DOT + index));
} catch (NumberFormatException e) {
VelocityPortletPaneledAction.addAlert(state, rb.getString("conditions.invalid.condition.argument"));
return;
}
double assignmentPoints = 0;
try {
assignmentPoints = new Double(assignmentPointsString);
} catch (NumberFormatException e) {
return;
}
if (((Double)argument < 0) || ((Double)argument > assignmentPoints)) {
VelocityPortletPaneledAction.addAlert(state, rb.getFormattedMessage("conditions.condition.argument.outofrange", new String[] { assignmentPointsString }));
return;
}
logger.debug("argument: " + argument);
}
if (cbSelected) {
if (item.useConditionalRelease) {
logger.debug("Previous condition exists. Removing related notification");
removeExistingNotification(item, state);
}
String containingCollectionId = item.containingCollectionId;
String resourceId = item.getId();
if (! resourceId.startsWith(containingCollectionId)) {
resourceId = containingCollectionId + resourceId;
if (item.isCollection() && !resourceId.endsWith("/")) resourceId = resourceId + "/";
}
List<Condition> predicates = new ArrayList();
Condition resourcePredicate = conditionService.makeBooleanExpression(eventDataClass, missingTermQuery, operatorValue, argument);
predicates.add(resourcePredicate);
Rule resourceConditionRule = conditionService.makeRule(resourceId, predicates, Rule.Conjunction.OR);
NotificationEdit notification = NotificationService.addNotification();
notification.addFunction(submittedFunctionName);
notification.addFunction("cond+" + submittedFunctionName);
notification.setResourceFilter(submittedResourceFilter);
if (missingTermQuery.contains("Date")) {
notification.addFunction("datetime.update");
notification.setResourceFilter(null);
}
notification.setAction(resourceConditionRule);
notification.getProperties().addProperty(ConditionService.PROP_SUBMITTED_FUNCTION_NAME, submittedFunctionName);
notification.getProperties().addProperty(ConditionService.PROP_SUBMITTED_RESOURCE_FILTER, submittedResourceFilter);
notification.getProperties().addProperty(ConditionService.PROP_SELECTED_CONDITION_KEY, selectedConditionValue);
notification.getProperties().addProperty(ConditionService.PROP_CONDITIONAL_RELEASE_ARGUMENT, params.get("assignment_grade" + ListItem.DOT + index));
notification.getProperties().addProperty("SAKAI:conditionEventState", additionalAssignmentInfo);
NotificationService.commitEdit(notification);
item.setUseConditionalRelease(true);
item.setNotificationId(notification.getId());
} else {
//only remove the condition if it previously existed
if (item.useConditionalRelease) {
item.setUseConditionalRelease(false);
removeExistingNotification(item, state);
}
}
}
private static boolean conditionsEnabled() {
return ServerConfigurationService.getBoolean("conditions.service.enabled", Boolean.FALSE)
&& conditionService != null && !conditionService.getRegisteredServiceNames().isEmpty();
}
void loadConditionData(SessionState state) {
if (! conditionsEnabled()) {
return;
}
logger.debug("Loading condition data");
ListItem item = (ListItem) state.getAttribute(ResourcesAction.STATE_REVISE_PROPERTIES_ITEM);
if ((item != null) && (item.useConditionalRelease)) {
try {
Notification notification = NotificationService.getNotification(item.getNotificationId());
if (notification != null) {
item.setSubmittedFunctionName(notification.getProperties().getProperty(ConditionService.PROP_SUBMITTED_FUNCTION_NAME));
item.setSubmittedResourceFilter(notification.getProperties().getProperty(ConditionService.PROP_SUBMITTED_RESOURCE_FILTER));
item.setSelectedConditionKey(notification.getProperties().getProperty(ConditionService.PROP_SELECTED_CONDITION_KEY));
item.setConditionArgument(notification.getProperties().getProperty(ConditionService.PROP_CONDITIONAL_RELEASE_ARGUMENT));
}
} catch (NotificationNotDefinedException e) {
VelocityPortletPaneledAction.addAlert(state, rb.getString("conditions.notification.load.error"));
}
}
Map<String,String> resourceSelections = conditionService.getEntitiesForServiceAndContext("gradebook", ToolManager.getCurrentPlacement().getContext());
//TODO look this data up
//Using LinkedHashMap to maintain order
Map<String,String> conditionSelections = new LinkedHashMap<String,String>();
conditionSelections.put("1|gradebook.updateAssignment|dueDateHasPassed|no_operator",rb.getString("conditional.duedate_passed"));
conditionSelections.put("2|gradebook.updateAssignment|dueDateHasNotPassed|no_operator",rb.getString("conditional.duedate_notpassed"));
conditionSelections.put("3|gradebook.updateAssignment|isReleasedToStudents|no_operator",rb.getString("conditional.released_to_students"));
conditionSelections.put("4|gradebook.updateAssignment|isNotReleasedToStudents|no_operator",rb.getString("conditional.not_released_to_students"));
conditionSelections.put("5|gradebook.updateAssignment|isIncludedInCourseGrade|no_operator",rb.getString("conditional.included_in_course_grade"));
conditionSelections.put("6|gradebook.updateAssignment|isNotIncludedInCourseGrade|no_operator",rb.getString("conditional.not_included_in_course_grade"));
conditionSelections.put("7|gradebook.updateItemScore|isScoreBlank|no_operator", rb.getString("conditional.grade_blank"));
conditionSelections.put("8|gradebook.updateItemScore|isScoreNonBlank|no_operator", rb.getString("conditional.grade_non_blank"));
conditionSelections.put("9|gradebook.updateItemScore|getScore|less_than",rb.getString("conditional.grade_less_than"));
conditionSelections.put("10|gradebook.updateItemScore|getScore|greater_than_equal_to",rb.getString("conditional.grade_greather_or_equal"));
//This isn't the final resting place for this data..see the buildReviseMetadataContext method in this class
state.setAttribute("resourceSelections", resourceSelections);
state.setAttribute("conditionSelections", conditionSelections);
if (item != null) {
state.setAttribute("conditionArgument", item.getConditionArgument());
}
}
static void removeExistingNotification(ListItem item, SessionState state) {
if (! conditionsEnabled()) {
return;
}
logger.debug("Removing condition");
try {
NotificationEdit notificationToRemove = NotificationService.editNotification(item.getNotificationId());
NotificationService.removeNotification(notificationToRemove);
} catch (NotificationLockedException e) {
VelocityPortletPaneledAction.addAlert(state, rb.getString("conditions.disable.error"));
} catch (NotificationNotDefinedException e) {
VelocityPortletPaneledAction.addAlert(state, rb.getString("conditions.disable.error"));
}
}
static void buildConditionContext(Context context, SessionState state) {
if (! conditionsEnabled()) {
context.put("conditions_enabled", Boolean.FALSE);
return;
}
context.put("conditions_enabled", Boolean.TRUE);
context.put("resourceSelections", state.getAttribute("resourceSelections"));
context.put("conditionSelections", state.getAttribute("conditionSelections"));
}
static void notifyCondition(Entity entity) {
if (! conditionsEnabled()) {
return;
}
Notification resourceNotification = null;
String notificationId = entity.getProperties().getProperty(ConditionService.PROP_CONDITIONAL_NOTIFICATION_ID);
if (notificationId != null && !"".equals(notificationId)) {
try {
resourceNotification = NotificationService.getNotification(notificationId);
} catch (NotificationNotDefinedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (resourceNotification != null) {
String eventDataString = resourceNotification.getProperties().getProperty("SAKAI:conditionEventState");
// event resource of the form: /gradebook/[gradebook id]/[assignment name]/[points possible]/[due date millis]/[is released]/[is included in course grade]/[has authz]
String resource = resourceNotification.getResourceFilter();
if (resource == null) resource = "/gradebook/null/null";
EventTrackingService.post(EventTrackingService.newEvent("cond+" + resourceNotification.getFunction(), resource + eventDataString, true));
}
}
}