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.nio.file.Path;
  import java.util.Calendar;
  
  import javax.persistence.EntityNotFoundException;
  import javax.persistence.PersistenceException;
  import javax.validation.constraints.NotNull;
  
  import org.eclipse.steady.backend.model.Bug;
  import org.eclipse.steady.backend.model.Library;
  import org.eclipse.steady.backend.model.LibraryId;
  import org.eclipse.steady.backend.util.ReferenceUpdater;
  import org.eclipse.steady.shared.enums.DigestAlgorithm;
  import org.eclipse.steady.shared.json.JacksonUtil;
  import org.eclipse.steady.shared.util.FileUtil;
  import org.eclipse.steady.shared.util.StopWatch;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.beans.factory.annotation.Autowired;
  
  /**
   * <p>LibraryRepositoryImpl class.</p>
   */
  public class LibraryRepositoryImpl implements LibraryRepositoryCustom {
  
    private static Logger log = LoggerFactory.getLogger(LibraryRepositoryImpl.class);
  
    /**
     * Required by {@link LibraryRepositoryImpl#customSave(Library)}.
     */
    @Autowired LibraryRepository libRepository;
  
    /**
     * Required by {@link LibraryRepositoryImpl#customSave(Library)}.
     */
    @Autowired LibraryIdRepository libidRepository;
  
    /**
     * Required by {@link BugRepositoryImpl#customSave(Bug)}.
     */
    @Autowired ConstructIdRepository cidRepository;
  
    @Autowired ReferenceUpdater refUpdater;
  
    /** {@inheritDoc} */
    public Library customSave(Library _lib) {
      final StopWatch sw = new StopWatch("Save library " + _lib).start();
      final String digest = _lib.getDigest();
  
      // for backward compatibility to vulas-2.x
      if (_lib.getDigestAlgorithm() == null) {
        log.warn(
            "Library uploaded with vulas 2.x (digestAlgoritm field missing), defaulting to SHA1 for"
                + " backward compatibility");
        _lib.setDigestAlgorithm(DigestAlgorithm.SHA1);
      }
  
      // Does it already exist?
      Library managed_lib = null;
      try {
        managed_lib = LibraryRepository.FILTER.findOne(this.libRepository.findByDigest(digest));
        _lib.setId(managed_lib.getId());
        _lib.setCreatedAt(managed_lib.getCreatedAt());
        _lib.setModifiedAt(Calendar.getInstance());
  
        // keep the existing lib GAV if the newly posted/put doesn't have one
        if (_lib.getLibraryId() == null) {
          // Recreate libId if null (to be removed once we ensure we added to the existing libs)
          if (managed_lib.getLibraryId() == null)
            _lib.setLibraryId(_lib.getLibIdFromMaven(_lib.getDigest()));
          else _lib.setLibraryId(managed_lib.getLibraryId());
        }
  
      } catch (EntityNotFoundException e1) {
        LibraryRepositoryImpl.log.debug(
            "Library [" + _lib.getDigest() + "] does not yet exist, going to save it.");
      }
  
      // Retrieve libId from Maven if digest verified
      if (_lib.getLibraryId() == null) _lib.setLibraryId(_lib.getLibIdFromMaven(_lib.getDigest()));
  
      // Update refs to independent entities
      _lib.setConstructs(refUpdater.saveNestedConstructIds(_lib.getConstructs()));
      sw.lap("Updated refs to nested constructs");
  
      _lib.setProperties(refUpdater.saveNestedProperties(_lib.getProperties()));
      sw.lap("Updated refs to nested properties");
  
      _lib.setBundledLibraryIds(refUpdater.saveNestedBundledLibraryIds(_lib.getBundledLibraryIds()));
  
      // we always verify the digest to make sure all fields are filled and check that
      // libraryId provided by the client is known (replaced with known one otherwise)
      // Note that this replaces digestVerificationUrl, digestTimestamp and WellknownDigest
      _lib.verifyDigest();
  
      _lib = this.saveNestedLibraryId(_lib);
  
      // Save
      try {
        managed_lib = this.libRepository.save(_lib);
        sw.stop();
      } catch (Exception e) {
        sw.stop(e);
        LibraryRepositoryImpl.log.error(
            "Error while saving lib ["
                + digest
                + "]: "
                + e.getMessage()
                + " ----- Going to save JSON and store incomplete library.");
  
        // Save lib to temporay JSON file
        Path temp_file = null;
        try {
          _lib.getLibraryId().setAffLibraries(null);
          temp_file = FileUtil.writeToTmpFile("library", "json", JacksonUtil.asJsonString(_lib));
          log.info("To-be-saved library serialized to temporary JSON file [" + temp_file + "]");
        } catch (Exception ioe) {
          log.error(
              "Error while serializing to-be-saved library to to temporary JSON file: "
                  + ioe.getMessage());
        }
  
        managed_lib = saveIncomplete(_lib);
      }
  
      return managed_lib;
    }
  
    private Library saveNestedLibraryId(@NotNull Library _lib) {
      final LibraryId provided_libid = _lib.getLibraryId();
      LibraryId managed_libid = null;
      if (provided_libid != null) {
        try {
          managed_libid =
              LibraryIdRepository.FILTER.findOne(
                  this.libidRepository.findBySecondaryKey(
                      provided_libid.getMvnGroup(),
                      provided_libid.getArtifact(),
                      provided_libid.getVersion()));
        } catch (EntityNotFoundException e) {
          managed_libid = this.libidRepository.save(provided_libid);
        }
        _lib.setLibraryId(managed_libid);
      }
      return _lib;
    }
  
    /** {@inheritDoc} */
    public Library saveIncomplete(Library _lib) throws PersistenceException {
      Library incomplete = new Library(_lib.getDigest());
      incomplete.setDigestAlgorithm(_lib.getDigestAlgorithm());
      if (_lib.getLibraryId() != null) {
        LibraryRepositoryImpl.log.debug(
            "Setting library Id ["
                + _lib.getLibraryId().toString()
                + "] of incomplete library ["
                + _lib.getDigest()
                + "]");
        incomplete.setLibraryId(_lib.getLibraryId());
      } else incomplete.setLibraryId(null);
  
      if (_lib.getConstructs() != null)
        LibraryRepositoryImpl.log.debug(
            "Library ["
                + _lib.getDigest()
                + "] to be saved has ["
                + _lib.getConstructs().size()
                + "] constructs");
      if (_lib.getProperties() != null)
        LibraryRepositoryImpl.log.debug(
            "Library ["
                + _lib.getDigest()
                + "] to be saved has ["
                + _lib.getProperties().size()
                + "] properties");
  
      try {
        return this.libRepository.save(incomplete);
      } catch (Exception e) {
        throw new PersistenceException(
            "Error while saving incomplete lib [" + incomplete.getDigest() + "]: " + e.getMessage());
      }
    }
  }
  