Package org.olat.course.editor

Source Code of org.olat.course.editor.CourseEditorEnvImpl$CollectConditionExpressionsVisitor

/**
* 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.editor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org._3pq.jgrapht.DirectedGraph;
import org._3pq.jgrapht.Edge;
import org._3pq.jgrapht.alg.CycleDetector;
import org._3pq.jgrapht.edge.EdgeFactories;
import org._3pq.jgrapht.edge.EdgeFactories.DirectedEdgeFactory;
import org._3pq.jgrapht.graph.DefaultDirectedGraph;
import org.olat.core.util.nodes.INode;
import org.olat.core.util.tree.TreeVisitor;
import org.olat.core.util.tree.Visitor;
import org.olat.course.assessment.AssessmentHelper;
import org.olat.course.condition.interpreter.ConditionErrorMessage;
import org.olat.course.condition.interpreter.ConditionExpression;
import org.olat.course.condition.interpreter.ConditionInterpreter;
import org.olat.course.groupsandrights.CourseGroupManager;
import org.olat.course.nodes.CourseNode;
import org.olat.course.nodes.ENCourseNode;
import org.olat.course.tree.CourseEditorTreeModel;
import org.olat.course.tree.CourseEditorTreeNode;
import org.olat.group.area.BGArea;

/**
* Description:<br>
* TODO: guido Class Description for CourseEditorEnvImpl
*/
public class CourseEditorEnvImpl implements CourseEditorEnv {
  /**
   * the course editor tree model used in this editing session, exist only once
   * per open course editor
   */
  private CourseEditorTreeModel cetm;
  String currentCourseNodeId = null;
  /**
   * the course group manager is used for answering the existXXX questions
   * concering, groups and areas
   */
  private CourseGroupManager cgm;
  /**
   * the editor locale, it is used in the condition interpreter to provide
   * localized error messages.
   */
  private Locale editorLocale;
  /**
   * book keeping of (coursNodeId,
   * {conditionexpression,conditionexpression,...}) TODO: do we really need the
   * information splitted up by category and condition expression?
   */
  Map softRefs = new HashMap();
  /**
   * book keeping of (courseNodeId, StatusDescription)
   */
  Map statusDescs = new HashMap();
  /**
   * current active condition expression, it is activated by a call to
   * <code>validateConditionExpression(..)</code> the condition interpreter is
   * then asked for validating the expression. This validation parses the
   * expression into the atomic functions etc, which in turn access the
   * <code>CourseEditorEnvImpl</code> to <code>pushError()</code> and
   * <code>addSoftReference()</code>.
   */
  ConditionExpression currentConditionExpression = null;
  /**
   * different organized info as in softRefs: (nodeId,{nodeid,nodeId,...})
   */
  Map<String, Set<String>> nodeRefs = new HashMap<String, Set<String>>();
  /**
   * the condition interpreter for evaluating the condtion expressions.
   */
  ConditionInterpreter ci = null;

  public CourseEditorEnvImpl(CourseEditorTreeModel cetm, CourseGroupManager cgm, Locale editorLocale) {
    this.cetm = cetm;
    this.cgm = cgm;
    this.editorLocale = editorLocale;
  }

  /**
   * @param ci
   */
  public void setConditionInterpreter(ConditionInterpreter ci) {
    this.ci = ci;
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#isEnrollmentNode(java.lang.String)
   */
  public boolean isEnrollmentNode(String nodeId) {
    CourseEditorTreeNode cen = cetm.getCourseEditorNodeById(nodeId);
    if (cen == null) return false;
    if (cen.isDeleted()) return false;
    // node exists and is not marked as deleted, check the associated course
    // node correct type
    return (cen.getCourseNode() instanceof ENCourseNode);
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#isAssessable(java.lang.String)
   */
  public boolean isAssessable(String nodeId) {
    CourseEditorTreeNode cen = cetm.getCourseEditorNodeById(nodeId);
    if (cen == null) return false;
    if (cen.isDeleted()) return false;
    // node exists and is not marked as deleted, check the associated course
    // node for assessability.
    return AssessmentHelper.checkIfNodeIsAssessable(cen.getCourseNode());
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#existsNode(java.lang.String)
   */
  public boolean existsNode(String nodeId) {
    CourseEditorTreeNode cen = cetm.getCourseEditorNodeById(nodeId);
    boolean retVal = cen != null && !cen.isDeleted();
    return retVal;
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#existsGroup(java.lang.String)
   */
  public boolean existsGroup(String groupname) {
    // FIXME:fg:b improve performance by adding a special query for the existence
    // check!
    List cnt = cgm.getLearningGroupsFromAllContexts(groupname);
    return (cnt != null && cnt.size() > 0);
  }

  public boolean existsRightGroup(String groupname) {
    List cnt = cgm.getRightGroupsFromAllContexts(groupname);
    return (cnt != null && cnt.size() > 0);
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#existsArea(java.lang.String)
   */
  public boolean existsArea(String areaname) {
    // FIXME:fg:b improve performance by adding a special query for the existence
    // check!
    List cnt = cgm.getAllAreasFromAllContexts();
    for (Iterator iter = cnt.iterator(); iter.hasNext();) {
      BGArea element = (BGArea) iter.next();
      if (element.getName().equals(areaname)) { return true; }
    }
    return false;
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#getCurrentCourseNodeId()
   */
  public String getCurrentCourseNodeId() {
    return currentCourseNodeId;
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#setCurrentCourseNodeId(java.lang.String)
   */
  public void setCurrentCourseNodeId(String courseNodeId) {
    this.currentCourseNodeId = courseNodeId;
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#getEditorEnvLocale()
   */
  public Locale getEditorEnvLocale() {
    return editorLocale;
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#validateConditionExpression(org.olat.course.condition.interpreter.ConditionExpression)
   */
  public ConditionErrorMessage[] validateConditionExpression(ConditionExpression condExpr) {
    // first set the active condition expression, which will be accessed from
    // the conditions functions inserting soft references
    currentConditionExpression = condExpr;
    if(condExpr.getExptressionString()==null) {
      return null;
    }
    // evaluate expression
    ConditionErrorMessage[] cems = ci.syntaxTestExpression(condExpr);
    if (softRefs.containsKey(this.currentCourseNodeId)) {
      List condExprs = (ArrayList) softRefs.get(this.currentCourseNodeId);
      for (Iterator iter = condExprs.iterator(); iter.hasNext();) {
        ConditionExpression element = (ConditionExpression) iter.next();
        if (element.getId().equals(currentConditionExpression.getId())) {
          condExprs.remove(element);
          break;
        }
      }
      condExprs.add(currentConditionExpression);
    } else {
      List condExprs = new ArrayList();
      condExprs.add(currentConditionExpression);
      softRefs.put(currentCourseNodeId, condExprs);
    }

    //
    return cems;
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#addSoftReference(java.lang.String,
   *      java.lang.String)
   */
  public void addSoftReference(String category, String softReference) {
    currentConditionExpression.addSoftReference(category, softReference);

  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#pushError(java.lang.Exception)
   */
  public void pushError(Exception e) {
    currentConditionExpression.pushError(e);
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#validateCourse()
   */
  public void validateCourse() {
    /*
     * collect all condition error messages and soft references collect all
     * configuration errors.
     */
    String currentNodeWas = currentCourseNodeId;
    // reset all
    softRefs = new HashMap();
    nodeRefs = new HashMap<String, Set<String>>();
    Visitor v = new CollectConditionExpressionsVisitor();
    (new TreeVisitor(v, cetm.getRootNode(), true)).visitAll();
    for (Iterator iter = softRefs.keySet().iterator(); iter.hasNext();) {
      String nodeId = (String) iter.next();
      List conditionExprs = (List) softRefs.get(nodeId);
      for (int i = 0; i < conditionExprs.size(); i++) {
        ConditionExpression ce = (ConditionExpression) conditionExprs.get(i);
        // DO NOT validateConditionExpression(ce) as this is already done in the
        // CollectConditionExpressionsVisitor
        Set<String> refs = new HashSet<String>(ce.getSoftReferencesOf("courseNodeId"));
        if (refs != null && refs.size() > 0) {
          Set<String> oldOnes = nodeRefs.put(nodeId, null);
          if (oldOnes != null) {
            refs.addAll(oldOnes);
          }
          nodeRefs.put(nodeId, refs);
        }
      }

    }
    // refresh,create status descriptions of the course
    statusDescs = new HashMap();
    v = new CollectStatusDescriptionVisitor(this);
    (new TreeVisitor(v, cetm.getRootNode(), true)).visitAll();
    //
    currentCourseNodeId = currentNodeWas;
  }

  /**
   * @see org.olat.course.editor.CourseEditorEnv#getCourseStatus()
   */
  public StatusDescription[] getCourseStatus() {
    String[] a = new String[statusDescs.keySet().size()];
    a = (String[]) statusDescs.keySet().toArray(a);
    Arrays.sort(a);
    List all2gether = new ArrayList();
    for (int i = a.length - 1; i >= 0; i--) {
      all2gether.addAll((List) statusDescs.get(a[i]));
    }
    StatusDescription[] retVal = new StatusDescription[all2gether.size()];
    retVal = (StatusDescription[]) all2gether.toArray(retVal);
    return retVal;
  }

  public List getReferencingNodeIdsFor(String ident) {
    List refNodes = new ArrayList();
    for (Iterator iter = nodeRefs.keySet().iterator(); iter.hasNext();) {
      String nodeId = (String) iter.next();
      if (!nodeId.equals(ident)) {
        // self references are catched during form entering
        Set refs = (Set) nodeRefs.get(nodeId);
        if (refs.contains(ident)) {
          // nodeId references ident
          refNodes.add(nodeId);
        }
      }
    }
    return refNodes;
  }

 
  public String toString() {
    String retVal = "";
    Set keys = softRefs.keySet();
    for (Iterator iter = keys.iterator(); iter.hasNext();) {
      String nodId = (String) iter.next();
      retVal += "nodeId:" + nodId + "\n";
      List conditionExprs = (List) softRefs.get(nodId);
      for (Iterator iterator = conditionExprs.iterator(); iterator.hasNext();) {
        ConditionExpression ce = (ConditionExpression) iterator.next();
        retVal += "\t" + ce.toString() + "\n";
      }
      retVal += "\n";
    }
    return retVal;
  }

  class CollectStatusDescriptionVisitor implements Visitor {
    private CourseEditorEnv cev;

    public CollectStatusDescriptionVisitor(CourseEditorEnv cev) {
      this.cev = cev;
    }

    /**
     * @see org.olat.core.util.tree.Visitor#visit(org.olat.core.util.nodes.INode)
     */
    public void visit(INode node) {
      /**
       * collect only status descriptions of not deleted nodes
       */
      CourseEditorTreeNode tmp = (CourseEditorTreeNode) node;
      if (!tmp.isDeleted()) {
        CourseNode cn = tmp.getCourseNode();
        String key = cn.getIdent();
        StatusDescription[] allSds = cn.isConfigValid(cev);
        if (allSds.length > 0) {
          for (int i = 0; i < allSds.length; i++) {
            StatusDescription sd = allSds[i];
            if (sd != StatusDescription.NOERROR) {
              if (!statusDescs.containsKey(key)) {
                statusDescs.put(key, new ArrayList());
              }
              List sds = (List) statusDescs.get(key);
              sds.add(sd);
            }
          }
        }
      }
    }

  }

  class CollectConditionExpressionsVisitor implements Visitor {
    /**
     * @see org.olat.core.util.tree.Visitor#visit(org.olat.core.util.nodes.INode)
     */
    public void visit(INode node) {
      /**
       * collect condition expressions only for not deleted nodes
       */
      CourseEditorTreeNode tmp = (CourseEditorTreeNode) node;
      CourseNode cn = tmp.getCourseNode();
      String key = cn.getIdent();
      List condExprs = cn.getConditionExpressions();
      if (condExprs.size() > 0 && !tmp.isDeleted()) {
        // evaluate each expression
        for (Iterator iter = condExprs.iterator(); iter.hasNext();) {
          ConditionExpression ce = (ConditionExpression) iter.next();
          currentCourseNodeId = key;
          currentConditionExpression = ce;
          ci.syntaxTestExpression(ce);
        }
        // add it to the cache.
        softRefs.put(key, condExprs);
      }
    }

  }

  class Convert2DGVisitor implements Visitor{
    private DirectedEdgeFactory def;
    private DirectedGraph dg;
    public Convert2DGVisitor(DirectedGraph dg) {
      this.dg = dg;
      def = new EdgeFactories.DirectedEdgeFactory();
    }
    public void visit(INode node) {
      CourseEditorTreeNode tmp = (CourseEditorTreeNode) node;
      CourseNode cn = tmp.getCourseNode();
      String key = cn.getIdent();
      dg.addVertex(key);
      /*
       * add edge from parent to child. This directed edge represents the visibility accessability inheritance direction.
       */
      INode parent = tmp.getParent();
      if(parent!=null) {
        dg.addVertex(parent.getIdent());
        Edge toParent = def.createEdge( parent.getIdent(),key);
        dg.addEdge(toParent);
      }
    }
   
  }
 
  /**
   *
   * @see org.olat.course.editor.CourseEditorEnv#listCycles()
   */
  public Set<String> listCycles() {
    /*
     * convert nodeRefs datastructure to a directed graph
     */
    DirectedGraph dg = new DefaultDirectedGraph();
    DirectedEdgeFactory def = new EdgeFactories.DirectedEdgeFactory();
    /*
     * add the course structure as directed graph, where
     */
    Visitor v = new Convert2DGVisitor(dg);
    (new TreeVisitor(v, cetm.getRootNode(), true)).visitAll();
    /*
     * iterate over nodeRefs, add each not existing node id as vertex, for each
     * key - child relation add an edge to the directed graph.
     */
    Iterator<String> keys = nodeRefs.keySet().iterator();
    while(keys.hasNext()) {
      //a node
      String key = keys.next();
      if(!dg.containsVertex(key)) {
        dg.addVertex(key);
      }
      //and its children
      Set<String> children = nodeRefs.get(key);
      Iterator<String> childrenIt = children.iterator();
      while(childrenIt.hasNext()){
        String child = childrenIt.next();
        if(!dg.containsVertex(child)) {
          dg.addVertex(child);
        }
        //add edge, precondition: vertex key - child are already added to the graph
        Edge de = def.createEdge(key, child);
        dg.addEdge(de);
      }
    }
    /*
     * find the id's participating in the cycle, and return the intersection
     * with set of id's which actually produce references.
     */
    CycleDetector cd = new CycleDetector(dg);
    Set<String> cycleIds = cd.findCycles();
    cycleIds.retainAll(nodeRefs.keySet());
    return cycleIds;
  }

  /**
   *
   * @return CourseGroupManager for this course environment
   */
  public CourseGroupManager getCourseGroupManager() {
    return cgm;
  }


}
TOP

Related Classes of org.olat.course.editor.CourseEditorEnvImpl$CollectConditionExpressionsVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.