/* * Copyright (C) 2011 lightcouch.org * * 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. */ package org.lightcouch; import static org.lightcouch.CouchDbUtil.*; import static org.lightcouch.URIBuilder.buildUri; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.codec.Charsets; import org.lightcouch.ReplicatorDocument.UserCtx; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; /** * This class provides access to the <tt>_replicator</tt> database introduced in CouchDB version 1.1.0 * <p>A replication is triggered by persisting a document, and cancelled by removing the document that triggered the replication. * * <h3>Usage Example:</h3> * <pre> * Response response = dbClient.replicator() * .source("source-db") * .target("target-db") * .continuous(true) * .createTarget(true) * .replicatorDB("replicator-db-name") // optional, defaults to _replicator * .replicatorDocId("doc-id") // optional, defaults to UUID * .save(); // trigger replication * * ReplicatorDocument replicatorDoc = dbClient.replicator() * .replicatorDocId("doc-id") * .replicatorDocRev("doc-rev") // optional * .find(); * * {@code * List<ReplicatorDocument> replicatorDocs = dbClient.replicator().findAll(); * } * * Response response = dbClient.replicator() * .replicatorDocId("doc-id") * .replicatorDocRev("doc-rev") * .remove(); // cancels a replication * </pre> * * @see CouchDbClientBase#replicator() * @see Replication * @see ReplicatorDocument * @since 0.0.2 * @author Ahmed Yehia * */ public class Replicator { private String replicatorDB; private String userCtxName; private String[] userCtxRoles; private CouchDbClientBase dbc; private ReplicatorDocument replicatorDoc; private URI dbURI; public Replicator(CouchDbClientBase dbc) { this.dbc = dbc; replicatorDoc = new ReplicatorDocument(); replicatorDB = "_replicator"; // default replicator db userCtxRoles = new String[0]; // default roles dbURI = buildUri(dbc.getBaseUri()).path(replicatorDB).path("/").build(); } /** * Adds a new document to the replicator database. * @return {@link Response} */ public Response save() { assertNotEmpty(replicatorDoc.getSource(), "Source"); assertNotEmpty(replicatorDoc.getTarget(), "Target"); if(userCtxName != null) { UserCtx ctx = replicatorDoc.new UserCtx(); ctx.setName(userCtxName); ctx.setRoles(userCtxRoles); replicatorDoc.setUserCtx(ctx); } return dbc.put(dbURI, replicatorDoc, true); } /** * Finds a document in the replicator database. * @return {@link ReplicatorDocument} */ public ReplicatorDocument find() { assertNotEmpty(replicatorDoc.getId(), "Doc id"); final URI uri = buildUri(dbURI).path(replicatorDoc.getId()).query("rev", replicatorDoc.getRevision()).build(); return dbc.get(uri, ReplicatorDocument.class); } /** * Finds all documents in the replicator database. */ public List<ReplicatorDocument> findAll() { InputStream instream = null; try { final URI uri = buildUri(dbURI).path("_all_docs").query("include_docs", "true").build(); final Reader reader = new InputStreamReader(instream = dbc.get(uri), Charsets.UTF_8); final JsonArray jsonArray = new JsonParser().parse(reader) .getAsJsonObject().getAsJsonArray("rows"); final List<ReplicatorDocument> list = new ArrayList<ReplicatorDocument>(); for (JsonElement jsonElem : jsonArray) { JsonElement elem = jsonElem.getAsJsonObject().get("doc"); if(!getAsString(elem.getAsJsonObject(), "_id").startsWith("_design")) { // skip design docs ReplicatorDocument rd = dbc.getGson().fromJson(elem, ReplicatorDocument.class); list.add(rd); } } return list; } finally { close(instream); } } /** * Removes a document from the replicator database. * @return {@link Response} */ public Response remove() { assertNotEmpty(replicatorDoc.getId(), "Doc id"); assertNotEmpty(replicatorDoc.getRevision(), "Doc rev"); final URI uri = buildUri(dbURI).path(replicatorDoc.getId()).query("rev", replicatorDoc.getRevision()).build(); return dbc.delete(uri); } // fields public Replicator source(String source) { replicatorDoc.setSource(source); return this; } public Replicator target(String target) { replicatorDoc.setTarget(target); return this; } public Replicator continuous(boolean continuous) { replicatorDoc.setContinuous(continuous); return this; } public Replicator filter(String filter) { replicatorDoc.setFilter(filter); return this; } public Replicator queryParams(String queryParams) { replicatorDoc.setQueryParams(dbc.getGson().fromJson(queryParams, JsonObject.class)); return this; } public Replicator queryParams(Map<String, Object> queryParams) { replicatorDoc.setQueryParams(dbc.getGson().toJsonTree(queryParams).getAsJsonObject()); return this; } public Replicator docIds(String... docIds) { replicatorDoc.setDocIds(docIds); return this; } public Replicator proxy(String proxy) { replicatorDoc.setProxy(proxy); return this; } public Replicator createTarget(Boolean createTarget) { replicatorDoc.setCreateTarget(createTarget); return this; } public Replicator replicatorDB(String replicatorDB) { this.replicatorDB = replicatorDB; dbURI = buildUri(dbc.getBaseUri()).path(replicatorDB).path("/").build(); return this; } public Replicator replicatorDocId(String replicatorDocId) { replicatorDoc.setId(replicatorDocId); return this; } public Replicator replicatorDocRev(String replicatorDocRev) { replicatorDoc.setRevision(replicatorDocRev); return this; } public Replicator workerProcesses(int workerProcesses) { replicatorDoc.setWorkerProcesses(workerProcesses); return this; } public Replicator workerBatchSize(int workerBatchSize) { replicatorDoc.setWorkerBatchSize(workerBatchSize); return this; } public Replicator httpConnections(int httpConnections) { replicatorDoc.setHttpConnections(httpConnections); return this; } public Replicator connectionTimeout(long connectionTimeout) { replicatorDoc.setConnectionTimeout(connectionTimeout); return this; } public Replicator retriesPerRequest(int retriesPerRequest) { replicatorDoc.setRetriesPerRequest(retriesPerRequest); return this; } public Replicator userCtxName(String userCtxName) { this.userCtxName = userCtxName; return this; } public Replicator userCtxRoles(String... userCtxRoles) { this.userCtxRoles = userCtxRoles; return this; } public Replicator sinceSeq(Integer sinceSeq) { replicatorDoc.setSinceSeq(sinceSeq); return this; } }