/*
* Copyright 2009-2012 by KNURT Systeme (http://www.knurt.de)
*
* Licensed under the Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://creativecommons.org/licenses/by-nc-sa/3.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 de.knurt.fam.core.persistence.dao.couchdb;
import java.util.Date;
import java.util.Observable;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.jcouchdb.db.Database;
import org.jcouchdb.db.Response;
import org.jcouchdb.db.ServerImpl;
import org.svenson.JSONParseException;
import org.svenson.JSONParser;
import de.knurt.fam.connector.FamConnector;
import de.knurt.fam.core.aspects.logging.FamLog;
import de.knurt.fam.core.model.persist.User;
import de.knurt.fam.core.model.persist.document.FamBaseDocument;
import de.knurt.fam.core.persistence.dao.FamDocumentDao;
import de.knurt.heinzelmann.util.query.QueryString;
/**
* dao for couchdb
*
* @author Daniel Oltmanns <info@knurt.de>
* @since 1.20 (08/13/2010)
*/
public class FamCouchDBDao extends Observable implements FamDocumentDao {
// private Database database;
/** one and only instance of CouchDBDao */
private volatile static FamCouchDBDao me;
/** construct CouchDBDao */
private FamCouchDBDao() {
}
/**
* return the one and only instance of CouchDBDao
*
* @return the one and only instance of CouchDBDao
*/
public static FamCouchDBDao getInstance() {
if (me == null) { // no instance so far
synchronized (FamCouchDBDao.class) {
if (me == null) { // still no instance so far
me = new FamCouchDBDao(); // the one and only
}
}
}
return me;
}
@Override
public synchronized boolean createDocument(FamBaseDocument document) {
boolean result = true;
document.setCreated(new Date().getTime());
try {
database().createDocument(document);
document.setHasBeenCreated();
setChanged();
notifyObservers(document);
} catch (Exception e) {
FamLog.exception(e, 201203071217l);
result = false;
}
return result;
}
public JSONParser getJSONParserUsed() {
return database().getJsonConfig().getJsonParser();
}
/**
* put the given body without any validation into the database under a
* random uuid.
*
* @param body
* @return the response for the put request
*/
public Response put(String body) {
return database().getServer().put("/" + FamConnector.getGlobalProperty("couchdb_dbname") + "/" + this.getUuid(), body);
}
public byte[] getAttachment(String docId, String attachmentId) {
return database().getAttachment(docId, attachmentId);
}
private String getUuid() {
return database().getServer().getUUIDs(1).get(0);
}
public String getContentAsString(String uri) {
Response response = response(uri);
String result = "";
try {
result = response.getContentAsString().trim();
} finally {
if (response != null)
response.destroy();
}
return result;
}
public <R> R getContentAsBean(String uri, QueryString queryString, Class<R> cls) throws JSONParseException {
Response response = response(uri + "?" + queryString.getAsQueryParams(false));
R result = null;
try {
result = response.getContentAsBean(cls);
} finally {
if (response != null)
response.destroy();
}
return result;
}
public String getContentAsString(String uri, QueryString queryString) {
return this.getContentAsString(uri + "?" + queryString.getAsQueryParams(false));
}
/**
* return one document as the result class given
*
* @param <R>
* class document converted to
* @param docId
* search for
* @param resultClass
* document converted to
* @return on document as the result class object or null
* @see Database#getDocument(Class, String);
*/
public <R> R getOne(String docId, Class<R> resultClass) {
return database().getDocument(resultClass, docId);
}
/**
* alias for {@link #getOne(String, Class)}
*/
public <R> R getContentAsBean(String docId, Class<R> resultClass) {
return this.getOne(docId, resultClass);
}
/** {@inheritDoc} */
@Override
public synchronized boolean updateDocument(FamBaseDocument documentToUpdate, FamBaseDocument existingDocument) {
// update doc
documentToUpdate.setId(existingDocument.getId());
documentToUpdate.setRevision(existingDocument.getRevision());
return this.updateDocument(documentToUpdate);
}
/** {@inheritDoc} */
@Override
public synchronized boolean updateDocument(FamBaseDocument document) {
boolean result = true;
document.setCreated(new Date().getTime());
try {
database().updateDocument(document);
} catch (Exception e) {
FamLog.exception(e, 201203071218l);
result = false;
}
if (result) {
FamLog.info("update document: " + document.getId(), 201203080925l);
}
return result;
}
protected static Database database() {
String host = FamConnector.getGlobalProperty("couchdb_ip");
int port = Integer.parseInt(FamConnector.getGlobalProperty("couchdb_port"));
String name = FamConnector.getGlobalProperty("couchdb_dbname");
return new Database(new ServerImpl(host, port), name);
}
protected static Database admindatabase(User auth) {
if (auth.isAdmin()) {
String username = FamConnector.getGlobalProperty("couchdb_username");
String userpass = FamConnector.getGlobalProperty("couchdb_userpass");
String ip = FamConnector.getGlobalProperty("couchdb_ip");
String host = String.format("%s:%s@%s", username, userpass, ip);
int port = Integer.parseInt(FamConnector.getGlobalProperty("couchdb_port"));
String name = FamConnector.getGlobalProperty("couchdb_dbname");
ServerImpl s = new ServerImpl(host, port);
AuthScope authScope = new AuthScope(host, port, "_admin");
Credentials credentials = new UsernamePasswordCredentials(username, userpass);
s.setCredentials(authScope, credentials);
return new Database(s, name);
} else {
FamLog.error("this must be called by an admin", 201205041254l);
return null;
}
}
public String databaseName() {
return database().getName();
}
public long documentCount() {
return database().getStatus().getDocumentCount();
}
/**
* return the response object for the given uri. DO NOT FORGET TO DESTROY
* THE RESPONSE!!!
*/
protected static Response response(String uri) {
return database().getServer().get("/" + FamConnector.getGlobalProperty("couchdb_dbname") + "/" + uri);
}
}