code: /**
   * This file is part of Eclipse Steady.
   *
   * 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.
   *
   * SPDX-License-Identifier: Apache-2.0
   * SPDX-FileCopyrightText: Copyright (c) 2018-2020 SAP SE or an SAP affiliate company and Eclipse Steady contributors
   */
  package org.eclipse.steady.backend.repo;
  
  import java.util.Collection;
  import java.util.HashSet;
  import java.util.Iterator;
  
  import javax.persistence.EntityNotFoundException;
  import javax.persistence.PersistenceException;
  
  import org.eclipse.steady.backend.model.Application;
  import org.eclipse.steady.backend.model.GoalExecution;
  import org.eclipse.steady.backend.model.Property;
  import org.eclipse.steady.backend.util.ReferenceUpdater;
  import org.eclipse.steady.shared.enums.GoalType;
  import org.eclipse.steady.shared.util.StringList;
  import org.eclipse.steady.shared.util.VulasConfiguration;
  import org.eclipse.steady.shared.util.StringList.CaseSensitivity;
  import org.eclipse.steady.shared.util.StringList.ComparisonMode;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.beans.factory.annotation.Autowired;
  
  /**
   * <p>GoalExecutionRepositoryImpl class.</p>
   */
  public class GoalExecutionRepositoryImpl implements GoalExecutionRepositoryCustom {
  
    private static Logger log = LoggerFactory.getLogger(GoalExecutionRepositoryImpl.class);
  
    @Autowired GoalExecutionRepository gexeRepository;
  
    @Autowired ApplicationRepository appRepository;
  
    @Autowired ReferenceUpdater refUpdater;
  
    // @CacheEvict(value="gexe", key="#_app")
    /** {@inheritDoc} */
    @Override
    public GoalExecution customSave(Application _app, GoalExecution _provided_gexe) {
      GoalExecution managed_gexe = null;
  
      try {
        managed_gexe =
            GoalExecutionRepository.FILTER.findOne(
                this.gexeRepository.findByExecutionId(_provided_gexe.getExecutionId()));
        _provided_gexe.setId(managed_gexe.getId());
        _provided_gexe.setCreatedAt(managed_gexe.getCreatedAt());
      } catch (EntityNotFoundException e1) {
      }
  
      // Update refs to independent entities
      _provided_gexe.setApp(_app);
      _provided_gexe.setConfiguration(
          refUpdater.saveNestedProperties(_provided_gexe.getConfiguration()));
      _provided_gexe.setSystemInfo(
          refUpdater.saveNestedProperties(this.filterSystemInfo(_provided_gexe.getSystemInfo())));
  
      // update the lastScan timestamp of the application (we already have a managed application here)
      appRepository.refreshLastScanbyApp(_app);
  
      // Save
      try {
        managed_gexe = this.gexeRepository.save(_provided_gexe);
      } catch (Exception e) {
        throw new PersistenceException(
            "Error while saving goal execution [" + _provided_gexe + "]: " + e.getMessage());
      }
      return managed_gexe;
    }
  
    // @Cacheable(value="gexe", key="#_app", sync=true) //, unless="#result.isEmpty()") // Note that
    // in Spring proxy mode (default), only external calls will be cached. Calls within the class
    // (this....) will not.
    /** {@inheritDoc} */
    @Override
    public GoalExecution findLatestGoalExecution(Application _app, GoalType _type) {
      Long id = null;
      if (_type != null) id = this.gexeRepository.findLatestForApp(_app.getId(), _type.toString());
      else id = this.gexeRepository.findLatestForApp(_app.getId());
      if (id != null) return this.gexeRepository.findById(id).orElse(null);
      else return null;
    }
  
    /**
     * Only keeps system info properties whose name matches the configured whitelist.
     * @param _in
     * @return
     */
    private Collection<Property> filterSystemInfo(Collection<Property> _in) {
      final StringList env_whitelist =
          VulasConfiguration.getGlobal()
              .getStringList(VulasConfiguration.ENV_VARS, VulasConfiguration.ENV_VARS_CUSTOM);
      final StringList sys_whitelist =
          VulasConfiguration.getGlobal()
              .getStringList(VulasConfiguration.SYS_PROPS, VulasConfiguration.SYS_PROPS_CUSTOM);
      final Collection<Property> out = new HashSet<Property>();
      final Iterator<Property> iter = _in.iterator();
      while (iter.hasNext()) {
        final Property p = iter.next();
        if (sys_whitelist.contains(
                p.getName(), ComparisonMode.STARTSWITH, CaseSensitivity.CASE_INSENSITIVE)
            || env_whitelist.contains(
                p.getName(), ComparisonMode.EQUALS, CaseSensitivity.CASE_INSENSITIVE)) out.add(p);
      }
      return out;
    }
  }
  