content: package alien4cloud.images;
  
  import java.awt.image.BufferedImage;
  import java.beans.IntrospectionException;
  import java.io.ByteArrayInputStream;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.nio.file.Paths;
  import java.util.UUID;
  
  import javax.annotation.PostConstruct;
  import javax.annotation.Resource;
  import javax.imageio.ImageIO;
  
  import lombok.extern.slf4j.Slf4j;
  
  import org.elasticsearch.mapping.MappingBuilder;
  import org.springframework.beans.factory.annotation.Required;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.stereotype.Component;
  
  import alien4cloud.dao.ESGenericIdDAO;
  import alien4cloud.exception.IndexingServiceException;
  import alien4cloud.exception.NotFoundException;
  import alien4cloud.images.exception.ImageUploadException;
  import alien4cloud.utils.ImageQuality;
  import alien4cloud.utils.ImageResizeUtil;
  
  /**
   * A dao to store/load images.
   */
  @Slf4j
  @Component("image-dao")
  public class ImageDAO extends ESGenericIdDAO implements IImageDAO {
      @Resource
      private MappingBuilder mappingBuilder;
      private Path rootPath;
  
      @Required
      @Value("${directories.alien}/${directories.images}")
      public void setRootPath(String path) throws IOException {
          this.rootPath = Paths.get(path).toAbsolutePath();
          if (!Files.exists(rootPath)) {
              Files.createDirectories(rootPath);
          }
      }
  
      @PostConstruct
      public void initEnvironment() {
          // init ES annotation scanning
          try {
              mappingBuilder.initialize(ImageData.class.getPackage().getName());
          } catch (IntrospectionException | IOException e) {
              throw new IndexingServiceException("Could not initialize elastic search mapping builder", e);
          }
          // init indexes and mapped classes
          initIndices(ImageData.class.getSimpleName().toLowerCase(), null, ImageData.class);
          initCompleted();
      }
  
      @Override
      public String writeImage(byte[] imageBytes) {
          String iconId = UUID.randomUUID().toString();
          ImageData imageData = new ImageData();
          imageData.setData(imageBytes);
          imageData.setId(iconId);
          writeImage(imageData);
          return iconId;
      }
  
      @Override
      public void writeImage(final ImageData imageData) {
          // resize the image to store the different available qualities.
          InputStream is = new ByteArrayInputStream(imageData.getData());
          try {
              BufferedImage original = ImageIO.read(is);
              if (original == null) {
                  throw new ImageUploadException("The image is not valid and cannot be read");
              }
              resizeAndWrite(getImageId(ImageQuality.QUALITY_16, imageData.getId()), original, ImageQuality.QUALITY_16.getSize());
              resizeAndWrite(getImageId(ImageQuality.QUALITY_32, imageData.getId()), original, ImageQuality.QUALITY_32.getSize());
              resizeAndWrite(getImageId(ImageQuality.QUALITY_64, imageData.getId()), original, ImageQuality.QUALITY_64.getSize());
              resizeAndWrite(getImageId(ImageQuality.QUALITY_128, imageData.getId()), original, ImageQuality.QUALITY_128.getSize());
              // resizeAndWrite(getImageId(ImageQuality.QUALITY_512, imageData.getId()), original, ImageQuality.QUALITY_512.getSize());
  
              saveAsPng(imageData.getId(), original);
          } catch (IOException e) {
              throw new ImageUploadException("Unable to write uploaded image to data source", e);
          }
      }
  
      private void resizeAndWrite(final String imageId, final BufferedImage original, final int size) throws IOException {
          BufferedImage target = ImageResizeUtil.resizeImageWithHint(original, size, size, true);
          saveAsPng(imageId, target);
      }
  
      private void saveAsPng(String imageId, BufferedImage target) throws IOException {
          FileOutputStream fos = new FileOutputStream(rootPath.resolve(imageId + ".png").toFile());
          try {
              ImageIO.write(target, "png", fos);
              fos.flush();
          } finally {
              fos.close();
          }
          // save in elastic search
          ImageData imageData = new ImageData();
          imageData.setId(imageId);
          imageData.setMime("image/png");
          this.save(imageData);
      }
  
      @Override
      public ImageData readImage(final String id, ImageQuality imageQuality) {
          ImageData imageData = findById(ImageData.class, getImageId(imageQuality, id));
          if (imageData == null) {
              throw new NotFoundException("Unable to find image.");
          }
          if (imageData.getData() == null) {
              try {
                  imageData.setData(Files.readAllBytes(rootPath.resolve(imageData.getId() + ".png")));
              } catch (IOException e) {
                  throw new NotFoundException("Unable to find image on disk.");
              }
          }
          return imageData;
      }
  
      @Override
      public void delete(String id) {
          delete(ImageData.class, id);
          // delete image from hard drive
          safeDeleteFile(rootPath.resolve(id + ".png"));
      }
  
      @Override
      public void deleteAll(String id) {
          delete(id);
          delete(getImageId(ImageQuality.QUALITY_16, id));
          delete(getImageId(ImageQuality.QUALITY_32, id));
          delete(getImageId(ImageQuality.QUALITY_64, id));
          delete(getImageId(ImageQuality.QUALITY_128, id));
      }
  
      private void safeDeleteFile(Path file) {
          try {
              Files.deleteIfExists(file);
          } catch (IOException e) {
              log.error("Error when trying to delete image <" + file + ">", e);
          }
      }
  
      private String getImageId(final ImageQuality imageQuality, final String id) {
          switch (imageQuality) {
          case QUALITY_16:
              return imageQuality.name() + id;
          case QUALITY_32:
              return imageQuality.name() + id;
          case QUALITY_64:
              return imageQuality.name() + id;
          case QUALITY_128:
              return imageQuality.name() + id;
          case QUALITY_512:
              return imageQuality.name() + id;
          default:
              return id;
          }
      }
  }