/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.camel.component.couchbase; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import com.couchbase.client.CouchbaseClient; import com.couchbase.client.CouchbaseConnectionFactoryBuilder; import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; import org.apache.camel.impl.ScheduledPollEndpoint; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; import org.apache.camel.spi.UriPath; import static org.apache.camel.component.couchbase.CouchbaseConstants.COUCHBASE_PUT; import static org.apache.camel.component.couchbase.CouchbaseConstants.COUCHBASE_URI_ERROR; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_CONSUME_PROCESSED_STRATEGY; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_COUCHBASE_PORT; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_DESIGN_DOCUMENT_NAME; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_MAX_RECONNECT_DELAY; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_OBS_POLL_INTERVAL; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_OBS_TIMEOUT; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_OP_QUEUE_MAX_BLOCK_TIME; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_OP_TIMEOUT; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_PAUSE_BETWEEN_RETRIES; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_PRODUCER_RETRIES; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_READ_BUFFER_SIZE; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_TIMEOUT_EXCEPTION_THRESHOLD; import static org.apache.camel.component.couchbase.CouchbaseConstants.DEFAULT_VIEWNAME; /** * Represents a Couchbase endpoint that can query Views with a Poll strategy * and/or produce various type of operations. */ @UriEndpoint(firstVersion = "2.19.0", scheme = "couchbase", title = "Couchbase", syntax = "couchbase:url", consumerClass = CouchbaseConsumer.class, label = "database,nosql") public class CouchbaseEndpoint extends ScheduledPollEndpoint { @UriPath @Metadata(required = "true") private String protocol; @UriPath @Metadata(required = "true") private String hostname; @UriParam(defaultValue = "8091") private int port; @UriParam private String bucket; // Couchbase key @UriParam private String key; // Authentication @UriParam(label = "security", secret = true) private String username; @UriParam(label = "security", secret = true) private String password; // Additional hosts @UriParam(label = "advanced") private String additionalHosts; // Persistence and replication parameters @UriParam(label = "producer", defaultValue = "0") private int persistTo; @UriParam(label = "producer", defaultValue = "0") private int replicateTo; // Producer parameters @UriParam(label = "producer", defaultValue = COUCHBASE_PUT) private String operation = COUCHBASE_PUT; @UriParam(label = "producer", defaultValue = "false") private boolean autoStartIdForInserts; @UriParam(label = "producer", defaultValue = "2") private int producerRetryAttempts = DEFAULT_PRODUCER_RETRIES; @UriParam(label = "producer", defaultValue = "5000") private int producerRetryPause = DEFAULT_PAUSE_BETWEEN_RETRIES; @UriParam(label = "producer") private long startingIdForInsertsFrom; // View control @UriParam(label = "consumer", defaultValue = DEFAULT_DESIGN_DOCUMENT_NAME) private String designDocumentName = DEFAULT_DESIGN_DOCUMENT_NAME; @UriParam(label = "consumer", defaultValue = DEFAULT_VIEWNAME) private String viewName = DEFAULT_VIEWNAME; @UriParam(label = "consumer", defaultValue = "-1") private int limit = -1; @UriParam(label = "consumer", defaultValue = "false") private boolean descending; @UriParam(label = "consumer", defaultValue = "-1") private int skip = -1; @UriParam(label = "consumer") private String rangeStartKey; @UriParam(label = "consumer") private String rangeEndKey = ""; // Consumer strategy @UriParam(label = "consumer", defaultValue = DEFAULT_CONSUME_PROCESSED_STRATEGY) private String consumerProcessedStrategy = DEFAULT_CONSUME_PROCESSED_STRATEGY; // Connection fine tuning parameters @UriParam(label = "advanced", defaultValue = "2500") private long opTimeOut = DEFAULT_OP_TIMEOUT; @UriParam(label = "advanced", defaultValue = "998") private int timeoutExceptionThreshold = DEFAULT_TIMEOUT_EXCEPTION_THRESHOLD; @UriParam(label = "advanced", defaultValue = "16384") private int readBufferSize = DEFAULT_READ_BUFFER_SIZE; @UriParam(label = "advanced", defaultValue = "false") private boolean shouldOptimize; @UriParam(label = "advanced", defaultValue = "30000") private long maxReconnectDelay = DEFAULT_MAX_RECONNECT_DELAY; @UriParam(label = "advanced", defaultValue = "10000") private long opQueueMaxBlockTime = DEFAULT_OP_QUEUE_MAX_BLOCK_TIME; @UriParam(label = "advanced", defaultValue = "400") private long obsPollInterval = DEFAULT_OBS_POLL_INTERVAL; @UriParam(label = "advanced", defaultValue = "-1") private long obsTimeout = DEFAULT_OBS_TIMEOUT; public CouchbaseEndpoint() { } public CouchbaseEndpoint(String uri, String remaining, CouchbaseComponent component) throws URISyntaxException { super(uri, component); URI remainingUri = new URI(remaining); protocol = remainingUri.getScheme(); if (protocol == null) { throw new IllegalArgumentException(COUCHBASE_URI_ERROR); } port = remainingUri.getPort() == -1 ? DEFAULT_COUCHBASE_PORT : remainingUri.getPort(); if (remainingUri.getPath() == null || remainingUri.getPath().trim().length() == 0) { throw new IllegalArgumentException(COUCHBASE_URI_ERROR); } bucket = remainingUri.getPath().substring(1); hostname = remainingUri.getHost(); if (hostname == null) { throw new IllegalArgumentException(COUCHBASE_URI_ERROR); } } public CouchbaseEndpoint(String endpointUri, CouchbaseComponent component) { super(endpointUri, component); } @Override public Producer createProducer() throws Exception { return new CouchbaseProducer(this, createClient(), persistTo, replicateTo); } @Override public Consumer createConsumer(Processor processor) throws Exception { return new CouchbaseConsumer(this, createClient(), processor); } @Override public boolean isSingleton() { return true; } public String getProtocol() { return protocol; } /** * The protocol to use */ public void setProtocol(String protocol) { this.protocol = protocol; } public String getBucket() { return bucket; } /** * The bucket to use */ public void setBucket(String bucket) { this.bucket = bucket; } public String getHostname() { return hostname; } /** * The hostname to use */ public void setHostname(String hostname) { this.hostname = hostname; } public int getPort() { return port; } /** * The port number to use */ public void setPort(int port) { this.port = port; } public String getKey() { return key; } /** * The key to use */ public void setKey(String key) { this.key = key; } public String getUsername() { return username; } /** * The username to use */ public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } /** * The password to use */ public void setPassword(String password) { this.password = password; } public String getAdditionalHosts() { return additionalHosts; } /** * The additional hosts */ public void setAdditionalHosts(String additionalHosts) { this.additionalHosts = additionalHosts; } public int getPersistTo() { return persistTo; } /** * Where to persist the data */ public void setPersistTo(int persistTo) { this.persistTo = persistTo; } public int getReplicateTo() { return replicateTo; } /** * Where to replicate the data */ public void setReplicateTo(int replicateTo) { this.replicateTo = replicateTo; } public String getOperation() { return operation; } /** * The operation to do */ public void setOperation(String operation) { this.operation = operation; } public boolean isAutoStartIdForInserts() { return autoStartIdForInserts; } /** * Define if we want an autostart Id when we are doing an insert operation */ public void setAutoStartIdForInserts(boolean autoStartIdForInserts) { this.autoStartIdForInserts = autoStartIdForInserts; } public long getStartingIdForInsertsFrom() { return startingIdForInsertsFrom; } /** * Define the starting Id where we are doing an insert operation */ public void setStartingIdForInsertsFrom(long startingIdForInsertsFrom) { this.startingIdForInsertsFrom = startingIdForInsertsFrom; } public int getProducerRetryAttempts() { return producerRetryAttempts; } /** * Define the number of retry attempts */ public void setProducerRetryAttempts(int producerRetryAttempts) { this.producerRetryAttempts = producerRetryAttempts; } public int getProducerRetryPause() { return producerRetryPause; } /** * Define the retry pause between different attempts */ public void setProducerRetryPause(int producerRetryPause) { this.producerRetryPause = producerRetryPause; } public String getDesignDocumentName() { return designDocumentName; } /** * The design document name to use */ public void setDesignDocumentName(String designDocumentName) { this.designDocumentName = designDocumentName; } public String getViewName() { return viewName; } /** * The view name to use */ public void setViewName(String viewName) { this.viewName = viewName; } public int getLimit() { return limit; } /** * The output limit to use */ public void setLimit(int limit) { this.limit = limit; } public boolean isDescending() { return descending; } /** * Define if this operation is descending or not */ public void setDescending(boolean descending) { this.descending = descending; } public int getSkip() { return skip; } /** * Define the skip to use */ public void setSkip(int skip) { this.skip = skip; } public String getRangeStartKey() { return rangeStartKey; } /** * Define a range for the start key */ public void setRangeStartKey(String rangeStartKey) { this.rangeStartKey = rangeStartKey; } public String getRangeEndKey() { return rangeEndKey; } /** * Define a range for the end key */ public void setRangeEndKey(String rangeEndKey) { this.rangeEndKey = rangeEndKey; } public String getConsumerProcessedStrategy() { return consumerProcessedStrategy; } /** * Define the consumer Processed strategy to use */ public void setConsumerProcessedStrategy(String consumerProcessedStrategy) { this.consumerProcessedStrategy = consumerProcessedStrategy; } public long getOpTimeOut() { return opTimeOut; } /** * Define the operation timeout */ public void setOpTimeOut(long opTimeOut) { this.opTimeOut = opTimeOut; } public int getTimeoutExceptionThreshold() { return timeoutExceptionThreshold; } /** * Define the threshold for throwing a timeout Exception */ public void setTimeoutExceptionThreshold(int timeoutExceptionThreshold) { this.timeoutExceptionThreshold = timeoutExceptionThreshold; } public int getReadBufferSize() { return readBufferSize; } /** * Define the buffer size */ public void setReadBufferSize(int readBufferSize) { this.readBufferSize = readBufferSize; } public boolean isShouldOptimize() { return shouldOptimize; } /** * Define if we want to use optimization or not where possible */ public void setShouldOptimize(boolean shouldOptimize) { this.shouldOptimize = shouldOptimize; } public long getMaxReconnectDelay() { return maxReconnectDelay; } /** * Define the max delay during a reconnection */ public void setMaxReconnectDelay(long maxReconnectDelay) { this.maxReconnectDelay = maxReconnectDelay; } public long getOpQueueMaxBlockTime() { return opQueueMaxBlockTime; } /** * Define the max time an operation can be in queue blocked */ public void setOpQueueMaxBlockTime(long opQueueMaxBlockTime) { this.opQueueMaxBlockTime = opQueueMaxBlockTime; } public long getObsPollInterval() { return obsPollInterval; } /** * Define the observation polling interval */ public void setObsPollInterval(long obsPollInterval) { this.obsPollInterval = obsPollInterval; } public long getObsTimeout() { return obsTimeout; } /** * Define the observation timeout */ public void setObsTimeout(long obsTimeout) { this.obsTimeout = obsTimeout; } public URI[] makeBootstrapURI() throws URISyntaxException { if (additionalHosts == null || "".equals(additionalHosts)) { return new URI[] {new URI(protocol + "://" + hostname + ":" + port + "/pools")}; } return getAllUris(); } private URI[] getAllUris() throws URISyntaxException { String[] hosts = additionalHosts.split(","); for (int i = 0; i < hosts.length; i++) { hosts[i] = hosts[i].trim(); } List<String> hostList = new ArrayList<String>(); hostList.add(hostname); hostList.addAll(Arrays.asList(hosts)); Set<String> hostSet = new LinkedHashSet<String>(hostList); hosts = hostSet.toArray(new String[hostSet.size()]); URI[] uriArray = new URI[hosts.length]; for (int i = 0; i < hosts.length; i++) { uriArray[i] = new URI(protocol + "://" + hosts[i] + ":" + port + "/pools"); } return uriArray; } private CouchbaseClient createClient() throws IOException, URISyntaxException { List<URI> hosts = Arrays.asList(makeBootstrapURI()); CouchbaseConnectionFactoryBuilder cfb = new CouchbaseConnectionFactoryBuilder(); if (opTimeOut != DEFAULT_OP_TIMEOUT) { cfb.setOpTimeout(opTimeOut); } if (timeoutExceptionThreshold != DEFAULT_TIMEOUT_EXCEPTION_THRESHOLD) { cfb.setTimeoutExceptionThreshold(timeoutExceptionThreshold); } if (readBufferSize != DEFAULT_READ_BUFFER_SIZE) { cfb.setReadBufferSize(readBufferSize); } if (shouldOptimize) { cfb.setShouldOptimize(true); } if (maxReconnectDelay != DEFAULT_MAX_RECONNECT_DELAY) { cfb.setMaxReconnectDelay(maxReconnectDelay); } if (opQueueMaxBlockTime != DEFAULT_OP_QUEUE_MAX_BLOCK_TIME) { cfb.setOpQueueMaxBlockTime(opQueueMaxBlockTime); } if (obsPollInterval != DEFAULT_OBS_POLL_INTERVAL) { cfb.setObsPollInterval(obsPollInterval); } if (obsTimeout != DEFAULT_OBS_TIMEOUT) { cfb.setObsTimeout(obsTimeout); } return new CouchbaseClient(cfb.buildCouchbaseConnection(hosts, bucket, username, password)); } }