diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdmin.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdmin.java new file mode 100644 index 000000000..0b5586752 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdmin.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2011 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.document.mongodb; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.stereotype.Component; + +import com.mongodb.DB; +import com.mongodb.Mongo; + +/** + * Mongo server administration exposed via JMX annotations + * + * @author Mark Pollack + * + */ + +@ManagedResource(description="Mongo Admin Operations") +public class MongoAdmin implements MongoAdminOperations { + + /** Logger available to subclasses */ + protected final Log logger = LogFactory.getLog(getClass()); + + private Mongo mongo; + private String username; + private String password; + + public MongoAdmin(Mongo mongo) { + this.mongo = mongo; + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoAdminOperations#dropDatabase(java.lang.String) + */ + @ManagedOperation + public void dropDatabase(String databaseName) { + mongo.getDB(databaseName).dropDatabase(); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoAdminOperations#createDatabase(java.lang.String) + */ + @ManagedOperation + public void createDatabase(String databaseName) { + mongo.getDB(databaseName); + } + + /* (non-Javadoc) + * @see org.springframework.data.document.mongodb.MongoAdminOperations#getDatabaseStats(java.lang.String) + */ + @ManagedOperation + public String getDatabaseStats(String databaseName) { + return mongo.getDB("testAdminDb").getStats().toString(); + } + + /** + * Sets the username to use to connect to the Mongo database + * + * @param username The username to use + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Sets the password to use to authenticate with the Mongo database. + * + * @param password The password to use + */ + public void setPassword(String password) { + + this.password = password; + } + + + public DB getDb(String databaseName) { + return MongoDbUtils.getDB(mongo, databaseName, username, password == null ? null : password.toCharArray()); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdminOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdminOperations.java new file mode 100644 index 000000000..40113cbd6 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/MongoAdminOperations.java @@ -0,0 +1,16 @@ +package org.springframework.data.document.mongodb; + +import org.springframework.jmx.export.annotation.ManagedOperation; + +public interface MongoAdminOperations { + + @ManagedOperation + public abstract void dropDatabase(String databaseName); + + @ManagedOperation + public abstract void createDatabase(String databaseName); + + @ManagedOperation + public abstract String getDatabaseStats(String databaseName); + +} \ No newline at end of file diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AbstractMonitor.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AbstractMonitor.java new file mode 100644 index 000000000..e0aca0899 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/AbstractMonitor.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2011 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.document.mongodb.monitor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.data.document.mongodb.MongoDbUtils; + +import com.mongodb.CommandResult; +import com.mongodb.DB; +import com.mongodb.Mongo; +import com.mongodb.MongoException; + +/** + * Base class to encapsulate common configuration settings when connecting to a database + * + * @author Mark Pollack + * + */ +public abstract class AbstractMonitor { + + private final Log logger = LogFactory.getLog(getClass()); + + protected Mongo mongo; + private String username; + private String password; + + + /** + * Sets the username to use to connect to the Mongo database + * + * @param username The username to use + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Sets the password to use to authenticate with the Mongo database. + * + * @param password The password to use + */ + public void setPassword(String password) { + + this.password = password; + } + + public CommandResult getServerStatus() { + CommandResult result = getDb("admin").command("serverStatus"); + if (!result.ok()) { + logger.error("Could not query for server status. Command Result = " + result); + throw new MongoException("could not query for server status. Command Result = " + result); + } + return result; + } + + public DB getDb(String databaseName) { + return MongoDbUtils.getDB(mongo, databaseName, username, password == null ? null : password.toCharArray()); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/GlobalLockMetrics.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/GlobalLockMetrics.java new file mode 100644 index 000000000..eaebe3da6 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/GlobalLockMetrics.java @@ -0,0 +1,77 @@ +/* + * Copyright 2002-2011 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.document.mongodb.monitor; + +import org.springframework.jmx.export.annotation.ManagedMetric; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.jmx.support.MetricType; + +import com.mongodb.DBObject; +import com.mongodb.Mongo; + +@ManagedResource(description="Mongo Global Lock Metrics") +public class GlobalLockMetrics extends AbstractMonitor { + + + public GlobalLockMetrics(Mongo mongo) { + this.mongo = mongo; + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Total time") + public double getTotalTime() { + return getGlobalLockData("totalTime", java.lang.Double.class); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Lock time", unit="seconds") + public double getLockTime() { + return getGlobalLockData("lockTime", java.lang.Double.class); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Lock time") + public double getLockTimeRatio() { + return getGlobalLockData("ratio", java.lang.Double.class); + } + + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Current Queue") + public int getCurrentQueueTotal() { + return getCurrentQueue("total"); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Reader Queue") + public int getCurrentQueueReaders() { + return getCurrentQueue("readers"); + } + + @ManagedMetric(metricType = MetricType.GAUGE, displayName = "Writer Queue") + public int getCurrentQueueWriters() { + return getCurrentQueue("writers"); + } + + @SuppressWarnings("unchecked") + private T getGlobalLockData(String key, Class targetClass) { + DBObject globalLock = (DBObject) getServerStatus().get("globalLock"); + Object o = globalLock.get("totalTime"); + return (T) globalLock.get(key); + } + + private int getCurrentQueue(String key) { + DBObject globalLock = (DBObject) getServerStatus().get("globalLock"); + DBObject currentQueue = (DBObject) globalLock.get("currentQueue"); + Object o = currentQueue.get("total"); + return (Integer) currentQueue.get(key); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/OperationCounters.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/OperationCounters.java new file mode 100644 index 000000000..b692c0cca --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/OperationCounters.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2011 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.document.mongodb.monitor; + +import org.springframework.jmx.export.annotation.ManagedMetric; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.jmx.support.MetricType; + +import com.mongodb.DBObject; +import com.mongodb.Mongo; + +@ManagedResource(description="Mongo Operation Counters") +public class OperationCounters extends AbstractMonitor { + + + public OperationCounters(Mongo mongo) { + this.mongo = mongo; + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Insert operation count") + public int getInsertCount() { + return getOpCounter("insert"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Query operation count") + public int getQueryCount() { + return getOpCounter("query"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Update operation count") + public int getUpdateCount() { + return getOpCounter("update"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Delete operation count") + public int getDeleteCount() { + return getOpCounter("delete"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "GetMore operation count") + public int getGetMoreCount() { + return getOpCounter("getmore"); + } + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Command operation count") + public int getCommandCount() { + return getOpCounter("command"); + } + + private int getOpCounter(String key) { + DBObject opCounters = (DBObject) getServerStatus().get("opcounters"); + return (Integer) opCounters.get(key); + } +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ServerInfo.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ServerInfo.java new file mode 100644 index 000000000..911413f1f --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/monitor/ServerInfo.java @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2011 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.document.mongodb.monitor; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.springframework.jmx.export.annotation.ManagedMetric; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.jmx.support.MetricType; + +import com.mongodb.CommandResult; +import com.mongodb.Mongo; + +/** + * Expose basic server information + * + * @author Mark Pollack + * + */ +@ManagedResource(description="Mongo Server Information") +public class ServerInfo extends AbstractMonitor { + + public ServerInfo(Mongo mongo) { + this.mongo = mongo; + } + + + @ManagedOperation(description="Server host name") + public String getHostName() throws UnknownHostException { + return InetAddress.getLocalHost().getHostName(); + } + + @ManagedMetric(displayName="Uptime Estimate") + public double getUptimeEstimate() + { + return (Double)getServerStatus().get("uptimeEstimate"); + } + + @ManagedOperation(description="MongoDB Server Version") + public String getVersion() { + return (String) getServerStatus().get("version"); + } + + @ManagedOperation(description="Local Time") + public String getLocalTime() { + return (String) getServerStatus().get("localTime"); + } + + + @ManagedMetric(metricType = MetricType.COUNTER, displayName = "Server uptime in seconds", unit="seconds") + public double getUptime() { + return (Double) getServerStatus().get("uptime"); + } + +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/JmxServer.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/JmxServer.java new file mode 100644 index 000000000..ca49723d5 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/JmxServer.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2010 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.document.mongodb; + +import org.junit.Test; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Server application than can be run as an app or unit test. + * + * @author Mark Pollack + */ +public class JmxServer { + + public static void main(String[] args) { + new JmxServer().run(); + } + + public void run() { + new ClassPathXmlApplicationContext(new String[] {"infrastructure.xml", "server-jmx.xml"} ); + } + +} diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoAdminIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoAdminIntegrationTests.java new file mode 100644 index 000000000..96395db1d --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/MongoAdminIntegrationTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2011 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.document.mongodb; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.mongodb.CommandResult; +import com.mongodb.DB; +import com.mongodb.Mongo; + + +/** + * + * This test class assumes that you are already running the MongoDB server. + * + * @author Mark Pollack + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:infrastructure.xml") +public class MongoAdminIntegrationTests { + + private static Log logger = LogFactory.getLog(MongoAdminIntegrationTests.class); + + private MongoAdminOperations mongoAdmin; + + private DB testAdminDb; + + @Autowired + Mongo mongo; + + @Before + public void setUp() { + mongo.getDB("testAdminDb").dropDatabase(); + testAdminDb = mongo.getDB("testAdminDb"); + + } + + @Test + public void serverStats() { + //CommandResult result = testAdminDb.getStats(); + CommandResult result = mongo.getDB("admin").command("serverStatus"); + logger.info("stats = " + result); + } +} \ No newline at end of file diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests.java new file mode 100644 index 000000000..e7d68fff3 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2011 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.document.mongodb.monitor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +import com.mongodb.CommandResult; +import com.mongodb.DB; +import com.mongodb.Mongo; + + +/** + * + * This test class assumes that you are already running the MongoDB server. + * + * @author Mark Pollack + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class MongoMonitorIntegrationTests { + + @Autowired + Mongo mongo; + + @Test + public void serverInfo() { + ServerInfo serverInfo = new ServerInfo(mongo); + String version = serverInfo.getVersion(); + Assert.isTrue(StringUtils.hasText("1.")); + } + + @Test + public void operationCounters() { + OperationCounters operationCounters = new OperationCounters(mongo); + operationCounters.getInsertCount(); + } +} \ No newline at end of file diff --git a/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests-context.xml b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests-context.xml new file mode 100644 index 000000000..22dd36542 --- /dev/null +++ b/spring-data-mongodb/src/test/resources/org/springframework/data/document/mongodb/monitor/MongoMonitorIntegrationTests-context.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/spring-data-mongodb/src/test/resources/server-jmx.xml b/spring-data-mongodb/src/test/resources/server-jmx.xml new file mode 100644 index 000000000..342e2f613 --- /dev/null +++ b/spring-data-mongodb/src/test/resources/server-jmx.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-data-mongodb/template.mf b/spring-data-mongodb/template.mf index f627242f3..5f8a12d36 100644 --- a/spring-data-mongodb/template.mf +++ b/spring-data-mongodb/template.mf @@ -9,6 +9,7 @@ Import-Template: org.springframework.core.*;version="[3.0.0, 4.0.0)", org.springframework.dao.*;version="[3.0.0, 4.0.0)", org.springframework.util.*;version="[3.0.0, 4.0.0)", + org.springframework.jmx.export.*;version="[3.0.0, 4.0.0)", org.springframework.transaction.*;version="[3.0.0, 4.0.0)", org.springframework.data.core.*;version="[1.0.0, 2.0.0)", org.springframework.data.domain.*;version="[1.0.0, 2.0.0)",