implement basic configurations + monitoring
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors
|
||||
*
|
||||
* 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.springframework.data.couchbase.config;
|
||||
|
||||
/**
|
||||
* Contains default bean names that will be used when no "id" is supplied to the beans.
|
||||
*
|
||||
* @author Michael Nitschinger
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
public class BeanNames {
|
||||
|
||||
/**
|
||||
* Refers to the "<couchbase:cluster />" bean.
|
||||
*/
|
||||
static final String COUCHBASE_CLUSTER = "cluster";
|
||||
|
||||
/**
|
||||
* Refers to the "<couchbase:bucket />" bean.
|
||||
*/
|
||||
static final String COUCHBASE_BUCKET = "bucket";
|
||||
|
||||
/**
|
||||
* Refers to the "<couchbase:template />" bean.
|
||||
*/
|
||||
static final String COUCHBASE_TEMPLATE = "couchbaseTemplate";
|
||||
|
||||
/**
|
||||
* Refers to the "<couchbase:translation-service />" bean
|
||||
*/
|
||||
static final String TRANSLATION_SERVICE = "translationService";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors
|
||||
*
|
||||
* 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.springframework.data.couchbase.config;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.couchbase.monitor.ClientInfo;
|
||||
import org.springframework.data.couchbase.monitor.ClusterInfo;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Enables Parsing of the "<couchbase:jmx />" configuration bean.
|
||||
* <p/>
|
||||
* In order to enable JMX, different JmxComponents need to be registered. The dependency to the original
|
||||
* {@link Bucket} object is solved through the "bucket-ref" attribute.
|
||||
*
|
||||
* @author Michael Nitschinger
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
public class CouchbaseJmxParser implements BeanDefinitionParser {
|
||||
|
||||
/**
|
||||
* Parse the element and dispatch the registration of the JMX components.
|
||||
*
|
||||
* @param element the XML element which contains the attributes.
|
||||
* @param parserContext encapsulates the parsing state and configuration.
|
||||
* @return null, because no bean instance needs to be returned.
|
||||
*/
|
||||
public BeanDefinition parse(final Element element, final ParserContext parserContext) {
|
||||
String bucketName = element.getAttribute("bucket-ref");
|
||||
if (!StringUtils.hasText(bucketName)) {
|
||||
bucketName = BeanNames.COUCHBASE_BUCKET;
|
||||
}
|
||||
registerJmxComponents(bucketName, element, parserContext);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the JMX components in the context.
|
||||
*
|
||||
* @param element the XML element which contains the attributes.
|
||||
* @param parserContext encapsulates the parsing state and configuration.
|
||||
* @parma refBucketName the reference name to the couchbase bucket.
|
||||
*/
|
||||
protected void registerJmxComponents(final String refBucketName,
|
||||
final Element element, final ParserContext parserContext) {
|
||||
Object eleSource = parserContext.extractSource(element);
|
||||
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
|
||||
|
||||
createBeanDefEntry(ClientInfo.class, compositeDef, refBucketName, eleSource, parserContext);
|
||||
createBeanDefEntry(ClusterInfo.class, compositeDef, refBucketName, eleSource, parserContext);
|
||||
|
||||
parserContext.registerComponent(compositeDef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates Bean Definitions for JMX components and adds them as a nested component.
|
||||
*
|
||||
* @param clazz the class type to register.
|
||||
* @param compositeDef component that can hold nested components.
|
||||
* @param refName the reference name to the couchbase client.
|
||||
* @param eleSource source element to reference.
|
||||
* @param parserContext encapsulates the parsing state and configuration.
|
||||
*/
|
||||
protected void createBeanDefEntry(final Class<?> clazz, final CompositeComponentDefinition compositeDef,
|
||||
final String refName, final Object eleSource, final ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
|
||||
builder.getRawBeanDefinition().setSource(eleSource);
|
||||
builder.addConstructorArgReference(refName);
|
||||
BeanDefinition assertDef = builder.getBeanDefinition();
|
||||
String assertName = parserContext.getReaderContext().registerWithGeneratedName(assertDef);
|
||||
compositeDef.addNestedComponent(new BeanComponentDefinition(assertDef, assertName));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors
|
||||
*
|
||||
* 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.springframework.data.couchbase.config;
|
||||
|
||||
import org.springframework.beans.factory.xml.NamespaceHandler;
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
|
||||
/**
|
||||
* {@link NamespaceHandler} for Couchbase configuration.
|
||||
* <p/>
|
||||
* This handler acts as a container for one or more bean parsers and registers them. During parsing, the elements
|
||||
* get analyzed and the appropriate registered parser is called.
|
||||
*
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
public class CouchbaseNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
/**
|
||||
* Register bean definition parsers in the namespace handler.
|
||||
*/
|
||||
public final void init() {
|
||||
//TODO repositories (CouchbaseRepositoryConfigurationExtension and RepositoryBeanDefinitionParser)
|
||||
//TODO bucket
|
||||
//TODO cluster
|
||||
registerBeanDefinitionParser("jmx", new CouchbaseJmxParser());
|
||||
registerBeanDefinitionParser("template", new CouchbaseTemplateParser());
|
||||
//TODO translation service
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors
|
||||
*
|
||||
* 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.springframework.data.couchbase.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parser for "<couchbase:template />" bean definitions.
|
||||
* <p/>
|
||||
* The outcome of this bean definition parser will be a constructed {@link CouchbaseTemplate}.
|
||||
*
|
||||
* @author Michael Nitschinger
|
||||
*/
|
||||
public class CouchbaseTemplateParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
/**
|
||||
* Resolve the bean ID and assign a default if not set.
|
||||
*
|
||||
* @param element the XML element which contains the attributes.
|
||||
* @param definition the bean definition to work with.
|
||||
* @param parserContext encapsulates the parsing state and configuration.
|
||||
* @return the ID to work with.
|
||||
*/
|
||||
@Override
|
||||
protected String resolveId(final Element element, final AbstractBeanDefinition definition, final ParserContext parserContext) {
|
||||
String id = super.resolveId(element, definition, parserContext);
|
||||
return StringUtils.hasText(id) ? id : BeanNames.COUCHBASE_TEMPLATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the bean class that will be constructed.
|
||||
*
|
||||
* @param element the XML element which contains the attributes.
|
||||
* @return the class type to instantiate.
|
||||
*/
|
||||
@Override
|
||||
protected Class getBeanClass(final Element element) {
|
||||
return CouchbaseTemplate.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the bean definition and build up the bean.
|
||||
*
|
||||
* @param element the XML element which contains the attributes.
|
||||
* @param bean the builder which builds the bean.
|
||||
*/
|
||||
@Override
|
||||
protected void doParse(final Element element, final BeanDefinitionBuilder bean) {
|
||||
String bucketRef = element.getAttribute("bucket-ref");
|
||||
String converterRef = element.getAttribute("converter-ref");
|
||||
String translationServiceRef = element.getAttribute("translation-service-ref");
|
||||
|
||||
bean.addConstructorArgReference(StringUtils.hasText(bucketRef) ? bucketRef : BeanNames.COUCHBASE_BUCKET);
|
||||
|
||||
if (StringUtils.hasText(converterRef)) {
|
||||
bean.addConstructorArgReference(converterRef);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(translationServiceRef)) {
|
||||
bean.addConstructorArgReference(translationServiceRef);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors
|
||||
*
|
||||
* 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.springframework.data.couchbase.monitor;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.bucket.BucketInfo;
|
||||
|
||||
import org.springframework.jmx.export.annotation.ManagedAttribute;
|
||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
||||
|
||||
/**
|
||||
* Exposes basic client information.
|
||||
*
|
||||
* @author Michael Nitschinger
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@ManagedResource(description = "Client Information")
|
||||
public class ClientInfo {
|
||||
|
||||
private final Bucket bucket;
|
||||
private final BucketInfo info;
|
||||
|
||||
public ClientInfo(final Bucket bucket) {
|
||||
this.bucket = bucket;
|
||||
this.info = bucket.bucketManager().info();
|
||||
}
|
||||
|
||||
@ManagedAttribute(description = "Hostnames of connected nodes")
|
||||
public String getHostNames() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (InetAddress node : info.nodeList()) {
|
||||
result.append(node.toString()).append(",");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@ManagedAttribute(description = "Number of connected nodes")
|
||||
public int getNumberOfNodes() {
|
||||
return info.nodeCount();
|
||||
}
|
||||
|
||||
//TODO obtain count of available nodes vs unavailable ones and expose it
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors
|
||||
*
|
||||
* 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.springframework.data.couchbase.monitor;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.bucket.BucketInfo;
|
||||
|
||||
import org.springframework.jmx.export.annotation.ManagedAttribute;
|
||||
import org.springframework.jmx.export.annotation.ManagedMetric;
|
||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Exposes basic cluster information.
|
||||
*
|
||||
* @author Michael Nitschinger
|
||||
* @author Simon Baslé
|
||||
*/
|
||||
@ManagedResource(description = "Cluster Information")
|
||||
public class ClusterInfo {
|
||||
|
||||
private final RestTemplate template;
|
||||
private final Bucket bucket;
|
||||
private final BucketInfo info;
|
||||
|
||||
public ClusterInfo(final Bucket bucket) {
|
||||
this.template = new RestTemplate();
|
||||
this.bucket = bucket;
|
||||
this.info = bucket.bucketManager().info();
|
||||
}
|
||||
|
||||
@ManagedMetric(description = "Total RAM assigned")
|
||||
public long getTotalRAMAssigned() {
|
||||
return convertPotentialLong(parseStorageTotals().get("ram").get("total"));
|
||||
}
|
||||
|
||||
@ManagedMetric(description = "Total RAM used")
|
||||
public long getTotalRAMUsed() {
|
||||
return convertPotentialLong(parseStorageTotals().get("ram").get("used"));
|
||||
}
|
||||
|
||||
@ManagedMetric(description = "Total Disk Space assigned")
|
||||
public long getTotalDiskAssigned() {
|
||||
return convertPotentialLong(parseStorageTotals().get("hdd").get("total"));
|
||||
}
|
||||
|
||||
@ManagedMetric(description = "Total Disk Space used")
|
||||
public long getTotalDiskUsed() {
|
||||
return convertPotentialLong(parseStorageTotals().get("hdd").get("used"));
|
||||
}
|
||||
|
||||
@ManagedMetric(description = "Total Disk Space free")
|
||||
public long getTotalDiskFree() {
|
||||
return convertPotentialLong(parseStorageTotals().get("hdd").get("free"));
|
||||
}
|
||||
|
||||
@ManagedAttribute(description = "Cluster is Balanced")
|
||||
public boolean getIsBalanced() {
|
||||
return (Boolean) fetchPoolInfo().get("balanced");
|
||||
}
|
||||
|
||||
@ManagedAttribute(description = "Rebalance Status")
|
||||
public String getRebalanceStatus() {
|
||||
return (String) fetchPoolInfo().get("rebalanceStatus");
|
||||
}
|
||||
|
||||
@ManagedAttribute(description = "Maximum Available Buckets")
|
||||
public int getMaxBuckets() {
|
||||
return (Integer) fetchPoolInfo().get("maxBucketCount");
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on the value size, either int or long can be passed in and get
|
||||
* converted to long.
|
||||
*
|
||||
* @param value the value to convert.
|
||||
* @return the converted value.
|
||||
*/
|
||||
private long convertPotentialLong(Object value) {
|
||||
if (value instanceof Integer) {
|
||||
return new Long((Integer) value);
|
||||
}
|
||||
else if (value instanceof Long) {
|
||||
return (Long) value;
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Cannot convert value to long: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
protected String randomAvailableHostname() {
|
||||
List<InetAddress> available = info.nodeList();
|
||||
Collections.shuffle(available);
|
||||
return available.get(0).getHostName();
|
||||
}
|
||||
|
||||
private HashMap<String, Object> fetchPoolInfo() {
|
||||
return template.getForObject("http://"
|
||||
+ randomAvailableHostname() + ":8091/pools/default", HashMap.class);
|
||||
}
|
||||
|
||||
private HashMap<String, HashMap> parseStorageTotals() {
|
||||
HashMap<String, Object> stats = fetchPoolInfo();
|
||||
return (HashMap<String, HashMap>) stats.get("storageTotals");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user