Skip to content

Commit c752183

Browse files
author
Mark Pollack
committed
DATADOC-42 - Provide option for configuring replica sets using the Mongo namespace
1 parent 2e5906f commit c752183

File tree

10 files changed

+296
-66
lines changed

10 files changed

+296
-66
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2010 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.data.document.mongodb;
18+
19+
import org.springframework.dao.InvalidDataAccessApiUsageException;
20+
21+
public class InvalidMongoDbApiUsageException extends InvalidDataAccessApiUsageException {
22+
23+
public InvalidMongoDbApiUsageException(String msg) {
24+
super(msg);
25+
}
26+
27+
public InvalidMongoDbApiUsageException(String msg, Throwable cause) {
28+
super(msg, cause);
29+
}
30+
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2010 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.data.document.mongodb;
18+
19+
import org.springframework.dao.UncategorizedDataAccessException;
20+
21+
public class UncategorizedMongoDbException extends UncategorizedDataAccessException {
22+
23+
public UncategorizedMongoDbException(String msg, Throwable cause) {
24+
super(msg, cause);
25+
}
26+
27+
}

spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoDbFactoryParser.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa
9090
mongoBuilder.addPropertyValue("host", (StringUtils.hasText(overrideHost) ? overrideHost : host));
9191
String overridePort = mongoEl.getAttribute("port");
9292
mongoBuilder.addPropertyValue("port", (StringUtils.hasText(overridePort) ? overridePort : port));
93-
new MongoParser().parseOptions(parserContext, mongoEl, mongoBuilder);
93+
ParsingUtils.parseMongoOptions(parserContext, mongoEl, mongoBuilder);
94+
ParsingUtils.parseReplicaSet(parserContext, mongoEl, mongoBuilder);
9495
}
9596
else {
9697
mongoBuilder.addPropertyValue("host", host);

spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/config/MongoParser.java

Lines changed: 11 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.beans.factory.BeanDefinitionStoreException;
2020
import org.springframework.beans.factory.support.AbstractBeanDefinition;
2121
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
22+
import org.springframework.beans.factory.support.ManagedList;
2223
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
2324
import org.springframework.beans.factory.xml.ParserContext;
2425
import org.springframework.data.document.mongodb.MongoFactoryBean;
@@ -27,6 +28,8 @@
2728
import org.springframework.util.xml.DomUtils;
2829
import org.w3c.dom.Element;
2930

31+
import com.mongodb.ServerAddress;
32+
3033
/**
3134
* Parser for <mongo;gt; definitions. If no name
3235
*
@@ -42,46 +45,17 @@ protected Class<?> getBeanClass(Element element) {
4245
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
4346
super.doParse(element, builder);
4447

45-
setPropertyValue(element, builder, "port", "port");
46-
setPropertyValue(element, builder, "host", "host");
48+
ParsingUtils.setPropertyValue(element, builder, "port", "port");
49+
ParsingUtils.setPropertyValue(element, builder, "host", "host");
4750

48-
parseOptions(parserContext, element, builder);
51+
ParsingUtils.parseMongoOptions(parserContext, element, builder);
52+
ParsingUtils.parseReplicaSet(parserContext, element, builder);
4953

5054
}
5155

52-
/**
53-
* Parses the options sub-element. Populates the given attribute factory with the proper attributes.
54-
*
55-
* @param element
56-
* @param attrBuilder
57-
* @return true if parsing actually occured, false otherwise
58-
*/
59-
boolean parseOptions(ParserContext parserContext, Element element, BeanDefinitionBuilder mongoBuilder) {
60-
Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
61-
if (optionsElement == null)
62-
return false;
63-
64-
BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder
65-
.genericBeanDefinition(MongoOptionsFactoryBean.class);
66-
67-
setPropertyValue(optionsElement, optionsDefBuilder, "connections-per-host", "connectionsPerHost");
68-
setPropertyValue(optionsElement, optionsDefBuilder, "threads-allowed-to-block-for-connection-multiplier",
69-
"threadsAllowedToBlockForConnectionMultiplier");
70-
setPropertyValue(optionsElement, optionsDefBuilder, "max-wait-time", "maxWaitTime");
71-
setPropertyValue(optionsElement, optionsDefBuilder, "connect-timeout", "connectTimeout");
72-
setPropertyValue(optionsElement, optionsDefBuilder, "socket-timeout", "socketTimeout");
73-
setPropertyValue(optionsElement, optionsDefBuilder, "socket-keep-alive", "socketKeepAlive");
74-
setPropertyValue(optionsElement, optionsDefBuilder, "auto-connect-retry", "autoConnectRetry");
75-
setPropertyValue(optionsElement, optionsDefBuilder, "write-number", "writeNumber");
76-
setPropertyValue(optionsElement, optionsDefBuilder, "write-timeout", "writeTimeout");
77-
setPropertyValue(optionsElement, optionsDefBuilder, "write-fsync", "writeFsync");
78-
setPropertyValue(optionsElement, optionsDefBuilder, "slave-ok", "slaveOk");
79-
80-
81-
82-
mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
83-
return true;
84-
}
56+
57+
58+
8559

8660
@Override
8761
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
@@ -93,11 +67,5 @@ protected String resolveId(Element element, AbstractBeanDefinition definition, P
9367
return name;
9468
}
9569

96-
private void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName, String propertyName) {
97-
String attr = element.getAttribute(attrName);
98-
if (StringUtils.hasText(attr)) {
99-
builder.addPropertyValue(propertyName, attr);
100-
}
101-
}
102-
70+
10371
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2011 by the original author(s).
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.data.document.mongodb.config;
18+
19+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
20+
import org.springframework.beans.factory.support.ManagedList;
21+
import org.springframework.beans.factory.xml.ParserContext;
22+
import org.springframework.data.document.mongodb.MongoOptionsFactoryBean;
23+
import org.springframework.util.StringUtils;
24+
import org.springframework.util.xml.DomUtils;
25+
import org.w3c.dom.Element;
26+
27+
import com.mongodb.ServerAddress;
28+
29+
abstract class ParsingUtils {
30+
31+
/**
32+
* Parses the mongo replica-set element.
33+
* @param parserContext the parser context
34+
* @param element the mongo element
35+
* @param mongoBuilder the bean definition builder to populate
36+
* @return true if parsing actually occured, false otherwise
37+
*/
38+
static boolean parseReplicaSet(ParserContext parserContext, Element element, BeanDefinitionBuilder mongoBuilder) {
39+
40+
41+
String replicaSetString = element.getAttribute("replica-set");
42+
if (StringUtils.hasText(replicaSetString)) {
43+
ManagedList<Object> serverAddresses = new ManagedList<Object>();
44+
String[] replicaSetStringArray = StringUtils.commaDelimitedListToStringArray(replicaSetString);
45+
for (int i = 0; i < replicaSetStringArray.length; i++) {
46+
String[] hostAndPort = StringUtils.delimitedListToStringArray(replicaSetStringArray[i], ":");
47+
BeanDefinitionBuilder defBuilder = BeanDefinitionBuilder.genericBeanDefinition(ServerAddress.class);
48+
defBuilder.addConstructorArgValue(hostAndPort[0]);
49+
defBuilder.addConstructorArgValue(hostAndPort[1]);
50+
serverAddresses.add(defBuilder.getBeanDefinition());
51+
}
52+
if (!serverAddresses.isEmpty()) {
53+
mongoBuilder.addPropertyValue("replicaSetSeeds", serverAddresses);
54+
}
55+
}
56+
return true;
57+
58+
}
59+
/**
60+
* Parses the mongo:options sub-element. Populates the given attribute factory with the proper attributes.
61+
*
62+
* @return true if parsing actually occured, false otherwise
63+
*/
64+
static boolean parseMongoOptions(ParserContext parserContext, Element element, BeanDefinitionBuilder mongoBuilder) {
65+
Element optionsElement = DomUtils.getChildElementByTagName(element, "options");
66+
if (optionsElement == null)
67+
return false;
68+
69+
BeanDefinitionBuilder optionsDefBuilder = BeanDefinitionBuilder
70+
.genericBeanDefinition(MongoOptionsFactoryBean.class);
71+
72+
setPropertyValue(optionsElement, optionsDefBuilder, "connections-per-host", "connectionsPerHost");
73+
setPropertyValue(optionsElement, optionsDefBuilder, "threads-allowed-to-block-for-connection-multiplier",
74+
"threadsAllowedToBlockForConnectionMultiplier");
75+
setPropertyValue(optionsElement, optionsDefBuilder, "max-wait-time", "maxWaitTime");
76+
setPropertyValue(optionsElement, optionsDefBuilder, "connect-timeout", "connectTimeout");
77+
setPropertyValue(optionsElement, optionsDefBuilder, "socket-timeout", "socketTimeout");
78+
setPropertyValue(optionsElement, optionsDefBuilder, "socket-keep-alive", "socketKeepAlive");
79+
setPropertyValue(optionsElement, optionsDefBuilder, "auto-connect-retry", "autoConnectRetry");
80+
setPropertyValue(optionsElement, optionsDefBuilder, "write-number", "writeNumber");
81+
setPropertyValue(optionsElement, optionsDefBuilder, "write-timeout", "writeTimeout");
82+
setPropertyValue(optionsElement, optionsDefBuilder, "write-fsync", "writeFsync");
83+
setPropertyValue(optionsElement, optionsDefBuilder, "slave-ok", "slaveOk");
84+
85+
86+
87+
mongoBuilder.addPropertyValue("mongoOptions", optionsDefBuilder.getBeanDefinition());
88+
return true;
89+
}
90+
91+
static void setPropertyValue(Element element, BeanDefinitionBuilder builder, String attrName, String propertyName) {
92+
String attr = element.getAttribute(attrName);
93+
if (StringUtils.hasText(attr)) {
94+
builder.addPropertyValue(propertyName, attr);
95+
}
96+
}
97+
}

spring-data-mongodb/src/main/resources/org/springframework/data/document/mongodb/config/spring-mongo-1.0.xsd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ The host to connect to a MongoDB server. Default is localhost
283283
The comma delimited list of host:port entries to use for replica set/pairs.
284284
]]></xsd:documentation>
285285
</xsd:annotation>
286-
</xsd:attribute>
286+
</xsd:attribute>
287287
</xsd:complexType>
288288

289289
<xsd:complexType name="optionsType">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2010 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.data.document.mongodb.config;
18+
19+
import static org.junit.Assert.*;
20+
21+
import java.lang.reflect.Field;
22+
import java.util.List;
23+
24+
import org.junit.Test;
25+
import org.junit.runner.RunWith;
26+
import org.springframework.beans.factory.annotation.Autowired;
27+
import org.springframework.context.ApplicationContext;
28+
import org.springframework.data.document.mongodb.MongoFactoryBean;
29+
import org.springframework.test.context.ContextConfiguration;
30+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
31+
32+
import com.mongodb.Mongo;
33+
import com.mongodb.MongoOptions;
34+
import com.mongodb.ServerAddress;
35+
36+
@RunWith(SpringJUnit4ClassRunner.class)
37+
@ContextConfiguration
38+
public class MongoNamespaceReplicaSetTests extends NamespaceTestSupport {
39+
40+
@Autowired
41+
private ApplicationContext ctx;
42+
43+
44+
@Test
45+
public void testMongoWithReplicaSets() throws Exception {
46+
assertTrue(ctx.containsBean("replicaSetMongo"));
47+
MongoFactoryBean mfb = (MongoFactoryBean) ctx.getBean("&replicaSetMongo");
48+
String host = readField("host", mfb);
49+
Integer port = readField("port", mfb);
50+
List<ServerAddress> replicaSetSeeds = readField("replicaSetSeeds", mfb);
51+
assertNotNull(replicaSetSeeds);
52+
53+
assertEquals("127.0.0.1", replicaSetSeeds.get(0).getHost());
54+
assertEquals(27017, replicaSetSeeds.get(0).getPort());
55+
56+
assertEquals("localhost", replicaSetSeeds.get(1).getHost());
57+
assertEquals(27018, replicaSetSeeds.get(1).getPort());
58+
59+
Mongo mongo = mfb.getObject();
60+
61+
//TODO test infrastructure to have replica sets
62+
//assertEquals(2, mongo.getAllAddress().size());
63+
64+
}
65+
66+
}

spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/config/MongoNamespaceTests.java

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
import static org.junit.Assert.*;
2020

21-
import java.lang.reflect.Field;
22-
2321
import org.junit.Test;
2422
import org.junit.runner.RunWith;
2523
import org.springframework.beans.factory.annotation.Autowired;
@@ -33,7 +31,7 @@
3331

3432
@RunWith(SpringJUnit4ClassRunner.class)
3533
@ContextConfiguration
36-
public class MongoNamespaceTests {
34+
public class MongoNamespaceTests extends NamespaceTestSupport {
3735

3836
@Autowired
3937
private ApplicationContext ctx;
@@ -81,23 +79,5 @@ public void testMongoSingletonWithPropertyPlaceHolders() throws Exception {
8179

8280
}
8381

84-
@SuppressWarnings({ "unchecked" })
85-
public static <T> T readField(String name, Object target) throws Exception {
86-
Field field = null;
87-
Class<?> clazz = target.getClass();
88-
do {
89-
try {
90-
field = clazz.getDeclaredField(name);
91-
} catch (Exception ex) {
92-
}
93-
94-
clazz = clazz.getSuperclass();
95-
} while (field == null && !clazz.equals(Object.class));
9682

97-
if (field == null)
98-
throw new IllegalArgumentException("Cannot find field '" + name + "' in the class hierarchy of "
99-
+ target.getClass());
100-
field.setAccessible(true);
101-
return (T) field.get(target);
102-
}
10383
}

0 commit comments

Comments
 (0)