package ca.carleton.gcrc.couch.app;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.security.MessageDigest;
import net.sf.json.JSONObject;
import net.sf.json.util.JSONTokener;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import ca.carleton.gcrc.couch.client.CouchDb;
public class DocumentPush {
final protected Logger logger = Logger.getLogger(this.getClass());
final static public String DOC_SIG_KEY = "nunaliit_signature";
private CouchDb couchDb;
private File file;
public DocumentPush() {
}
public DocumentPush(
CouchDb couchDb
,File file
) {
this.couchDb = couchDb;
this.file = file;
}
public CouchDb getCouchDb() {
return couchDb;
}
public void setCouchDb(CouchDb couchDb) {
this.couchDb = couchDb;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public void push() throws Exception {
String docId = null;
// Load document
StringWriter docWriter = new StringWriter();
JSONObject doc = new JSONObject();
try {
JSONFileLoader builder = new JSONFileLoader(file);
builder.write(docWriter);
JSONTokener jsonTokener = new JSONTokener(docWriter.toString());
Object obj = jsonTokener.nextValue();
if( obj instanceof JSONObject ) {
doc = (JSONObject)obj;
} else {
throw new Exception("Unexpected returned object type: "+obj.getClass().getSimpleName());
}
docId = doc.getString("_id");
} catch(Exception e) {
throw new Exception("Unable to load document", e);
}
// Compute signature
String signature = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(baos, "UTF-8");
osw.write(docWriter.toString());
osw.flush();
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(baos.toByteArray());
byte[] sigBytes = md.digest();
// B64
byte[] encoded = Base64.encodeBase64(sigBytes);
ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
InputStreamReader isr = new InputStreamReader(bais, "UTF-8");
BufferedReader br = new BufferedReader(isr);
signature = br.readLine();
// Add signature to JSON doc
doc.put(DOC_SIG_KEY, signature);
logger.info("Document signature ("+docId+"): "+signature);
} catch(Exception e) {
throw new Exception("Unable to compute signature on document", e);
}
// Check if doc exists
boolean creationRequired = false;
boolean updateNeeded = false;
try {
if( false == couchDb.documentExists(docId) ) {
creationRequired = true;
} else {
// Check if it is the right signature
JSONObject currentDoc = couchDb.getDocument(docId);
if( false == currentDoc.containsKey(DOC_SIG_KEY) ) {
updateNeeded = true;
} else {
String currentSignature = currentDoc.getString(DOC_SIG_KEY);
if( false == signature.equals(currentSignature) ) {
updateNeeded = true;
}
}
// Update revision
doc.put("_rev", currentDoc.get("_rev"));
}
} catch(Exception e) {
throw new Exception("Unable to access current document", e);
}
// Upload, if required
if( creationRequired ) {
logger.info("Creating document: "+docId);
try {
couchDb.createDocument(doc);
} catch (Exception e) {
throw new Exception("Unable to create document", e);
}
} else if( updateNeeded ) {
logger.info("Uploading document: "+docId);
try {
couchDb.updateDocument(doc);
} catch (Exception e) {
throw new Exception("Unable to update document", e);
}
}
}
}