This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.nosql.couchbase-client-1.0.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-couchbase-client.git
commit a587659c476c21147dc79a82c34055c9030f4773 Author: Stefan Seifert <sseif...@apache.org> AuthorDate: Wed May 20 13:48:32 2015 +0000 SLING-4381 couchbase client git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/couchbase-client@1680570 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 131 +++++++++++++++++++ .../nosql/couchbase/client/CouchbaseClient.java | 63 +++++++++ .../sling/nosql/couchbase/client/CouchbaseKey.java | 79 ++++++++++++ .../couchbase/client/impl/CouchbaseClientImpl.java | 141 +++++++++++++++++++++ .../nosql/couchbase/client/impl/CouchbaseUtil.java | 63 +++++++++ .../sling/nosql/couchbase/client/package-info.java | 24 ++++ .../nosql/couchbase/client/CouchbaseKeyTest.java | 44 +++++++ 7 files changed, 545 insertions(+) diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d0a4ba9 --- /dev/null +++ b/pom.xml @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.sling</groupId> + <artifactId>sling</artifactId> + <version>22</version> + <relativePath/> + </parent> + + <artifactId>org.apache.sling.nosql.couchbase-client</artifactId> + <version>0.5.0-SNAPSHOT</version> + <packaging>bundle</packaging> + + <name>Apache Sling NoSQL Couchbase Client</name> + <description>Couchbase client provider using Couchbase SDK 2.</description> + + <scm> + <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/couchbase-client</connection> + <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/couchbase-client</developerConnection> + <url>http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/couchbase-client</url> + </scm> + + <properties> + <sling.java.version>7</sling.java.version> + <couchbase.client.version>2.1.3</couchbase.client.version> + </properties> + + <dependencies> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>com.couchbase.client</groupId> + <artifactId>java-client</artifactId> + <version>${couchbase.client.version}</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.commons.osgi</artifactId> + <version>2.2.2</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.3.2</version> + <scope>test</scope> + </dependency> + + </dependencies> + + <build> + <plugins> + + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <!-- Do not inline jars, include as jar files --> + <Embed-Dependency>*;scope=compile|runtime;inline=false;groupId=com.couchbase.*</Embed-Dependency> + <Embed-Transitive>true</Embed-Transitive> + <!-- use _exportcontents instead of Export-Package to avoid conflict with Embed-Dependency an inline=true --> + <_exportcontents> + com.couchbase.client.java.*;version=${couchbase.client.version}, + org.apache.sling.nosql.couchbase.client;version=${project.version} + </_exportcontents> + <Import-Package> + com.barchart.udt.*;resolution:=optional, + com.google.protobuf.*;resolution:=optional, + com.jcraft.jzlib.*;resolution:=optional, + com.sun.*;resolution:=optional, + gnu.io.*;resolution:=optional, + javassist.*;resolution:=optional, + org.apache.tomcat.*;resolution:=optional, + org.bouncycastle.*;resolution:=optional, + org.eclipse.jetty.*;resolution:=optional, + org.jboss.*;resolution:=optional, + rx.internal.*;resolution:=optional, + sun.misc.*;resolution:=optional, + sun.security.*;resolution:=optional, + * + </Import-Package> + </instructions> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + </plugin> + + </plugins> + </build> + +</project> diff --git a/src/main/java/org/apache/sling/nosql/couchbase/client/CouchbaseClient.java b/src/main/java/org/apache/sling/nosql/couchbase/client/CouchbaseClient.java new file mode 100644 index 0000000..f6751a2 --- /dev/null +++ b/src/main/java/org/apache/sling/nosql/couchbase/client/CouchbaseClient.java @@ -0,0 +1,63 @@ +/* + * 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.sling.nosql.couchbase.client; + +import aQute.bnd.annotation.ProviderType; + +import com.couchbase.client.java.AsyncBucket; +import com.couchbase.client.java.Bucket; + +/** + * Provides access to a preconfigured couchbase client. + * Multiple clients can be registered for different buckets; they can be filtered by the 'clientId' OSGi property. + */ +@ProviderType +public interface CouchbaseClient { + + /** + * OSGi property for filtering the configured couchbase clients. + */ + String CLIENT_ID_PROPERTY = "clientId"; + + /** + * @return ID to uniquely identify the couchbase client if multiple are defined. + */ + String getClientId(); + + /** + * @return true if Couchbase caching is enabled and configured properly. + */ + boolean isEnabled(); + + /** + * @return the name of the couchbase bucket to use for caching + */ + String getBucketName(); + + /** + * @return Default bucket as configured for the couchbase client provider. + */ + Bucket getBucket(); + + /** + * @return Default asynchronous bucket as configured for the couchbase client provider. + */ + AsyncBucket getAsyncBucket(); + +} diff --git a/src/main/java/org/apache/sling/nosql/couchbase/client/CouchbaseKey.java b/src/main/java/org/apache/sling/nosql/couchbase/client/CouchbaseKey.java new file mode 100644 index 0000000..e495ffc --- /dev/null +++ b/src/main/java/org/apache/sling/nosql/couchbase/client/CouchbaseKey.java @@ -0,0 +1,79 @@ +/* + * 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.sling.nosql.couchbase.client; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import aQute.bnd.annotation.ProviderType; + +/** + * Builds couchbase keys. Cuts them off and replaces the remaining part with a hash if too long. + */ +@ProviderType +public final class CouchbaseKey { + + static final int MAX_KEY_LENGTH = 250; + + private CouchbaseKey() { + // static methods only + } + + /** + * Builds a key for a couchbase document with the given prefix that does not + * exceed the max. length for couchbase keys. + * @param key Full key + * @param cacheKeyPrefix Prefix to add before the key + * @return Valid key for couchbase + */ + public static String build(String key, String keyPrefix) { + String cacheKey = keyPrefix + key; + + if (cacheKey.length() < MAX_KEY_LENGTH) { + return cacheKey; + } + + int charactersToKeep = MAX_KEY_LENGTH - keyPrefix.length() - 41; + + String toKeep = key.substring(0, charactersToKeep); + String toHash = key.substring(charactersToKeep); + + String hash = calculateHash(toHash); + + return keyPrefix + toKeep + "#" + hash; + } + + private static String calculateHash(String message) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + digest.update(message.getBytes("UTF-8")); + byte[] digestBytes = digest.digest(); + + return javax.xml.bind.DatatypeConverter.printHexBinary(digestBytes).toLowerCase(); + } + catch (NoSuchAlgorithmException ex) { + throw new RuntimeException("Failed to create sha1 Hash from " + message, ex); + } + catch (UnsupportedEncodingException ex) { + throw new RuntimeException("Failed to create sha1 Hash from " + message, ex); + } + } + +} diff --git a/src/main/java/org/apache/sling/nosql/couchbase/client/impl/CouchbaseClientImpl.java b/src/main/java/org/apache/sling/nosql/couchbase/client/impl/CouchbaseClientImpl.java new file mode 100644 index 0000000..a12a61f --- /dev/null +++ b/src/main/java/org/apache/sling/nosql/couchbase/client/impl/CouchbaseClientImpl.java @@ -0,0 +1,141 @@ +/* + * 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.sling.nosql.couchbase.client.impl; + +import java.util.Map; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.ConfigurationPolicy; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Service; +import org.apache.sling.commons.osgi.PropertiesUtil; +import org.apache.sling.nosql.couchbase.client.CouchbaseClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.couchbase.client.java.AsyncBucket; +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; + +/** + * Default implementation of {@link CouchbaseClient}. + */ +@Component(immediate = true, metatype = true, + name="org.apache.sling.nosql.couchbase.client.CouchbaseClient.factory.config", + label = "Apache Sling NoSQL Couchbase Client", + description = "Provides access to a preconfigured couchbase client.", + configurationFactory = true, policy = ConfigurationPolicy.REQUIRE) +@Service(CouchbaseClient.class) +@Property(name = "webconsole.configurationFactory.nameHint", + value = "{" + CouchbaseClientImpl.CLIENT_ID_PROPERTY + "}: {" + CouchbaseClientImpl.CACHE_BUCKET_NAME_PROPERTY + "}") +public class CouchbaseClientImpl implements CouchbaseClient { + + @Property(label = "Client ID", description = "ID to uniquely identify the couchbase client if multiple are defined.") + static final String CLIENT_ID_PROPERTY = CouchbaseClient.CLIENT_ID_PROPERTY; + + @Property(label = "Enabled", description = "Enable or disable couchbase caching.", boolValue = CouchbaseClientImpl.ENABLED_PROPERTY_DEFAULT) + static final String ENABLED_PROPERTY = "enabled"; + private static final boolean ENABLED_PROPERTY_DEFAULT = true; + + @Property(label = "Couchbase Hosts", description = "Couchbase cluster host list.", cardinality = Integer.MAX_VALUE) + static final String COUCHBASE_HOSTS_PROPERTY = "couchbaseHosts"; + + @Property(label = "Bucket Name", description = "Couchbase bucket name") + static final String CACHE_BUCKET_NAME_PROPERTY = "bucketName"; + + @Property(label = "Bucket Password", description = "Couchbase bucket password") + static final String CACHE_BUCKET_PASSWORD_PROPERTY = "bucketPassword"; + + private static final Logger log = LoggerFactory.getLogger(CouchbaseClientImpl.class); + + private String clientId; + private boolean enabled; + private String bucketName; + private Cluster cluster; + private Bucket bucket; + + @Activate + private void activate(Map<String, Object> config) { + clientId = PropertiesUtil.toString(config.get(CLIENT_ID_PROPERTY), null); + enabled = PropertiesUtil.toBoolean(config.get(ENABLED_PROPERTY), ENABLED_PROPERTY_DEFAULT); + if (!enabled) { + log.info("Couchbase caching for client '{}' is disabled by configuration.", clientId); + return; + } + + String[] couchbaseHosts = PropertiesUtil.toStringArray(config.get(COUCHBASE_HOSTS_PROPERTY)); + if (couchbaseHosts == null || couchbaseHosts.length == 0) { + enabled = false; + log.warn("No couchbase host configured, client '{}' is disabled.", clientId); + return; + } + + bucketName = PropertiesUtil.toString(config.get(CACHE_BUCKET_NAME_PROPERTY), null); + String bucketPassword = PropertiesUtil.toString(config.get(CACHE_BUCKET_PASSWORD_PROPERTY), null); + if (bucketName == null) { + enabled = false; + log.warn("No couchbase bucket name configured, client '{}' is disabled.", clientId); + return; + } + + try { + cluster = CouchbaseUtil.createCluster(couchbaseHosts); + bucket = CouchbaseUtil.openBucket(cluster, bucketName, bucketPassword); + } + catch (Throwable ex) { + enabled = false; + log.error("Unable to connect to couchbase cluster or open couchbase bucket, client '" + clientId + "' is disabled.", ex); + } + } + + @Deactivate + private void deactivate() { + if (bucket != null) { + bucket.close(); + bucket = null; + } + if (cluster != null) { + cluster.disconnect(); + cluster = null; + } + } + + public String getClientId() { + return clientId; + } + + public boolean isEnabled() { + return enabled; + } + + public String getBucketName() { + return bucketName; + } + + public Bucket getBucket() { + return bucket; + } + + public AsyncBucket getAsyncBucket() { + return bucket.async(); + } + +} diff --git a/src/main/java/org/apache/sling/nosql/couchbase/client/impl/CouchbaseUtil.java b/src/main/java/org/apache/sling/nosql/couchbase/client/impl/CouchbaseUtil.java new file mode 100644 index 0000000..523870c --- /dev/null +++ b/src/main/java/org/apache/sling/nosql/couchbase/client/impl/CouchbaseUtil.java @@ -0,0 +1,63 @@ +/* + * 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.sling.nosql.couchbase.client.impl; + +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.CouchbaseCluster; +import com.couchbase.client.java.env.CouchbaseEnvironment; +import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; + +/** + * Manages couchbase environment. + */ +final class CouchbaseUtil { + + private static final CouchbaseEnvironment COUCHBASE_ENVIRONMENT = DefaultCouchbaseEnvironment.builder().build(); + + private CouchbaseUtil() { + // static methods only + } + + /** + * Create new couchbase cluster. + * @param hostNames Multiple hosts + * @return Couchbase cluster + */ + public static Cluster createCluster(String... hostNames) { + return CouchbaseCluster.create(COUCHBASE_ENVIRONMENT, hostNames); + } + + /** + * Open couchbase bucket. + * @param cluster Couchbase cluster + * @param bucketName Bucker name + * @param bucketPassword Bucker password (optional) + * @return Couchbase bucket + */ + public static Bucket openBucket(Cluster cluster, String bucketName, String bucketPassword) { + if (bucketPassword == null) { + return cluster.openBucket(bucketName, bucketPassword); + } + else { + return cluster.openBucket(bucketName); + } + } + +} diff --git a/src/main/java/org/apache/sling/nosql/couchbase/client/package-info.java b/src/main/java/org/apache/sling/nosql/couchbase/client/package-info.java new file mode 100644 index 0000000..537c719 --- /dev/null +++ b/src/main/java/org/apache/sling/nosql/couchbase/client/package-info.java @@ -0,0 +1,24 @@ +/* + * 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. + */ +/** + * Couchbase Client Provider + */ +@aQute.bnd.annotation.Version("0.5.0") +package org.apache.sling.nosql.couchbase.client; + diff --git a/src/test/java/org/apache/sling/nosql/couchbase/client/CouchbaseKeyTest.java b/src/test/java/org/apache/sling/nosql/couchbase/client/CouchbaseKeyTest.java new file mode 100644 index 0000000..cd1a68b --- /dev/null +++ b/src/test/java/org/apache/sling/nosql/couchbase/client/CouchbaseKeyTest.java @@ -0,0 +1,44 @@ +/* + * 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.sling.nosql.couchbase.client; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; + +public class CouchbaseKeyTest { + + private static final String PREFIX = "prefix:"; + + @Test + public void testShortKey() { + String key = CouchbaseKey.build("/short/key", PREFIX); + assertEquals(PREFIX + "/short/key", key); + } + + @Test + public void testLongKey() { + String key = CouchbaseKey.build("/long/key/" + StringUtils.repeat("/aaa", 500), PREFIX); + assertTrue(StringUtils.startsWith(key, PREFIX + "/long/key/")); + assertEquals(CouchbaseKey.MAX_KEY_LENGTH, key.length()); + } + +} -- To stop receiving notification emails like this one, please contact "commits@sling.apache.org" <commits@sling.apache.org>.