package org.couchbase.mock;
import org.couchbase.mock.client.RestAPIUtil;
import org.couchbase.mock.memcached.protocol.ErrorCode;
import org.couchbase.mock.util.ReaderUtils;
import org.tukaani.xz.LZMA2Options;
import org.tukaani.xz.XZInputStream;
import org.tukaani.xz.XZOutputStream;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* This is a miniature version of the {@code cbdocloader} tool.
*/
public class DocumentLoader {
static final Pattern ptnDESIGN = Pattern.compile(".*/design_docs/(.*)\\.json$");
static final Pattern ptnDOCUMENT = Pattern.compile(".*/docs/(.*)\\.json$");
private final CouchbaseMock mock;
private final Bucket bucket;
/**
* Create a new document loader
* @param mock The cluster
* @param bucketName The name of the bucket in which the documents should be loaded. The bucket must exist
*/
public DocumentLoader(CouchbaseMock mock, String bucketName) {
this.mock = mock;
if (mock != null) {
Map<String, Bucket> buckets = mock.getBuckets();
bucket = buckets.get(bucketName);
if (bucket == null) {
throw new IllegalArgumentException("No such bucket!");
}
} else {
bucket = null;
}
}
protected void handleDocument(String docId, String contents) {
ErrorCode result = bucket.storeItem(docId, contents.getBytes(Charset.forName("UTF-8")));
if (result.value() != ErrorCode.SUCCESS.value()) {
throw new RuntimeException("Couldn't store: " + result.value());
}
}
protected void handleDesign(String designName, String contents) throws IOException {
RestAPIUtil.defineDesignDocument(mock, designName, contents, bucket.getName());
}
/**
* Load documents into the bucket
* @param docsFile The path to the ZIP file which contains the documents
* @throws IOException
*/
public void loadDocuments(String docsFile) throws IOException {
ZipFile zipFile = new ZipFile(docsFile);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
int numDocs = 0;
int numDesigns = 0;
while (entries.hasMoreElements()) {
ZipEntry ent = entries.nextElement();
String fName = ent.getName();
InputStream is = zipFile.getInputStream(ent);
String contents = ReaderUtils.fromStream(is);
Matcher mIsDoc = ptnDOCUMENT.matcher(fName);
if (mIsDoc.matches()) {
String docId = mIsDoc.group(1);
handleDocument(docId, contents);
numDocs++;
continue;
}
Matcher mIsDesign = ptnDESIGN.matcher(fName);
if (mIsDesign.matches()) {
String designName = mIsDesign.group(1);
handleDesign(designName, contents);
numDesigns++;
}
}
System.err.printf("Loaded %d documents. %d design documents%n", numDocs, numDesigns);
}
static class StoredInfo implements Serializable {
final Map<String,String> designs = new HashMap<String, String>();
final Map<String,String> documents = new HashMap<String, String>();
}
static class BundleSerializer extends DocumentLoader {
final StoredInfo toStore = new StoredInfo();
BundleSerializer() {
super(null, null);
}
@Override
protected void handleDocument(String id, String contents) {
toStore.documents.put(id, contents);
}
@Override
protected void handleDesign(String id, String contents) {
toStore.designs.put(id, contents);
}
}
/**
* Loads the {@code beer-sample} documents from the built-in serialized compressed resource.
* @param is The input stream
* @param bucketName The target bucket into which the docs should be loaded
* @param mock The cluster
* @throws IOException
*/
public static void loadFromSerializedXZ(InputStream is, String bucketName, CouchbaseMock mock) throws IOException {
XZInputStream xzi = new XZInputStream(is);
ObjectInputStream ois = new ObjectInputStream(xzi);
StoredInfo si;
try {
si = (StoredInfo) ois.readObject();
} catch (ClassNotFoundException ex) {
throw new IOException(ex);
}
DocumentLoader loader = new DocumentLoader(mock, bucketName);
for (Map.Entry<String,String> ent : si.documents.entrySet()) {
loader.handleDocument(ent.getKey(), ent.getValue());
}
for (Map.Entry<String,String> ent: si.designs.entrySet()) {
loader.handleDesign(ent.getKey(), ent.getValue());
}
System.err.printf("Finished loading %d documents and %d designs into %s%n", si.documents.size(), si.designs.size(), bucketName);
}
/**
* Load the {@code `beer-sample`} bucket
* @param mock The cluster
* @throws IOException
*/
public static void loadBeerSample(CouchbaseMock mock) throws IOException {
InputStream iss = CouchbaseMock.class.getClassLoader().getResourceAsStream("views/beer-sample.serialized.xz");
DocumentLoader.loadFromSerializedXZ(iss, "beer-sample", mock);
}
/**
* Converts a zip file into a serialized compress resource.
* @param args The ZIP file
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String input = args[0];
File outputFile = new File(input.replace(".zip", "") + ".serialized.xz");
// Get the base name
FileOutputStream fos = new FileOutputStream(outputFile);
LZMA2Options options = new LZMA2Options(9);
XZOutputStream xzo = new XZOutputStream(fos, options);
ObjectOutputStream oos = new ObjectOutputStream(xzo);
BundleSerializer ml = new BundleSerializer();
ml.loadDocuments(input);
oos.writeObject(ml.toStore);
oos.flush();
oos.close();
}
}