/*************************GO-LICENSE-START*********************************
* Copyright 2014 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.
*************************GO-LICENSE-END***********************************/
package com.thoughtworks.go.server.cache;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListSet;
import com.thoughtworks.go.server.service.ArtifactsDirHolder;
/**
* @understands serving prepared artifacts and preparing artifact offline
*/
public abstract class ArtifactCache<T> {
protected final ArtifactsDirHolder artifactsDirHolder;
protected ConcurrentSkipListSet<T> pendingCacheFiles = new ConcurrentSkipListSet<>();
protected ConcurrentMap<T, Exception> pendingExceptions = new ConcurrentHashMap<>();
public static final String CACHE_ARTIFACTS_FOLDER = "cache/artifacts/";
public ArtifactCache(ArtifactsDirHolder artifactsDirHolder) {
this.artifactsDirHolder = artifactsDirHolder;
}
public boolean cacheCreated(T artifactLocation) throws Exception {
if (currentlyCreatingCache(artifactLocation)) { return false; }
if (exceptionCreatingCache(artifactLocation)) {
Exception e = pendingExceptions.get(artifactLocation);
if (e != null && pendingExceptions.remove(artifactLocation, e)) {
throw e;
} else {
return false;
}
}
if (cacheAlreadyCreated(artifactLocation)) { return true; }
startCacheCreationThread(artifactLocation);
return false;
}
private boolean exceptionCreatingCache(T artifactLocation) {
return pendingExceptions.containsKey(artifactLocation);
}
private boolean cacheAlreadyCreated(T artifactLocation) {
return cachedFile(artifactLocation).exists();
}
private boolean currentlyCreatingCache(T artifactLocation) {
return pendingCacheFiles.contains(artifactLocation);
}
protected void startCacheCreationThread(final T artifactLocation) {
boolean inserted = pendingCacheFiles.add(artifactLocation);
if (inserted) {
Thread cacheCreatorThread = new Thread("cache-creator-thread-" + UUID.randomUUID().toString()) {
public void run() {
try {
createCachedFile(artifactLocation);
} catch (Exception e) {
pendingExceptions.putIfAbsent(artifactLocation, e);
} finally {
pendingCacheFiles.remove(artifactLocation);
}
}
};
cacheCreatorThread.start();
}
}
public abstract File cachedFile(T artifactLocation);
abstract void createCachedFile(T artifactLocation) throws IOException;
}