/*******************************************************************************
* Copyright (c) 2012 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware Inc. - initial contribution
*******************************************************************************/
package org.eclipse.virgo.kernel.install.artifact.internal;
import java.io.File;
import org.eclipse.virgo.util.io.PathReference;
/**
* {@link GenerationalArtifactStore} implements {@link ArtifactStore} by creating a series of paths so that each version
* of the artifact has a fresh path (unless the series wraps which is extremely unlikely in practice). This is designed
* for storing a bundle which will be installed by reference into the OSGi framework since, when the bundle is updated,
* the current version of the bundle may be in use until the bundle becomes unresolved.
* <p />
*
* <strong>Concurrent Semantics</strong><br />
* TODO Document concurrent semantics of GenerationalArtifactStore
*/
final class GenerationalArtifactStore extends AbstractArtifactStore implements ArtifactStore {
private final PathReference baseDirectory;
private long generation;
private final String baseName;
/**
* Constructs a {@link GenerationalArtifactStore} in the directory of the specified path and prepares the path
* storage ready for the new artifact. Each path produced by this store has the same filename as the specified path.
*/
GenerationalArtifactStore(PathReference basePathReference) {
super(basePathReference);
this.baseDirectory = basePathReference.getParent();
this.baseName = basePathReference.getName();
final long recoveredGeneration = recoverLastGeneration(this.baseDirectory);
this.generation = recoveredGeneration == -1 ? 0 : recoveredGeneration;
PathReference currentPathReference = getGenerationPath(this.generation, this.baseDirectory, this.baseName);
if (recoveredGeneration == -1) {
currentPathReference.getParent().createDirectory();
currentPathReference.delete(true);
}
}
private static long recoverLastGeneration(PathReference baseDirectory) {
long lastGeneration = -1;
File file = baseDirectory.toFile();
String[] children = file.list();
if (children != null) {
for (String child : children) {
try {
long childGeneration = Long.parseLong(child);
if (childGeneration > lastGeneration) {
lastGeneration = childGeneration;
}
} catch (NumberFormatException ignored) {
}
}
}
return lastGeneration;
}
/**
* {@inheritDoc}
*/
public PathReference getCurrentPath() {
synchronized (this.monitor) {
return getGenerationPath(this.generation);
}
}
/**
* {@inheritDoc}
*/
@Override
public void save() {
synchronized (this.monitor) {
if (this.generation != 0) {
getSavedPath().delete(true);
}
this.generation++;
super.save();
}
}
/**
* {@inheritDoc}
*/
@Override
public void restore() {
synchronized (this.monitor) {
super.restore();
this.generation--;
}
}
protected PathReference getSavedPath() {
return getGenerationPath(this.generation - 1);
}
private PathReference getGenerationPath(long generation) {
return getGenerationPath(generation, this.baseDirectory, this.baseName);
}
private static PathReference getGenerationPath(long generation, PathReference baseDirectory, String baseName) {
return baseDirectory.newChild(Long.toString(generation)).newChild(baseName);
}
}