com.thoughtworks.go.server.service.ArtifactsService.java Source code

Java tutorial

Introduction

Here is the source code for com.thoughtworks.go.server.service.ArtifactsService.java

Source

/*
 * Copyright 2019 ThoughtWorks, Inc.
 *
 * 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.
 */
package com.thoughtworks.go.server.service;

import com.thoughtworks.go.domain.ArtifactUrlReader;
import com.thoughtworks.go.domain.JobIdentifier;
import com.thoughtworks.go.domain.Stage;
import com.thoughtworks.go.domain.StageIdentifier;
import com.thoughtworks.go.domain.exception.IllegalArtifactLocationException;
import com.thoughtworks.go.server.dao.StageDao;
import com.thoughtworks.go.server.view.artifacts.ArtifactDirectoryChooser;
import com.thoughtworks.go.server.view.artifacts.BuildIdArtifactLocator;
import com.thoughtworks.go.server.view.artifacts.PathBasedArtifactsLocator;
import com.thoughtworks.go.util.*;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipInputStream;

import static java.lang.String.format;

@Service
public class ArtifactsService implements ArtifactUrlReader {
    private final ArtifactsDirHolder artifactsDirHolder;
    private final ZipUtil zipUtil;
    private final JobResolverService jobResolverService;
    private final StageDao stageDao;
    private SystemService systemService;
    public static final Logger LOGGER = LoggerFactory.getLogger(ArtifactsService.class);
    public static final String LOG_XML_NAME = "log.xml";
    private ArtifactDirectoryChooser chooser;

    @Autowired
    public ArtifactsService(JobResolverService jobResolverService, StageDao stageDao,
            ArtifactsDirHolder artifactsDirHolder, ZipUtil zipUtil, SystemService systemService) {
        this(jobResolverService, stageDao, artifactsDirHolder, zipUtil, systemService,
                new ArtifactDirectoryChooser());
    }

    protected ArtifactsService(JobResolverService jobResolverService, StageDao stageDao,
            ArtifactsDirHolder artifactsDirHolder, ZipUtil zipUtil, SystemService systemService,
            ArtifactDirectoryChooser chooser) {
        this.artifactsDirHolder = artifactsDirHolder;
        this.zipUtil = zipUtil;
        this.jobResolverService = jobResolverService;
        this.stageDao = stageDao;
        this.systemService = systemService;

        //This is a Chain of Responsibility to decide which view should be shown for a particular artifact URL
        this.chooser = chooser;

    }

    public void initialize() {
        chooser.add(new PathBasedArtifactsLocator(artifactsDirHolder.getArtifactsDir()));
        chooser.add(new BuildIdArtifactLocator(artifactsDirHolder.getArtifactsDir()));
    }

    public boolean saveFile(File dest, InputStream stream, boolean shouldUnzip, int attempt) {
        String destPath = dest.getAbsolutePath();
        try {
            LOGGER.trace("Saving file [{}]", destPath);
            if (shouldUnzip) {
                zipUtil.unzip(new ZipInputStream(stream), dest);
            } else {
                systemService.streamToFile(stream, dest);
            }
            LOGGER.trace("File [{}] saved.", destPath);
            return true;
        } catch (IOException e) {
            final String message = format("Failed to save the file to: [%s]", destPath);
            if (attempt < GoConstants.PUBLISH_MAX_RETRIES) {
                LOGGER.warn(message, e);
            } else {
                LOGGER.error(message, e);
            }
            return false;
        } catch (IllegalPathException e) {
            final String message = format("Failed to save the file to: [%s]", destPath);
            LOGGER.error(message, e);
            return false;
        }
    }

    public boolean saveOrAppendFile(File dest, InputStream stream) {
        String destPath = dest.getAbsolutePath();
        try {
            LOGGER.trace("Appending file [{}]", destPath);
            systemService.streamToFile(stream, dest);
            LOGGER.trace("File [{}] appended.", destPath);
            return true;
        } catch (IOException e) {
            LOGGER.error("Failed to save the file to : [{}]", destPath, e);
            return false;
        }
    }

    public File findArtifact(JobIdentifier identifier, String path) throws IllegalArtifactLocationException {
        return chooser.findArtifact(identifier, path);
    }

    public String findArtifactRoot(JobIdentifier identifier) throws IllegalArtifactLocationException {
        JobIdentifier id = jobResolverService.actualJobIdentifier(identifier);
        try {
            String fullArtifactPath = chooser.findArtifact(id, "").getCanonicalPath();
            String artifactRoot = artifactsDirHolder.getArtifactsDir().getCanonicalPath();
            String relativePath = fullArtifactPath.replace(artifactRoot, "");
            if (relativePath.startsWith(File.separator)) {
                relativePath = relativePath.replaceFirst("\\" + File.separator, "");
            }
            return relativePath;
        } catch (IOException e) {
            throw new IllegalArtifactLocationException("No artifact found.", e);
        }
    }

    public String findArtifactUrl(JobIdentifier jobIdentifier) {
        JobIdentifier actualId = jobResolverService.actualJobIdentifier(jobIdentifier);
        return format("/files/%s", actualId.buildLocator());
    }

    public String findArtifactUrl(JobIdentifier jobIdentifier, String path) {
        return format("%s/%s", findArtifactUrl(jobIdentifier), path);
    }

    public File getArtifactLocation(String path) throws IllegalArtifactLocationException {
        try {
            File file = new File(artifactsDirHolder.getArtifactsDir(), path);
            if (!FileUtil.isSubdirectoryOf(artifactsDirHolder.getArtifactsDir(), file)) {
                throw new IllegalArtifactLocationException("Illegal artifact path " + path);
            }
            return file;
        } catch (Exception e) {
            throw new IllegalArtifactLocationException("Illegal artifact path " + path);
        }
    }

    public void purgeArtifactsForStage(Stage stage) {
        StageIdentifier stageIdentifier = stage.getIdentifier();
        try {
            File stageRoot = chooser.findArtifact(stageIdentifier, "");
            File cachedStageRoot = chooser.findCachedArtifact(stageIdentifier);
            deleteFile(cachedStageRoot);
            boolean didDelete = deleteArtifactsExceptCruiseOutputAndPluggableArtifactMetadata(stageRoot);

            if (!didDelete) {
                LOGGER.error("Artifacts for stage '{}' at path '{}' was not deleted",
                        stageIdentifier.entityLocator(), stageRoot.getAbsolutePath());
            }
        } catch (Exception e) {
            LOGGER.error("Error occurred while clearing artifacts for '{}'. Error: '{}'",
                    stageIdentifier.entityLocator(), e.getMessage(), e);
        }
        stageDao.markArtifactsDeletedFor(stage);
        LOGGER.debug("Marked stage '{}' as artifacts deleted.", stageIdentifier.entityLocator());
    }

    private boolean deleteArtifactsExceptCruiseOutputAndPluggableArtifactMetadata(File stageRoot)
            throws IOException {
        File[] jobs = stageRoot.listFiles();
        if (jobs == null) { // null if security restricted
            throw new IOException("Failed to list contents of " + stageRoot);
        }

        boolean didDelete = true;

        for (File jobRoot : jobs) {
            File[] artifacts = jobRoot.listFiles();
            if (artifacts == null) { // null if security restricted
                throw new IOException("Failed to list contents of " + stageRoot);
            }
            for (File artifact : artifacts) {
                if (artifact.isDirectory() && (artifact.getName().equals(ArtifactLogUtil.CRUISE_OUTPUT_FOLDER)
                        || artifact.getName().equals(ArtifactLogUtil.PLUGGABLE_ARTIFACT_METADATA_FOLDER))) {
                    continue;
                }
                didDelete &= deleteFile(artifact);
            }
        }
        return didDelete;
    }

    private boolean deleteFile(File file) {
        return FileUtils.deleteQuietly(file);
    }

}