public Scoring getScoringDefinition(String scoringId) {
   Scoring definition = persistenceService.load(scoringId, Scoring.class);
   if (definition != null) {
     for (ScoringElement element : definition.getElements()) {
       ParserHelper.resolveConditionType(definitionsService, element.getCondition());
     }
   }
   return definition;
 }
 private List<Scoring> getAllScoringDefinitions() {
   List<Scoring> allItems = persistenceService.getAllItems(Scoring.class);
   for (Scoring scoring : allItems) {
     for (ScoringElement element : scoring.getElements()) {
       ParserHelper.resolveConditionType(definitionsService, element.getCondition());
     }
   }
   return allItems;
 }
 public DependentMetadata getScoringDependentMetadata(String scoringId) {
   List<Metadata> segments = new LinkedList<>();
   List<Metadata> scorings = new LinkedList<>();
   for (Segment definition : getScoringDependentSegments(scoringId)) {
     segments.add(definition.getMetadata());
   }
   for (Scoring definition : getScoringDependentScorings(scoringId)) {
     scorings.add(definition.getMetadata());
   }
   return new DependentMetadata(segments, scorings);
 }
 private Set<Scoring> getScoringDependentScorings(String scoringId) {
   Set<Scoring> impactedScoring = new HashSet<>(this.allScoring.size());
   for (Scoring scoring : this.allScoring) {
     for (ScoringElement element : scoring.getElements()) {
       if (checkScoringDeletionImpact(element.getCondition(), scoringId)) {
         impactedScoring.add(scoring);
         break;
       }
     }
   }
   return impactedScoring;
 }
  public void createScoringDefinition(
      String scope, String scoringId, String name, String description) {
    Metadata metadata = new Metadata(scope, scoringId, name, description);
    Scoring scoring = new Scoring(metadata);
    Condition rootCondition = new Condition();
    rootCondition.setConditionType(definitionsService.getConditionType("booleanCondition"));
    rootCondition.setParameter("operator", "and");
    rootCondition.setParameter("subConditions", new ArrayList<Condition>());
    scoring.setElements(new ArrayList<ScoringElement>());

    setScoringDefinition(scoring);
  }
  public DependentMetadata removeScoringDefinition(String scoringId, boolean validate) {
    Set<Segment> impactedSegments = getScoringDependentSegments(scoringId);
    Set<Scoring> impactedScorings = getScoringDependentScorings(scoringId);
    if (!validate || (impactedSegments.isEmpty() && impactedScorings.isEmpty())) {
      // update profiles
      updateExistingProfilesForRemovedScoring(scoringId);

      // update impacted segments
      for (Segment segment : impactedSegments) {
        Condition updatedCondition =
            updateScoringDependentCondition(segment.getCondition(), scoringId);
        segment.setCondition(updatedCondition);
        if (updatedCondition == null) {
          clearAutoGeneratedRules(
              persistenceService.query(
                  "linkedItems", segment.getMetadata().getId(), null, Rule.class),
              segment.getMetadata().getId());
          segment.getMetadata().setEnabled(false);
        }
        setSegmentDefinition(segment);
      }

      // update impacted scorings
      for (Scoring scoring : impactedScorings) {
        List<ScoringElement> updatedScoringElements = new ArrayList<>();
        for (ScoringElement scoringElement : scoring.getElements()) {
          Condition updatedCondition =
              updateScoringDependentCondition(scoringElement.getCondition(), scoringId);
          if (updatedCondition != null) {
            scoringElement.setCondition(updatedCondition);
            updatedScoringElements.add(scoringElement);
          }
        }
        scoring.setElements(updatedScoringElements);
        if (updatedScoringElements.isEmpty()) {
          clearAutoGeneratedRules(
              persistenceService.query(
                  "linkedItems", scoring.getMetadata().getId(), null, Rule.class),
              scoring.getMetadata().getId());
          scoring.getMetadata().setEnabled(false);
        }
        setScoringDefinition(scoring);
      }

      persistenceService.remove(scoringId, Scoring.class);
      List<Rule> previousRules =
          persistenceService.query("linkedItems", scoringId, null, Rule.class);
      clearAutoGeneratedRules(previousRules, scoringId);
    }

    List<Metadata> segments = new LinkedList<>();
    List<Metadata> scorings = new LinkedList<>();
    for (Segment definition : impactedSegments) {
      segments.add(definition.getMetadata());
    }
    for (Scoring definition : impactedScorings) {
      scorings.add(definition.getMetadata());
    }
    return new DependentMetadata(segments, scorings);
  }
  private void updateExistingProfilesForScoring(Scoring scoring) {
    long t = System.currentTimeMillis();
    Condition scoringCondition = new Condition();
    scoringCondition.setConditionType(
        definitionsService.getConditionType("profilePropertyCondition"));
    scoringCondition.setParameter("propertyName", "scores." + scoring.getItemId());
    scoringCondition.setParameter("comparisonOperator", "exists");
    List<Profile> previousProfiles =
        persistenceService.query(scoringCondition, null, Profile.class);

    HashMap<String, Object> scriptParams = new HashMap<>();
    scriptParams.put("scoringId", scoring.getItemId());

    for (Profile profileToRemove : previousProfiles) {
      persistenceService.updateWithScript(
          profileToRemove.getItemId(),
          null,
          Profile.class,
          "if (ctx._source.systemProperties.scoreModifiers == null) { ctx._source.systemProperties.scoreModifiers=[:] } ; if (ctx._source.systemProperties.scoreModifiers.containsKey(scoringId)) { ctx._source.scores[scoringId] = ctx._source.systemProperties.scoreModifiers[scoringId] } else { ctx._source.scores.remove(scoringId) }",
          scriptParams);
    }
    if (scoring.getMetadata().isEnabled()) {
      String script =
          "if (ctx._source.scores == null) { ctx._source.scores=[:] } ; if (ctx._source.scores.containsKey(scoringId)) { ctx._source.scores[scoringId] += scoringValue } else { ctx._source.scores[scoringId] = scoringValue }";
      Map<String, Event> updatedProfiles = new HashMap<>();
      for (ScoringElement element : scoring.getElements()) {
        scriptParams.put("scoringValue", element.getValue());
        for (Profile p : persistenceService.query(element.getCondition(), null, Profile.class)) {
          persistenceService.updateWithScript(
              p.getItemId(), null, Profile.class, script, scriptParams);
          Event profileUpdated = new Event("profileUpdated", null, p, null, null, p, new Date());
          profileUpdated.setPersistent(false);
          updatedProfiles.put(p.getItemId(), profileUpdated);
        }
      }
      Iterator<Map.Entry<String, Event>> entries = updatedProfiles.entrySet().iterator();
      while (entries.hasNext()) {
        eventService.send(entries.next().getValue());
      }
    }
    logger.info("Profiles updated in {}", System.currentTimeMillis() - t);
  }
  public void setScoringDefinition(Scoring scoring) {
    for (ScoringElement element : scoring.getElements()) {
      ParserHelper.resolveConditionType(definitionsService, element.getCondition());
    }
    for (ScoringElement element : scoring.getElements()) {
      if (scoring.getMetadata().isEnabled() && !scoring.getMetadata().isMissingPlugins()) {
        updateAutoGeneratedRules(scoring.getMetadata(), element.getCondition());
      }
    }
    // make sure we update the name and description metadata that might not match, so first we
    // remove the entry from the map
    persistenceService.save(scoring);

    persistenceService.createMapping(
        Profile.ITEM_TYPE,
        String.format(
            "{\n"
                + "    \"profile\": {\n"
                + "        \"properties\" : {\n"
                + "            \"scores\": {\n"
                + "                \"properties\": {\n"
                + "                    \"%s\": {\n"
                + "                        \"type\": \"long\"\n"
                + "                    }\n"
                + "                }\n"
                + "            }\n"
                + "        }\n"
                + "    }\n"
                + "}\n",
            scoring.getItemId()));

    updateExistingProfilesForScoring(scoring);
  }
  public SegmentsAndScores getSegmentsAndScoresForProfile(Profile profile) {
    Set<String> segments = new HashSet<String>();
    Map<String, Integer> scores = new HashMap<String, Integer>();

    List<Segment> allSegments = this.allSegments;
    for (Segment segment : allSegments) {
      if (persistenceService.testMatch(segment.getCondition(), profile)) {
        segments.add(segment.getMetadata().getId());
      }
    }

    List<Scoring> allScoring = this.allScoring;
    Map<String, Integer> scoreModifiers =
        (Map<String, Integer>) profile.getSystemProperties().get("scoreModifiers");
    for (Scoring scoring : allScoring) {
      if (scoring.getMetadata().isEnabled()) {
        int score = 0;
        for (ScoringElement scoringElement : scoring.getElements()) {
          if (persistenceService.testMatch(scoringElement.getCondition(), profile)) {
            score += scoringElement.getValue();
          }
        }
        String scoringId = scoring.getMetadata().getId();
        if (scoreModifiers != null
            && scoreModifiers.containsKey(scoringId)
            && scoreModifiers.get(scoringId) != null) {
          score += scoreModifiers.get(scoringId);
        }
        if (score > 0) {
          scores.put(scoringId, score);
        }
      }
    }

    return new SegmentsAndScores(segments, scores);
  }
  private void loadPredefinedScorings(BundleContext bundleContext) {
    Enumeration<URL> predefinedScoringEntries =
        bundleContext.getBundle().findEntries("META-INF/cxs/scoring", "*.json", true);
    if (predefinedScoringEntries == null) {
      return;
    }
    while (predefinedScoringEntries.hasMoreElements()) {
      URL predefinedScoringURL = predefinedScoringEntries.nextElement();
      logger.debug("Found predefined scoring at " + predefinedScoringURL + ", loading... ");

      try {
        Scoring scoring =
            CustomObjectMapper.getObjectMapper().readValue(predefinedScoringURL, Scoring.class);
        if (scoring.getMetadata().getScope() == null) {
          scoring.getMetadata().setScope("systemscope");
        }
        if (getScoringDefinition(scoring.getMetadata().getId()) == null) {
          setScoringDefinition(scoring);
        }
      } catch (IOException e) {
        logger.error("Error while loading segment definition " + predefinedScoringURL, e);
      }
    }
  }
  public DependentMetadata removeSegmentDefinition(String segmentId, boolean validate) {
    Set<Segment> impactedSegments = getSegmentDependentSegments(segmentId);
    Set<Scoring> impactedScorings = getSegmentDependentScorings(segmentId);
    if (!validate || (impactedSegments.isEmpty() && impactedScorings.isEmpty())) {
      // update profiles
      Condition segmentCondition = new Condition();
      segmentCondition.setConditionType(
          definitionsService.getConditionType("profilePropertyCondition"));
      segmentCondition.setParameter("propertyName", "segments");
      segmentCondition.setParameter("comparisonOperator", "equals");
      segmentCondition.setParameter("propertyValue", segmentId);

      List<Profile> previousProfiles =
          persistenceService.query(segmentCondition, null, Profile.class);
      for (Profile profileToRemove : previousProfiles) {
        profileToRemove.getSegments().remove(segmentId);
        persistenceService.update(
            profileToRemove.getItemId(),
            null,
            Profile.class,
            "segments",
            profileToRemove.getSegments());
      }

      // update impacted segments
      for (Segment segment : impactedSegments) {
        Condition updatedCondition =
            updateSegmentDependentCondition(segment.getCondition(), segmentId);
        segment.setCondition(updatedCondition);
        if (updatedCondition == null) {
          clearAutoGeneratedRules(
              persistenceService.query(
                  "linkedItems", segment.getMetadata().getId(), null, Rule.class),
              segment.getMetadata().getId());
          segment.getMetadata().setEnabled(false);
        }
        setSegmentDefinition(segment);
      }

      // update impacted scorings
      for (Scoring scoring : impactedScorings) {
        List<ScoringElement> updatedScoringElements = new ArrayList<>();
        for (ScoringElement scoringElement : scoring.getElements()) {
          Condition updatedCondition =
              updateSegmentDependentCondition(scoringElement.getCondition(), segmentId);
          if (updatedCondition != null) {
            scoringElement.setCondition(updatedCondition);
            updatedScoringElements.add(scoringElement);
          }
        }
        scoring.setElements(updatedScoringElements);
        if (updatedScoringElements.isEmpty()) {
          clearAutoGeneratedRules(
              persistenceService.query(
                  "linkedItems", scoring.getMetadata().getId(), null, Rule.class),
              scoring.getMetadata().getId());
          scoring.getMetadata().setEnabled(false);
        }
        setScoringDefinition(scoring);
      }

      persistenceService.remove(segmentId, Segment.class);
      List<Rule> previousRules =
          persistenceService.query("linkedItems", segmentId, null, Rule.class);
      clearAutoGeneratedRules(previousRules, segmentId);
    }

    List<Metadata> segments = new LinkedList<>();
    List<Metadata> scorings = new LinkedList<>();
    for (Segment definition : impactedSegments) {
      segments.add(definition.getMetadata());
    }
    for (Scoring definition : impactedScorings) {
      scorings.add(definition.getMetadata());
    }
    return new DependentMetadata(segments, scorings);
  }