Browse Source

Add some tests for conversion, nested object conversion support, and base classes for use in MVC analystics

pull/1/head
Mark Pollack 15 years ago
parent
commit
e2a9193a7f
  1. 84
      spring-datastore-document-core/src/main/java/org/springframework/datastore/document/analytics/MvcEvent.java
  2. 35
      spring-datastore-document-core/src/main/java/org/springframework/datastore/document/analytics/Parameters.java
  3. 6
      spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoTemplate.java
  4. 138
      spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/SimpleMongoConverter.java
  5. 42
      spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/Person.java
  6. 51
      spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/Portfolio.java
  7. 68
      spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/SimpleMongoConverterTests.java
  8. 62
      spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/Trade.java
  9. 74
      spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/User.java
  10. 148
      spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/analytics/MvcAnalyticsTests.java

84
spring-datastore-document-core/src/main/java/org/springframework/datastore/document/analytics/MvcEvent.java

@ -0,0 +1,84 @@
package org.springframework.datastore.document.analytics;
import java.util.Date;
public class MvcEvent {
private String controller;
private String action;
private Parameters parameters;
private Date date;
private String requestUri;
private String requestAddress;
private String remoteUser;
private String view;
public String getController() {
return controller;
}
public void setController(String controller) {
this.controller = controller;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public Parameters getParameters() {
return parameters;
}
public void setParameters(Parameters parameters) {
this.parameters = parameters;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getRequestUri() {
return requestUri;
}
public void setRequestUri(String requestUri) {
this.requestUri = requestUri;
}
public String getRequestAddress() {
return requestAddress;
}
public void setRequestAddress(String requestAddress) {
this.requestAddress = requestAddress;
}
public String getRemoteUser() {
return remoteUser;
}
public void setRemoteUser(String remoteUser) {
this.remoteUser = remoteUser;
}
//TODO
//Map sessionAttributes
}

35
spring-datastore-document-core/src/main/java/org/springframework/datastore/document/analytics/Parameters.java

@ -0,0 +1,35 @@
package org.springframework.datastore.document.analytics;
public class Parameters {
private String p1;
private String p2;
private String p3;
public String getP1() {
return p1;
}
public void setP1(String p1) {
this.p1 = p1;
}
public String getP2() {
return p2;
}
public void setP2(String p2) {
this.p2 = p2;
}
public String getP3() {
return p3;
}
public void setP3(String p3) {
this.p3 = p3;
}
}

6
spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/MongoTemplate.java

@ -79,7 +79,7 @@ public class MongoTemplate extends AbstractDocumentStoreTemplate<DB> implements
command.toString() + " failed: " + err); command.toString() + " failed: " + err);
} }
} }
public DBCollection createCollection(String collectionName) { public DBCollection createCollection(String collectionName) {
try { try {
return getConnection().createCollection(collectionName, null); return getConnection().createCollection(collectionName, null);
@ -95,6 +95,7 @@ public class MongoTemplate extends AbstractDocumentStoreTemplate<DB> implements
throw new InvalidDataAccessApiUsageException("Error creating collection " + collectionName + ": " + e.getMessage(), e); throw new InvalidDataAccessApiUsageException("Error creating collection " + collectionName + ": " + e.getMessage(), e);
} }
} }
public boolean collectionExists(String collectionName) { public boolean collectionExists(String collectionName) {
try { try {
@ -250,6 +251,9 @@ public class MongoTemplate extends AbstractDocumentStoreTemplate<DB> implements
db.createCollection(getDefaultCollectionName(), null); db.createCollection(getDefaultCollectionName(), null);
} }
} }
if (this.mongoConverter == null) {
mongoConverter = new SimpleMongoConverter();
}
} }
} }

138
spring-datastore-mongodb/src/main/java/org/springframework/datastore/document/mongodb/SimpleMongoConverter.java

@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -35,11 +36,13 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.GenericConversionService; import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject; import com.mongodb.DBObject;
import com.mongodb.DBRef; import com.mongodb.DBRef;
public class SimpleMongoConverter implements MongoConverter { public class SimpleMongoConverter implements MongoConverter {
/** Logger available to subclasses */ /** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass()); protected final Log logger = LogFactory.getLog(getClass());
@ -100,48 +103,91 @@ public class SimpleMongoConverter implements MongoConverter {
initializeConverters(); initializeConverters();
} }
protected void initializeConverters() { public SimpleMongoConverter(GenericConversionService conversionService) {
super();
this.conversionService = conversionService;
}
protected void initializeConverters() {
conversionService.addConverter(new Converter<ObjectId, String>() { conversionService.addConverter(new Converter<ObjectId, String>() {
public String convert(ObjectId id) { public String convert(ObjectId id) {
return id.toString(); return id.toString();
} }
}); });
}
/*
public ConversionContext getConversionContext() {
return conversionContext;
} }
public SimpleMongoConverter(GenericConversionService conversionService) { public void setConversionContext(ConversionContext conversionContext) {
super(); this.conversionContext = conversionContext;
this.conversionService = conversionService;
} }
public void writeNew(Object obj, DBObject dbo) {
conversionContext.convertToDBObject(dbo, null, obj);
}*/
public void write(Object obj, DBObject dbo) { public void write(Object obj, DBObject dbo) {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(obj); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(obj);
// This will leverage the conversion service.
initBeanWrapper(bw); initBeanWrapper(bw);
PropertyDescriptor[] propertyDescriptors = BeanUtils PropertyDescriptor[] propertyDescriptors = BeanUtils
.getPropertyDescriptors(obj.getClass()); .getPropertyDescriptors(obj.getClass());
for (PropertyDescriptor pd : propertyDescriptors) { for (PropertyDescriptor pd : propertyDescriptors) {
if (isSimpleType(pd.getPropertyType())) { // if (isSimpleType(pd.getPropertyType())) {
Object value = bw.getPropertyValue(pd.getName()); Object value = bw.getPropertyValue(pd.getName());
String keyToUse = ("id".equals(pd.getName()) ? "_id" : pd String keyToUse = ("id".equals(pd.getName()) ? "_id" : pd.getName());
.getName());
if (isValidProperty(pd)) {
if (isValidProperty(pd)) { // TODO validate Enums...
writeValue(dbo, keyToUse, value);
//TODO validate Enums... // dbo.put(keyToUse, value);
} else {
// This will leverage the conversion service. logger.warn("Unable to map property " + pd.getName()
dbo.put(keyToUse, value); + ". Skipping.");
} else {
logger.warn("Unable to map property " + pd.getName() + ". Skipping.");
}
} }
// }
}
}
private void writeValue(DBObject dbo, String keyToUse, Object value) {
// is not asimple type.
if (value != null) {
if (!isSimpleType(value.getClass())) {
writeCompoundValue(dbo, keyToUse, value);
} else {
dbo.put(keyToUse, value);
}
} }
} }
private void writeCompoundValue(DBObject dbo, String keyToUse, Object value) {
if (value instanceof Map) {
// Should write a collection!
return;
}
if (value instanceof Collection) {
// Should write a collection!
return;
}
DBObject nestedDbo = new BasicDBObject();
dbo.put(keyToUse, nestedDbo);
write(value, nestedDbo);
}
/*
public Object readNew(Class<? extends Object> clazz, DBObject dbo) {
return conversionContext.convertToObject(clazz, dbo);
}*/
public Object read(Class<? extends Object> clazz, DBObject dbo) { public Object read(Class<? extends Object> clazz, DBObject dbo) {
Assert.state(clazz != null, "Mapped class was not specified"); Assert.state(clazz != null, "Mapped class was not specified");
@ -151,24 +197,26 @@ public class SimpleMongoConverter implements MongoConverter {
initBeanWrapper(bw); initBeanWrapper(bw);
// Iterate over properties of the object. // Iterate over properties of the object.
// TODO iterate over the properties of DBObject and support nested property names with SpEL
// e.g. { "parameters.p1" : "1" , "count" : 5.0}
PropertyDescriptor[] propertyDescriptors = BeanUtils PropertyDescriptor[] propertyDescriptors = BeanUtils
.getPropertyDescriptors(clazz); .getPropertyDescriptors(clazz);
for (PropertyDescriptor pd : propertyDescriptors) { for (PropertyDescriptor pd : propertyDescriptors) {
if (isSimpleType(pd.getPropertyType())) {
if (dbo.containsField(pd.getName())) { if (dbo.containsField(pd.getName())) {
Object value = dbo.get(pd.getName()); Object value = dbo.get(pd.getName());
if (value instanceof ObjectId) { if (value instanceof ObjectId) {
setObjectIdOnObject(bw, pd, (ObjectId) value); setObjectIdOnObject(bw, pd, (ObjectId) value);
} else {
if (isValidProperty(pd)) {
// This will leverage the conversion service.
// bw.setPropertyValue(pd.getName(),
// dbo.get(pd.getName()));
readValue(bw, pd, dbo);
} else { } else {
if (isValidProperty(pd)) { logger.warn("Unable to map DBObject field "
// This will leverage the conversion service. + pd.getName() + " to property " + pd.getName()
bw.setPropertyValue(pd.getName(), + ". Skipping.");
dbo.get(pd.getName()));
} else {
logger.warn("Unable to map DBObject field "
+ pd.getName() + " to property "
+ pd.getName() + ". Skipping.");
}
} }
} }
} }
@ -177,6 +225,32 @@ public class SimpleMongoConverter implements MongoConverter {
return mappedObject; return mappedObject;
} }
private void readValue(BeanWrapper bw, PropertyDescriptor pd, DBObject dbo) {
Object value = dbo.get(pd.getName());
// is not a simple type.
if (!isSimpleType(value.getClass())) {
bw.setPropertyValue(
pd.getName(),
readCompoundValue(pd.getPropertyType(),
(DBObject) dbo.get(pd.getName())));
} else {
bw.setPropertyValue(pd.getName(), value);
}
}
private Object readCompoundValue(Class<?> propertyClazz, DBObject dbo) {
if (Map.class.isAssignableFrom(propertyClazz)) {
// Should read a map!
return null;
}
if (Collection.class.isAssignableFrom(propertyClazz)) {
// Should read a collection!
return null;
}
// single document
return read(propertyClazz, dbo);
}
protected void setObjectIdOnObject(BeanWrapper bw, PropertyDescriptor pd, protected void setObjectIdOnObject(BeanWrapper bw, PropertyDescriptor pd,
ObjectId value) { ObjectId value) {
// TODO strategy for setting the id field. suggest looking for public // TODO strategy for setting the id field. suggest looking for public

42
spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/Person.java

@ -0,0 +1,42 @@
/*
* Copyright 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.datastore.document.mongodb;
public class Person {
private String firstName;
private Person friend;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public Person getFriend() {
return friend;
}
public void setFriend(Person friend) {
this.friend = friend;
}
}

51
spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/Portfolio.java

@ -0,0 +1,51 @@
/*
* Copyright 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.datastore.document.mongodb;
import java.util.ArrayList;
import java.util.List;
public class Portfolio {
private String portfolioName;
private User user;
private List trades;
public Portfolio() {
trades = new ArrayList();
}
public String getPortfolioName() {
return portfolioName;
}
public void setPortfolioName(String portfolioName) {
this.portfolioName = portfolioName;
}
public List getTrades() {
return trades;
}
public void setTrades(List trades) {
this.trades = trades;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

68
spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/SimpleMongoConverterTests.java

@ -15,13 +15,79 @@
*/ */
package org.springframework.datastore.document.mongodb; package org.springframework.datastore.document.mongodb;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
public class SimpleMongoConverterTests { public class SimpleMongoConverterTests {
@Test @Test
public void converters() { public void notNestedObject() {
User user = new User();
user.setAccountName("My Account");
user.setUserName("Mark");
SimpleMongoConverter converter = createConverter();
DBObject dbo = new BasicDBObject();
converter.write(user, dbo);
Assert.assertEquals("My Account", dbo.get("accountName"));
Assert.assertEquals("Mark", dbo.get("userName"));
User u = (User) converter.read(User.class, dbo);
Assert.assertEquals("My Account", u.getAccountName());
Assert.assertEquals("Mark", u.getUserName());
}
@Test
public void nestedObject() {
Portfolio p = createPortfolioWithNoTrades();
SimpleMongoConverter converter = createConverter();
DBObject dbo = new BasicDBObject();
converter.write(p, dbo);
Assert.assertEquals("High Risk Trading Account", dbo.get("portfolioName"));
Assert.assertTrue(dbo.containsField("user"));
Portfolio cp = (Portfolio) converter.read(Portfolio.class, dbo);
Assert.assertEquals("High Risk Trading Account", cp.getPortfolioName());
Assert.assertEquals("Joe Trader", cp.getUser().getUserName());
Assert.assertEquals("ACCT-123", cp.getUser().getAccountName());
}
private SimpleMongoConverter createConverter() {
SimpleMongoConverter converter = new SimpleMongoConverter();
ConversionContext context = new ConversionContext();
context.setBuilderLookup(new BuilderLookup());
converter.setConversionContext(context);
return converter;
}
@Test
public void instanceOfTests() {
List<String> list = new ArrayList<String>();
Assert.assertTrue(list instanceof Collection);
List objList = new ArrayList();
Assert.assertTrue(objList instanceof Collection);
} }
protected Portfolio createPortfolioWithNoTrades()
{
Portfolio portfolio = new Portfolio();
User user = new User();
user.setUserName("Joe Trader");
user.setAccountName("ACCT-123");
portfolio.setUser(user);
portfolio.setPortfolioName("High Risk Trading Account");
return portfolio;
}
} }

62
spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/Trade.java

@ -0,0 +1,62 @@
/*
* Copyright 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.datastore.document.mongodb;
public class Trade {
private String ticker;
private long quantity;
private double price;
private String orderType;
public String getOrderType() {
return orderType;
}
public void setOrderType(String orderType) {
this.orderType = orderType;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public long getQuantity() {
return quantity;
}
public void setQuantity(long quantity) {
this.quantity = quantity;
}
public String getTicker() {
return ticker;
}
public void setTicker(String ticker) {
this.ticker = ticker;
}
}

74
spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/User.java

@ -0,0 +1,74 @@
/*
* Copyright 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.datastore.document.mongodb;
public class User {
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((accountName == null) ? 0 : accountName.hashCode());
result = prime * result
+ ((userName == null) ? 0 : userName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (accountName == null) {
if (other.accountName != null)
return false;
} else if (!accountName.equals(other.accountName))
return false;
if (userName == null) {
if (other.userName != null)
return false;
} else if (!userName.equals(other.userName))
return false;
return true;
}
private String accountName;
private String userName;
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}

148
spring-datastore-mongodb/src/test/java/org/springframework/datastore/document/mongodb/analytics/MvcAnalyticsTests.java

@ -0,0 +1,148 @@
package org.springframework.datastore.document.mongodb.analytics;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.datastore.document.analytics.MvcEvent;
import org.springframework.datastore.document.analytics.Parameters;
import org.springframework.datastore.document.mongodb.MongoTemplate;
import org.springframework.datastore.document.mongodb.query.Query;
//import org.springframework.datastore.document.mongodb.query.QueryBuilder;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.QueryBuilder;
public class MvcAnalyticsTests {
private MongoTemplate mongoTemplate;
@Before
public void setUp() throws Exception {
Mongo m = new Mongo();
DB db = m.getDB("mvc");
mongoTemplate = new MongoTemplate(db);
mongoTemplate.setDefaultCollectionName("mvc");
mongoTemplate.afterPropertiesSet();
//mongoTemplate.dropCollection("mvc");
//mongoTemplate.createCollection("mvc");
}
@Test
public void loadData() {
//datasize, favoriteRestId
createAndStoreForP1(5, 1);
createAndStoreForP1(6, 2);
createAndStoreForP1(3, 3);
createAndStoreForP1(8, 4);
List<MvcEvent> mvcEvents = mongoTemplate.queryForCollection("mvc", MvcEvent.class);
Assert.assertEquals(22, mvcEvents.size());
}
/*
var start = new Date(2010,9,1);
var end = new Date(2010,11,1);
db.mvc.group(
{ cond: {"action": "addFavoriteRestaurant", "date": {$gte: start, $lt: end}}
, key: {"parameters.p1": true}
, initial: {count: 0}
, reduce: function(doc, out){ out.count++; }
} );
*/
@Test
public void listAll() {
List<MvcEvent> mvcEvents = mongoTemplate.queryForCollection("mvc", MvcEvent.class);
for (MvcEvent mvcEvent : mvcEvents) {
System.out.println(mvcEvent.getDate());
}
//System.out.println(mvcEvents);
}
@Test
public void groupQuery() {
//This circumvents exception translation
DBCollection collection = mongoTemplate.getConnection().getCollection("mvc");
//QueryBuilder qb = new QueryBuilder();
//qb.start("date").greaterThan(object)
Calendar startDate = Calendar.getInstance();
startDate.clear();
startDate.set(Calendar.YEAR, 2010);
startDate.set(Calendar.MONTH, 5);
Calendar endDate = Calendar.getInstance();
endDate.clear();
endDate.set(Calendar.YEAR, 2010);
endDate.set(Calendar.MONTH, 12);
/*
QueryBuilder qb = new QueryBuilder();
Query q = qb.find("date").gte(startDate.getTime()).lt(endDate.getTime()).and("action").is("addFavoriteRestaurant").build();
DBObject cond2 = q.getQueryObject();
*/
DBObject cond = QueryBuilder.start("date").greaterThanEquals(startDate.getTime()).lessThan(endDate.getTime()).and("action").is("addFavoriteRestaurant").get();
DBObject key = new BasicDBObject("parameters.p1", true);
/*
DBObject dateQ = new BasicDBObject();
dateQ.put("$gte", startDate.getTime());
dateQ.put("$lt", endDate.getTime());
DBObject cond = new BasicDBObject();
cond.put("action", "addFavoriteRestaurant");
cond.put("date", dateQ);*/
DBObject intitial = new BasicDBObject("count", 0);
DBObject result = collection.group(key, cond, intitial, "function(doc, out){ out.count++; }");
if (result instanceof BasicDBList) {
BasicDBList dbList = (BasicDBList) result;
for (Iterator iterator = dbList.iterator(); iterator.hasNext();) {
DBObject dbo = (DBObject) iterator.next();
System.out.println(dbo);
}
}
Map resultMap = result.toMap();
System.out.println(result);
}
private void createAndStoreForP1(int dataSize, int p1) {
for (int i = 0; i < dataSize; i++) {
MvcEvent event = generateEvent(p1);
mongoTemplate.save(event);
}
}
private MvcEvent generateEvent(Integer p1) {
MvcEvent event = new MvcEvent();
event.setController("RestaurantController");
event.setAction("addFavoriteRestaurant");
event.setDate(new Date());
event.setRemoteUser("mpollack");
event.setRequestAddress("127.0.0.1");
event.setRequestUri("/myrestaurants-analytics/restaurants");
Parameters params = new Parameters();
params.setP1(p1.toString());
params.setP2("2");
event.setParameters(params);
return event;
}
}
Loading…
Cancel
Save