You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by ie...@apache.org on 2008/07/19 15:51:04 UTC
svn commit: r678158 - in /incubator/shindig/trunk: ./ java/social-api/
java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/
java/social-api/src/test/java/org/apache/shindig/social/
java/social-api/src/test/java/org/apache/shindig/so...
Author: ieb
Date: Sat Jul 19 06:51:03 2008
New Revision: 678158
URL: http://svn.apache.org/viewvc?rev=678158&view=rev
Log:
SHINDIG-451
Applying patch from the JIRA.
Adds a json-lib (net.sf) converter, not wired into social-api at present.
Added:
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConversionException.java
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConverter.java
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/JSONLibConverterUtils.java
incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/JSONObjectToMapMorpher.java
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/JsonLibTestsGuiceModule.java
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidator.java
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidatorExpcetion.java
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidatorTest.java
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConverterTest.java
incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/JsonConverterPerformancePerf.java
Modified:
incubator/shindig/trunk/java/social-api/pom.xml
incubator/shindig/trunk/pom.xml
Modified: incubator/shindig/trunk/java/social-api/pom.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/pom.xml?rev=678158&r1=678157&r2=678158&view=diff
==============================================================================
--- incubator/shindig/trunk/java/social-api/pom.xml (original)
+++ incubator/shindig/trunk/java/social-api/pom.xml Sat Jul 19 06:51:03 2008
@@ -60,12 +60,31 @@
<groupId>org.apache.shindig</groupId>
<artifactId>shindig-common</artifactId>
</dependency>
+ <!-- is this Ok, only used in test to load the features -->
+ <dependency>
+ <groupId>org.apache.shindig</groupId>
+ <artifactId>shindig-features</artifactId>
+ <scope>test</scope>
+ </dependency>
<!-- external depenencies -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</dependency>
+ <!-- the classifier prevents this working in dep management -->
+ <dependency>
+ <groupId>net.sf.json-lib</groupId>
+ <artifactId>json-lib</artifactId>
+ <version>2.2</version>
+ <classifier>jdk15</classifier>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>rhino</groupId>
+ <artifactId>js</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>com.google.code.guice</groupId>
<artifactId>guice</artifactId>
@@ -112,5 +131,10 @@
<artifactId>core</artifactId>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConversionException.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConversionException.java?rev=678158&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConversionException.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConversionException.java Sat Jul 19 06:51:03 2008
@@ -0,0 +1,43 @@
+/*
+ * 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.shindig.social.opensocial.util;
+
+/**
+ * Where a conversion exception happens in the Json Lib conversion, this
+ * exception is thrown.
+ */
+public class BeanJsonLibConversionException extends RuntimeException {
+
+ private static final long serialVersionUID = -8609384443448202372L;
+
+ public BeanJsonLibConversionException() {
+ }
+
+ public BeanJsonLibConversionException(String arg0) {
+ super(arg0);
+ }
+
+ public BeanJsonLibConversionException(Throwable arg0) {
+ super(arg0);
+ }
+
+ public BeanJsonLibConversionException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+}
Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConverter.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConverter.java?rev=678158&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConverter.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConverter.java Sat Jul 19 06:51:03 2008
@@ -0,0 +1,286 @@
+/*
+ * 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.shindig.social.opensocial.util;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.ezmorph.MorpherRegistry;
+import net.sf.json.JSONArray;
+import net.sf.json.JSONException;
+import net.sf.json.JSONObject;
+import net.sf.json.JsonConfig;
+import net.sf.json.processors.DefaultValueProcessor;
+import net.sf.json.util.EnumMorpher;
+import net.sf.json.util.JSONUtils;
+import net.sf.json.util.NewBeanInstanceStrategy;
+import net.sf.json.util.PropertyFilter;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.shindig.social.opensocial.model.Address;
+import org.apache.shindig.social.opensocial.model.Email;
+import org.apache.shindig.social.opensocial.model.Enum;
+import org.apache.shindig.social.opensocial.model.MediaItem;
+import org.apache.shindig.social.opensocial.model.Organization;
+import org.apache.shindig.social.opensocial.model.Phone;
+import org.apache.shindig.social.opensocial.model.Url;
+
+
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
+/**
+ *
+ */
+public class BeanJsonLibConverter implements BeanConverter {
+
+ protected static final Log log = LogFactory
+ .getLog(BeanJsonLibConverter.class);
+ private Injector injector;
+ private JsonConfig jsonConfig;
+ private boolean debugMode = false;
+
+ /*
+ * Register the Enum Morphers so that JSON -> Bean works correctly for enums.
+ */
+ static {
+ MorpherRegistry morpherRegistry = JSONUtils.getMorpherRegistry();
+ morpherRegistry.registerMorpher(new EnumMorpher(Address.Field.class));
+ morpherRegistry.registerMorpher(new EnumMorpher(Phone.Field.class));
+ morpherRegistry.registerMorpher(new EnumMorpher(Email.Field.class));
+ morpherRegistry.registerMorpher(new EnumMorpher(MediaItem.Field.class));
+ morpherRegistry.registerMorpher(new EnumMorpher(MediaItem.Type.class));
+ morpherRegistry.registerMorpher(new EnumMorpher(Enum.Drinker.class));
+ morpherRegistry.registerMorpher(new EnumMorpher(Enum.Field.class));
+ morpherRegistry.registerMorpher(new EnumMorpher(Enum.Gender.class));
+ morpherRegistry
+ .registerMorpher(new EnumMorpher(Enum.NetworkPresence.class));
+ morpherRegistry.registerMorpher(new EnumMorpher(Enum.Smoker.class));
+
+ morpherRegistry.registerMorpher(new JSONObjectToMapMorpher());
+ }
+
+ @Inject
+ public BeanJsonLibConverter(Injector injector) {
+ this.injector = injector;
+ createJsonConfig();
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T convertToObject(String string, final Class<T> rootBeanClass) {
+
+ if (string.startsWith("[")) {
+ JSONArray jsonArray = JSONArray.fromObject(string, jsonConfig);
+ if (debugMode) {
+ JSONLibConverterUtils.dumpJsonArray(jsonArray, " ");
+ }
+
+ if (rootBeanClass.isArray()) {
+ Class<?> componentType = rootBeanClass.getComponentType();
+ Object rootObject = injector.getInstance(componentType);
+ List<?> o = JSONArray.toList(jsonArray, rootObject, jsonConfig);
+ Object[] result = (Object[]) Array.newInstance(componentType, o.size());
+ for (int i = 0; i < o.size(); i++) {
+ result[i] = o.get(i);
+ }
+ return (T) result;
+
+ } else {
+ T rootObject = injector.getInstance(rootBeanClass);
+ Object o = JSONArray.toArray(jsonArray, rootObject, jsonConfig);
+ return (T) o;
+ }
+ } else {
+ JSONObject jsonObject = JSONObject.fromObject(string, jsonConfig);
+
+ if (debugMode) {
+ JSONLibConverterUtils.dumpJsonObject(jsonObject, " ");
+ }
+
+ T rootObject = injector.getInstance(rootBeanClass);
+ Object o = JSONObject.toBean(jsonObject, rootObject, jsonConfig);
+ return (T) o;
+
+ }
+ }
+
+ /**
+ * @return
+ */
+ private void createJsonConfig() {
+
+ jsonConfig = new JsonConfig();
+
+ /*
+ * This hook deals with the creation of new beans in the JSON -> Java Bean
+ * conversion
+ */
+ jsonConfig.setNewBeanInstanceStrategy(new NewBeanInstanceStrategy() {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object newInstance(Class beanClass, JSONObject jsonObject)
+ throws InstantiationException, IllegalAccessException,
+ SecurityException, NoSuchMethodException, InvocationTargetException {
+ if (beanClass != null) {
+ Object o = BeanJsonLibConverter.this.injector.getInstance(beanClass);
+ if (debugMode) {
+ log.info("Created Object " + o + " for " + beanClass + " with ["
+ + jsonObject + "]");
+ }
+ return o;
+ }
+ return DEFAULT.newInstance(beanClass, jsonObject);
+ }
+
+ });
+
+ /*
+ * We are expecting null for nulls
+ */
+ jsonConfig.registerDefaultValueProcessor(String.class,
+ new DefaultValueProcessor() {
+ @SuppressWarnings("unchecked")
+ public Object getDefaultValue(Class target) {
+ return null;
+ }
+ });
+
+ jsonConfig.setJsonPropertyFilter(new PropertyFilter() {
+
+ public boolean apply(Object source, String name, Object value) {
+ return filterProperty(source, name, value);
+ }
+
+ });
+
+ jsonConfig.setJavaPropertyFilter(new PropertyFilter() {
+
+ public boolean apply(Object source, String name, Object value) {
+ return filterProperty(source,name,value);
+ }
+
+ });
+
+ // the classMap deals with the basic json string to bean conversion
+
+ Map<String, Class<?>> classMap = new HashMap<String, Class<?>>();
+
+ /*
+ * mappings are required where there is a List of objects in the interface
+ * with no indication of what type the list should contain. At the moment,
+ * we are using 1 map for all json trees, as there is no conflict, but if
+ * there is a map could be selected on the basis of the root object. It
+ * would be better to do this with generics, but this is good enough and
+ * compact enough for the moment.
+ *
+ */
+ //
+ // activity
+ classMap.put("mediaItems", MediaItem.class);
+ // this may not be necessary
+ classMap.put("templateParams", Map.class);
+ // BodyType needs no mappings
+ // Message needs no mappings
+ // Name needs no mappings
+ // Organization needs no mappings
+ // Url needs no mappings
+ // Email needs no mappings
+ // Phone Needs no mappings
+ // Address Needs no mappings
+ // MediaItem needs no mappings
+
+ // Person map
+ classMap.put("addresses", Address.class);
+ classMap.put("phoneNumbers", Phone.class);
+ classMap.put("emails", Email.class);
+ classMap.put("mediaItems", MediaItem.class);
+ classMap.put("jobs", Organization.class);
+ classMap.put("schools", Organization.class);
+ classMap.put("urls", Url.class);
+ jsonConfig.setClassMap(classMap);
+
+ }
+
+ /**
+ * @param source
+ * @param name
+ * @param value
+ * @return
+ */
+ protected boolean filterProperty(Object source, String name, Object value) {
+ if ( value == null ) {
+ return true;
+ }
+ if ( value instanceof JSONArray ) {
+ JSONArray array = (JSONArray) value;
+ if ( array.size() == 0 ) {
+ return true;
+ }
+ }
+ if ( value instanceof JSONObject ) {
+ JSONObject object = (JSONObject) value;
+ if ( object.isNullObject() || object.isEmpty() ) {
+ return true;
+ }
+ }
+ if ( value instanceof Collection) {
+ Collection<?> collection = (Collection<?>) value;
+ if ( collection.size() == 0 ) {
+ return true;
+ }
+ }
+ if ( value instanceof Object[] ) {
+ Object[] oarray = (Object[]) value;
+ if ( oarray.length == 0 ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String convertToString(Object pojo) {
+
+ try {
+ JSONObject jsonObject = JSONObject.fromObject(pojo, jsonConfig);
+ return jsonObject.toString();
+ } catch (JSONException jse) {
+ Class<?> pojoClass = pojo.getClass();
+ if (JSONUtils.isArray(pojoClass)) {
+ JSONArray jsonArray = JSONArray.fromObject(pojo);
+ String result = jsonArray.toString();
+ return result;
+ }
+ throw jse;
+ }
+ }
+
+ /**
+ * @param string
+ * @param class1
+ */
+ public void addMapping(String key, Class<?> class1) {
+ jsonConfig.getClassMap().put(key, class1);
+ }
+
+}
Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/JSONLibConverterUtils.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/JSONLibConverterUtils.java?rev=678158&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/JSONLibConverterUtils.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/JSONLibConverterUtils.java Sat Jul 19 06:51:03 2008
@@ -0,0 +1,72 @@
+/*
+ * 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.shindig.social.opensocial.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
+/**
+ *
+ */
+public class JSONLibConverterUtils {
+ protected static final Log log = LogFactory
+ .getLog(JSONLibConverterUtils.class);
+
+
+ /**
+ * @param jsonObject
+ */
+ public static final void dumpJsonObject(JSONObject jsonObject, String indent) {
+ for (Object key : jsonObject.keySet()) {
+ Object value = jsonObject.get(key);
+ if (value instanceof JSONObject) {
+ log.info(indent + key + ":JSONObject");
+ dumpJsonObject((JSONObject) value, indent + " ");
+ } else if (value instanceof JSONArray) {
+ log.info(indent + key + ":JSONArray " + ((JSONArray) value).size());
+ dumpJsonArray((JSONArray) value, indent + " ");
+ } else {
+ log.info(indent + key + ":" + value + ":"
+ + (value == null ? "na" : value.getClass()));
+ }
+ }
+ }
+
+
+ /**
+ * @param value
+ * @param string
+ */
+ static void dumpJsonArray(JSONArray array, String indent) {
+ for (Object value : array) {
+ if (value instanceof JSONObject) {
+ log.info(indent + ":JSONObject");
+ dumpJsonObject((JSONObject) value, indent + " ");
+ } else if (value instanceof JSONArray) {
+ log.info(indent + ":JSONArray " + ((JSONArray) value).size());
+ dumpJsonArray((JSONArray) value, indent + " ");
+ } else {
+ log.info(indent + ":" + value + ":"
+ + (value == null ? "na" : value.getClass()));
+ }
+ }
+ }
+}
Added: incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/JSONObjectToMapMorpher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/JSONObjectToMapMorpher.java?rev=678158&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/JSONObjectToMapMorpher.java (added)
+++ incubator/shindig/trunk/java/social-api/src/main/java/org/apache/shindig/social/opensocial/util/JSONObjectToMapMorpher.java Sat Jul 19 06:51:03 2008
@@ -0,0 +1,50 @@
+/*
+ * 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.shindig.social.opensocial.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.ezmorph.Morpher;
+import net.sf.ezmorph.ObjectMorpher;
+import net.sf.json.JSONObject;
+
+/**
+ *
+ */
+public class JSONObjectToMapMorpher implements Morpher, ObjectMorpher {
+
+ public Class<?> morphsTo() {
+ return Map.class;
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean supports(Class clazz) {
+ return (JSONObject.class.equals(clazz));
+ }
+
+ public Object morph(Object bean) {
+ Map<Object, Object> result = new HashMap<Object, Object>();
+ JSONObject jsonObject = (JSONObject) bean;
+ for ( Object key : jsonObject.keySet()) {
+ result.put(key,jsonObject.get(key));
+ }
+ return result;
+ }
+
+}
Added: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/JsonLibTestsGuiceModule.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/JsonLibTestsGuiceModule.java?rev=678158&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/JsonLibTestsGuiceModule.java (added)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/JsonLibTestsGuiceModule.java Sat Jul 19 06:51:03 2008
@@ -0,0 +1,40 @@
+/*
+ * 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.shindig.social;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.inject.AbstractModule;
+
+/**
+ * Provides social api component injection for all large tests
+ */
+public class JsonLibTestsGuiceModule extends AbstractModule {
+ @Override
+ protected void configure() {
+
+ bind(Map.class).to(HashMap.class);
+ bind(List.class).to(ArrayList.class);
+ bind(Map[].class).to(HashMap[].class);
+ }
+
+}
Added: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidator.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidator.java?rev=678158&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidator.java (added)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidator.java Sat Jul 19 06:51:03 2008
@@ -0,0 +1,352 @@
+/*
+ * 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.shindig.social.opensocial.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.EvaluatorException;
+import org.mozilla.javascript.Script;
+import org.mozilla.javascript.ScriptableObject;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * A class that loads a feature set from features into a Javascript Parser to
+ * make the model available to validate JSON messages against.
+ */
+public class APIValidator {
+
+ private static final Log log = LogFactory.getLog(APIValidator.class);
+ private Context ctx;
+ private ScriptableObject scope;
+
+ /**
+ * @param feature
+ * The name of the feature are eg "opensocial-reference", this
+ * is a classpath stub (not starting with /) where the location
+ * contains a feature.xml file.
+ * @throws SAXException
+ * if feature.xml is not parsable
+ * @throws ParserConfigurationException
+ * if the parsers are invalid
+ * @throws IOException
+ * if feature.xml or the javascript that represents the
+ * feature is missing
+ *
+ */
+ public APIValidator(String feature) throws IOException,
+ ParserConfigurationException, SAXException {
+ ctx = Context.enter();
+ scope = ctx.initStandardObjects();
+ load(feature);
+ }
+
+ /**
+ * @param json
+ * The json to validate expected in a form { xyz: yyy } form
+ * @param object
+ * The json Fields object specifying the structure of the json
+ * object, each field in this object contains the name of the
+ * json field in the json structure.
+ * @param optionalFields
+ * If any of the fields that appear in the json structure are
+ * optional, then they should be defined in this parameter.
+ * @param nullfields
+ * @throws APIValidatorExpcetion
+ * if there is a problem validating the json
+ * @return a map so string object pairs containing the fields at the top level
+ * of the json tree. Where these are native java objects, they will
+ * appear as native object. Complex json objects will appear as Rhino
+ * specific objects
+ */
+ public Map<String, Object> validate(String json, String object,
+ String[] optionalFields, String[] nullfields)
+ throws APIValidatorExpcetion {
+
+ /*
+ * Object[] ids = ScriptableObject.getPropertyIds(scope); for (Object id :
+ * ids) { Object o = ScriptableObject.getProperty(scope,
+ * String.valueOf(id)); log.debug("ID is " + id + " class " + id.getClass() + "
+ * is " + o); if (o instanceof ScriptableObject) {
+ * listScriptable(String.valueOf(id), (ScriptableObject) o); } }
+ */
+
+ log.debug("Loading " + json);
+ json = json.trim();
+ if (!json.endsWith("}")) {
+ json = json + "}";
+ }
+ if (!json.startsWith("{")) {
+ json = "{" + json;
+ }
+ json = "( testingObject = " + json + " )";
+
+ Object so = null;
+ try {
+ so = ctx.evaluateString(scope, json, "test json", 0, null);
+ } catch (EvaluatorException ex) {
+ log.error("Non parseable JSON " + json);
+ }
+ log.debug("Loaded " + so);
+
+ return validateOject(so, object, optionalFields, nullfields);
+
+ }
+
+ /**
+ * Validate an JSON Object extracted
+ *
+ * @param object
+ * @param string
+ * @param optional
+ * @return
+ * @throws APIValidatorExpcetion
+ */
+ public Map<String, Object> validateOject(Object jsonObject, String object,
+ String[] optionalFields, String[] nullFields)
+ throws APIValidatorExpcetion {
+ Map<String, String> optional = new HashMap<String, String>();
+ for (String opt : optionalFields) {
+ optional.put(opt, opt);
+ }
+ Map<String, String> nullf = new HashMap<String, String>();
+ for (String nf : nullFields) {
+ nullf.put(nf, nf);
+ }
+
+ ScriptableObject specification = getScriptableObject(object);
+ log.debug("Looking for " + object + " found " + specification);
+ listScriptable(object, specification);
+
+ Map<String, Object> resultFields = new HashMap<String, Object>();
+
+ if (jsonObject instanceof ScriptableObject) {
+ ScriptableObject parsedJSONObject = (ScriptableObject) jsonObject;
+ listScriptable("testingObject", parsedJSONObject);
+ Object[] fields = specification.getIds();
+ for (Object f : fields) {
+ Object fieldName = specification.get(String.valueOf(f), specification);
+ Object o = parsedJSONObject.get(String.valueOf(fieldName),
+ parsedJSONObject);
+ if (o == ScriptableObject.NOT_FOUND) {
+ if (optional.containsKey(fieldName)) {
+ log.warn("Missing Optional Field " + fieldName);
+ } else if (!nullf.containsKey(fieldName)) {
+ log.error("Missing Field " + fieldName);
+ throw new APIValidatorExpcetion("Missing Field " + fieldName);
+ }
+ } else {
+ if (nullf.containsKey(fieldName)) {
+ log.error("Field should have been null and was not");
+ }
+ if (o == null) {
+ if (nullf.containsKey(fieldName)) {
+ log.error("Null Fields has been serialized " + fieldName);
+ }
+ log.debug("Got a Null object for Field " + f + ":" + fieldName
+ + " on json [[" + jsonObject + "]]");
+
+ } else {
+
+ log.debug("Got JSON Field Field," + f + ":" + fieldName + " as "
+ + o + " " + o.getClass());
+ }
+ resultFields.put(String.valueOf(fieldName), o);
+ }
+ }
+
+ } else {
+ throw new APIValidatorExpcetion(
+ "Parsing JSON resulted in invalid Javascript object, which was "
+ + jsonObject + " JSON was [[" + jsonObject + "]]");
+ }
+ return resultFields;
+ }
+
+ /**
+ * get an object from the json context and scope.
+ *
+ * @param object
+ * the name of the object specified as a path from the base
+ * object
+ * @return the json object
+ */
+ private ScriptableObject getScriptableObject(String object) {
+ String[] path = object.split("\\.");
+ log.debug("Looking up " + object + " elements " + path.length);
+
+ ScriptableObject s = scope;
+ for (String pe : path) {
+ log.debug("Looking up " + pe + " in " + s);
+ s = (ScriptableObject) s.get(pe, s);
+ log.debug("Looking for " + pe + " in found " + s);
+ }
+ return s;
+ }
+
+ /**
+ * List a scriptable object at log debug level, constructors will not be
+ * expanded as this loads to recursion.
+ *
+ * @param id
+ * The name of the object
+ * @param scriptableObject
+ * the scriptable Object
+ */
+ private void listScriptable(String id, ScriptableObject scriptableObject) {
+ log.debug("ID is Scriptable " + id);
+ if (!id.endsWith("constructor")) {
+ Object[] allIDs = scriptableObject.getAllIds();
+ for (Object oid : allIDs) {
+ log.debug(id + "." + oid);
+ Object o = scriptableObject.get(String.valueOf(oid), scriptableObject);
+ if (o instanceof ScriptableObject) {
+ listScriptable(id + "." + String.valueOf(oid), (ScriptableObject) o);
+ }
+ }
+ }
+ }
+
+ /**
+ * Load a feature based on the spec
+ *
+ * @param spec
+ * The name of the location of the spec in the classpath, must
+ * not start with a '/' and must should contain a feature.xml
+ * file in the location
+ * @throws IOException
+ * If any of the resources cant be found
+ * @throws ParserConfigurationException
+ * If the parser has a problem being constructed
+ * @throws SAXException
+ * on a parse error on the features.xml
+ */
+ private void load(String spec) throws IOException, SAXException,
+ ParserConfigurationException {
+
+ List<String> scripts = getScripts(spec);
+
+ List<Script> compiled = new ArrayList<Script>();
+ for (String script : scripts) {
+ String scriptPath = spec + "/" + script;
+ InputStream in = this.getClass().getClassLoader().getResourceAsStream(
+ scriptPath);
+ if (in == null) {
+ in = this.getClass().getClassLoader().getResourceAsStream(
+ "features/" + scriptPath);
+ if (in == null) {
+ throw new IOException("Cant load spec " + spec + " or features/"+spec+" from classpath");
+ }
+ }
+ InputStreamReader reader = new InputStreamReader(in);
+ Script compiledScript = ctx.compileReader(reader, spec, 0, null);
+ compiled.add(compiledScript);
+ }
+
+ for (Script compiledScript : compiled) {
+ compiledScript.exec(ctx, scope);
+ }
+
+ }
+
+ /**
+ * Add some javascript to the context, and execute it. If extra custom
+ * javascript is wanted in the context or scope then this method will load it.
+ *
+ * @param javascript
+ */
+ public void addScript(String javascript) {
+ Script compileScript = ctx.compileString(javascript, "AdditionalJS", 0,
+ null);
+ compileScript.exec(ctx, scope);
+ }
+
+ /**
+ * Get an ordered list of javascript resources from a feature sets.
+ *
+ * @param spec
+ * The spec location
+ * @return An ordered list of javascript resources, these are relative to
+ * specification file.
+ * @throws IOException
+ * If any of the resources can't be loaded.
+ * @throws SAXException
+ * Where the feature.xml file is not parsable
+ * @throws ParserConfigurationException
+ * where the parser can't be constructed.
+ * @return An ordered list of script that need to be loaded and executed to
+ * make the feature available in the context.
+ */
+ private List<String> getScripts(String spec) throws SAXException,
+ IOException, ParserConfigurationException {
+ String features = spec + "/feature.xml";
+ InputStream in = this.getClass().getClassLoader().getResourceAsStream(
+ features);
+ if (in == null) {
+ in = this.getClass().getClassLoader().getResourceAsStream(
+ "features/"+features);
+ if (in == null) {
+ throw new IOException("Cant find " + features + " or features/" + features+ " in classpath ");
+ }
+ }
+ DocumentBuilderFactory builderFactory = DocumentBuilderFactory
+ .newInstance();
+ DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
+ Document doc = documentBuilder.parse(in);
+ NodeList nl = doc.getElementsByTagName("script");
+ List<String> scripts = new ArrayList<String>();
+ for (int i = 0; i < nl.getLength(); i++) {
+ Node scriptNode = nl.item(i);
+ NamedNodeMap attributes = scriptNode.getAttributes();
+ Node scriptAttr = attributes.getNamedItem("src");
+ String script = scriptAttr.getNodeValue();
+ scripts.add(script);
+ }
+ return scripts;
+ }
+
+ /**
+ * @param nameJSON
+ */
+ public static void dump(Map<?, ?> nameJSON) {
+ if (log.isDebugEnabled()) {
+ for (Object k : nameJSON.keySet()) {
+ Object o = nameJSON.get(k);
+ log.info("Key [" + k + "] value:["
+ + (o == null ? o : o + ":" + o.getClass()) + "]");
+ }
+ }
+ }
+
+}
Added: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidatorExpcetion.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidatorExpcetion.java?rev=678158&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidatorExpcetion.java (added)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidatorExpcetion.java Sat Jul 19 06:51:03 2008
@@ -0,0 +1,42 @@
+/*
+ * 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.shindig.social.opensocial.util;
+
+/**
+ * Thrown when there is a validation exception on one of the apis
+ */
+public class APIValidatorExpcetion extends Exception {
+
+ private static final long serialVersionUID = -8969858718669454612L;
+
+ public APIValidatorExpcetion() {
+ }
+
+ public APIValidatorExpcetion(String message) {
+ super(message);
+ }
+
+ public APIValidatorExpcetion(Throwable cause) {
+ super(cause);
+ }
+
+ public APIValidatorExpcetion(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
Added: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidatorTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidatorTest.java?rev=678158&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidatorTest.java (added)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/APIValidatorTest.java Sat Jul 19 06:51:03 2008
@@ -0,0 +1,89 @@
+/*
+ * 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.shindig.social.opensocial.util;
+
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.xml.sax.SAXException;
+
+/**
+ * Test the api validator to make certain it behaves as is expected.
+ */
+public class APIValidatorTest {
+
+ /**
+ * A definition of the test json used in this unit test.
+ */
+ private static final String TEST_DEFINITION =
+ "var TestDef = {}; TestDef.Field = { FIELD1 : \"json\", FIELD2 : \"xyz\", FIELD3 : \"shouldBeMissing\" };";
+
+ /**
+ * test the validator for successful validation
+ * @throws APIValidatorExpcetion
+ * @throws IOException
+ * @throws ParserConfigurationException
+ * @throws SAXException
+ */
+ @Test
+ public void testValidator() throws APIValidatorExpcetion, IOException, ParserConfigurationException, SAXException {
+ APIValidator apiVal = new APIValidator("opensocial-reference");
+ apiVal.addScript(TEST_DEFINITION);
+ String[] optional = {"shouldBeMissing"};
+ String[] nullfields = {};
+ Map<String, Object> result = apiVal.validate("{ json: \"A Test JSON\", xyz : 123 }", "TestDef.Field", optional, nullfields );
+ Assert.assertNotNull(result);
+ Assert.assertNotNull(result.get("json"));
+ Assert.assertNotNull(result.get("xyz"));
+ Assert.assertEquals(String.class,result.get("json").getClass());
+ Assert.assertEquals(Integer.class,result.get("xyz").getClass());
+ Assert.assertEquals("A Test JSON",result.get("json"));
+ Assert.assertEquals(123,((Integer)result.get("xyz")).intValue());
+
+
+ }
+
+ /**
+ * Test for a failing validation
+ * @throws APIValidatorExpcetion
+ * @throws IOException
+ * @throws ParserConfigurationException
+ * @throws SAXException
+ */
+ @Test
+ public void testValidatorFail() throws APIValidatorExpcetion, IOException, ParserConfigurationException, SAXException {
+ APIValidator apiVal = new APIValidator("opensocial-reference");
+ apiVal.addScript(TEST_DEFINITION);
+ String[] optional = {};
+ String[] nullfields = {};
+ try {
+ apiVal.validate("{ jsonIsMissing: \"A Test JSON\", xyz : 123 }", "TestDef.Field", optional, nullfields );
+ Assert.fail("Should have Generated an APIValidatorException ");
+ } catch ( APIValidatorExpcetion ex ) {
+
+ }
+
+
+ }
+
+}
Added: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConverterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConverterTest.java?rev=678158&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConverterTest.java (added)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/BeanJsonLibConverterTest.java Sat Jul 19 06:51:03 2008
@@ -0,0 +1,359 @@
+/*
+ * 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.shindig.social.opensocial.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.shindig.social.JsonLibTestsGuiceModule;
+import org.apache.shindig.social.opensocial.model.Activity;
+import org.apache.shindig.social.opensocial.model.ActivityImpl;
+import org.apache.shindig.social.opensocial.model.Address;
+import org.apache.shindig.social.opensocial.model.AddressImpl;
+import org.apache.shindig.social.opensocial.model.Email;
+import org.apache.shindig.social.opensocial.model.EmailImpl;
+import org.apache.shindig.social.opensocial.model.MediaItem;
+import org.apache.shindig.social.opensocial.model.MediaItemImpl;
+import org.apache.shindig.social.opensocial.model.Name;
+import org.apache.shindig.social.opensocial.model.NameImpl;
+import org.apache.shindig.social.opensocial.model.Person;
+import org.apache.shindig.social.opensocial.model.PersonImpl;
+import org.apache.shindig.social.opensocial.model.Phone;
+import org.apache.shindig.social.opensocial.model.PhoneImpl;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.inject.Guice;
+
+public class BeanJsonLibConverterTest extends TestCase {
+
+ private static final Log log = LogFactory
+ .getLog(BeanJsonLibConverterTest.class);
+ private Person johnDoe;
+ private Activity activity;
+
+ private BeanJsonLibConverter beanJsonConverter;
+ private APIValidator apiValidator;
+ // set to true to get loging output at info level
+ private boolean outputInfo = false;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ johnDoe = new PersonImpl("johnDoeId", new NameImpl("John Doe"));
+ johnDoe.setPhoneNumbers(Lists.<Phone> newArrayList(new PhoneImpl(
+ "+33H000000000", "home"), new PhoneImpl("+33M000000000", "mobile"),
+ new PhoneImpl("+33W000000000", "work")));
+
+ johnDoe.setAddresses(Lists.<Address> newArrayList(new AddressImpl(
+ "My home address")));
+
+ johnDoe.setEmails(Lists.<Email> newArrayList(new EmailImpl(
+ "john.doe@work.bar", "work"),
+ new EmailImpl("john.doe@home.bar", "home")));
+
+ activity = new ActivityImpl("activityId", johnDoe.getId());
+
+ activity.setMediaItems(Lists.<MediaItem> newArrayList(new MediaItemImpl(
+ "image/jpg", MediaItem.Type.IMAGE, "http://foo.bar")));
+
+ beanJsonConverter = new BeanJsonLibConverter(Guice
+ .createInjector(new JsonLibTestsGuiceModule()));
+
+ apiValidator = new APIValidator("opensocial-reference");
+
+ }
+
+ public static class SpecialPerson extends PersonImpl {
+ public static final String[] OPTIONALFIELDS = {};
+ public static final String[] NULLFIELDS = {"jobInterests","nickname","romance","religion","timeZone",
+ "relationshipStatus","tags","networkPresence","books","quotes","phoneNumbers","languagesSpoken",
+ "activities","jobs","dateOfBirth","profileVideo","bodyType","urls","schools","music","addresses",
+ "livingArrangement","thumbnailUrl","humor","sports","scaredOf","movies","age","pets","hasApp","turnOffs",
+ "gender","fashion","drinker","aboutMe","children","sexualOrientation","heroes","profileSong","lookingFor",
+ "cars","turnOns","tvShows","profileUrl","status","currentLocation","smoker","happiestWhen","ethnicity",
+ "food","emails","politicalViews","interests","familyName","honorificSuffix","additionalName","honorificPrefix","givenName"};
+
+ private String newfield;
+
+ public SpecialPerson() {
+ super();
+ }
+
+ public SpecialPerson(String id, String name, String newfield) {
+ super(id, new NameImpl(name));
+ this.newfield = newfield;
+ }
+
+ public String getNewfield() {
+ return newfield;
+ }
+
+ public void setNewfield(String newfield) {
+ this.newfield = newfield;
+ }
+
+ }
+
+ public void testToJsonOnInheritedClass() throws Exception {
+ SpecialPerson cassie = new SpecialPerson("5", "robot", "nonsense");
+
+ String result = beanJsonConverter.convertToString(cassie);
+
+ validatePerson(result, "5", "robot", SpecialPerson.OPTIONALFIELDS, SpecialPerson.NULLFIELDS);
+
+ apiValidator.addScript(" specialPerson = { SPECIAL : \"newfield\" }; ");
+ String[] optional = {};
+ String[] nullfields = {};
+ Map<String, Object> special = apiValidator.validate(result,
+ "specialPerson", optional,nullfields);
+ assertNotNull(special.get("newfield"));
+ assertEquals(String.class, special.get("newfield").getClass());
+ assertEquals("nonsense", special.get("newfield"));
+
+ // convert back into an object Tree
+
+ SpecialPerson parseCassie = beanJsonConverter.convertToObject(result,
+ SpecialPerson.class);
+
+ assertNotNull(parseCassie);
+ assertEquals(cassie.getId(), parseCassie.getId());
+ assertEquals(cassie.getNewfield(), parseCassie.getNewfield());
+
+ Name name = parseCassie.getName();
+ Name cassieName = cassie.getName();
+ assertNotNull(name);
+ assertEquals(cassieName.getUnstructured(), name.getUnstructured());
+ assertEquals(cassieName.getAdditionalName(), name.getAdditionalName());
+ assertEquals(cassieName.getFamilyName(), name.getFamilyName());
+ assertEquals(cassieName.getGivenName(), name.getGivenName());
+ assertEquals(cassieName.getHonorificPrefix(), name.getHonorificPrefix());
+ assertEquals(cassieName.getHonorificSuffix(), name.getHonorificSuffix());
+
+ }
+
+ /**
+ * @param result
+ * @throws APIValidatorExpcetion
+ */
+ private void validatePerson(String result, String id, String name, String[] optional, String[] nullfields)
+ throws APIValidatorExpcetion {
+
+ Map<String, Object> standard = apiValidator.validate(result,
+ "opensocial.Person.Field", optional,nullfields);
+ assertNotNull(standard.get("id"));
+ assertEquals(String.class, standard.get("id").getClass());
+ assertEquals(id, standard.get("id"));
+
+ assertNotNull(standard.get("name"));
+ Map<String, Object> nameJSON = apiValidator.validateOject(standard
+ .get("name"), "opensocial.Name.Field", optional,nullfields);
+ APIValidator.dump(nameJSON);
+
+ assertNotNull(nameJSON.get("unstructured"));
+ assertEquals(String.class, nameJSON.get("unstructured").getClass());
+ assertEquals(name, nameJSON.get("unstructured"));
+
+ // additional name
+ assertNull(nameJSON.get("additionalName"));
+
+ }
+
+ public void testPersonToJson() throws Exception {
+ String result = beanJsonConverter.convertToString(johnDoe);
+ if (outputInfo) {
+ log.info("JSON (" + result + ")");
+ }
+ Person parsedPerson = beanJsonConverter.convertToObject(result,
+ Person.class);
+
+ assertEquals(johnDoe.getId(), parsedPerson.getId());
+ assertEquals(johnDoe.getName().getUnstructured(), parsedPerson.getName()
+ .getUnstructured());
+
+ List<Address> addresses = parsedPerson.getAddresses();
+ if (outputInfo) {
+ for (Object o : addresses) {
+ log.info("Address " + o);
+ }
+ }
+
+ assertEquals(1, addresses.size());
+ Address address = addresses.get(0);
+ String unstructured = address.getUnstructuredAddress();
+
+ assertNotNull(unstructured);
+ assertEquals(johnDoe.getAddresses().get(0).getUnstructuredAddress(),
+ parsedPerson.getAddresses().get(0).getUnstructuredAddress());
+
+ assertEquals(3, parsedPerson.getPhoneNumbers().size());
+
+ for (int i = 0; i < johnDoe.getPhoneNumbers().size(); i++) {
+ Phone expectedPhone = johnDoe.getPhoneNumbers().get(i);
+ Phone actualPhone = parsedPerson.getPhoneNumbers().get(i);
+ assertEquals(expectedPhone.getType(), actualPhone.getType());
+ assertEquals(expectedPhone.getNumber(), actualPhone.getNumber());
+ }
+
+ assertEquals(2, parsedPerson.getEmails().size());
+
+ for (int i = 0; i < johnDoe.getEmails().size(); i++) {
+ Email expectedEmail = johnDoe.getEmails().get(i);
+ Email actualEmail = parsedPerson.getEmails().get(i);
+ assertEquals(expectedEmail.getType(), actualEmail.getType());
+ assertEquals(expectedEmail.getAddress(), actualEmail.getAddress());
+ }
+ }
+
+ public void testActivityToJson() throws Exception {
+
+ String result = beanJsonConverter.convertToString(activity);
+ if (outputInfo) {
+ log.info("JSON (" + result + ")");
+ }
+ Activity parsedActivity = beanJsonConverter.convertToObject(result,
+ Activity.class);
+ assertEquals(activity.getUserId(), parsedActivity.getUserId());
+ assertEquals(activity.getId(), parsedActivity.getId());
+
+ assertEquals(1, parsedActivity.getMediaItems().size());
+
+ MediaItem expectedItem = activity.getMediaItems().get(0);
+ MediaItem actualItem = parsedActivity.getMediaItems().get(0);
+
+ assertEquals(expectedItem.getUrl(), actualItem.getUrl());
+ assertEquals(expectedItem.getMimeType(), actualItem.getMimeType());
+ assertEquals(expectedItem.getType().toString(), actualItem.getType()
+ .toString());
+ }
+
+ public void testMapsToJson() throws Exception {
+ Map<String, Map<String, String>> map = Maps.newHashMap();
+
+ Map<String, String> item1Map = Maps.newHashMap();
+ item1Map.put("value", "1");
+
+ // Null values shouldn't cause exceptions
+ item1Map.put("value2", null);
+ map.put("item1", item1Map);
+
+ Map<String, String> item2Map = Maps.newHashMap();
+ item2Map.put("value", "2");
+ map.put("item2", item2Map);
+
+ String result = beanJsonConverter.convertToString(map);
+ if (outputInfo) {
+ log.info("JSON (" + result + ")");
+ }
+ // there is introspection that can tell jsonobject -> bean converter what a
+ // map should contain, so we have to tell it
+ beanJsonConverter.addMapping("item1", Map.class);
+ beanJsonConverter.addMapping("item2", Map.class);
+ Map<?, ?> parsedMap = beanJsonConverter
+ .convertToObject(result, Map.class);
+
+ if (outputInfo) {
+ log.info("Dumping Map (" + parsedMap + ")");
+ }
+ APIValidator.dump(parsedMap);
+
+ assertEquals("1", ((Map<?,?>)parsedMap.get("item1")).get("value"));
+ assertEquals("2", ((Map<?,?>)parsedMap.get("item2")).get("value"));
+ }
+
+ public void testListsToJson() throws Exception {
+ Map<String, String> item1Map = Maps.newHashMap();
+ item1Map.put("value", "1");
+
+ Map<String, String> item2Map = Maps.newHashMap();
+ item2Map.put("value", "2");
+
+ // put the list into a container before serializing, top level lists dont
+ // appear
+ // to be allowed in json
+ // just check that the list is in the holder correctly
+ List<Map<String, String>> list = new ArrayList<Map<String, String>>();
+ list.add(item1Map);
+ list.add(item2Map);
+ String result = beanJsonConverter.convertToString(list);
+ if (outputInfo) {
+ log.info("JSON (" + result + ")");
+ }
+ Map<?, ?>[] parsedList = beanJsonConverter.convertToObject(
+ result, Map[].class);
+
+ assertEquals("1", parsedList[0].get("value"));
+ assertEquals("2", parsedList[1].get("value"));
+ }
+
+ public void testArrayToJson() throws Exception {
+ String[] colors = { "blue", "green", "aquamarine" };
+ String result = beanJsonConverter.convertToString(colors);
+ if (outputInfo) {
+ log.info("JSON (" + result + ")");
+ }
+ String[] parsedColors = beanJsonConverter.convertToObject(result,
+ String[].class);
+ assertEquals(colors.length, parsedColors.length);
+ assertEquals(colors[0], parsedColors[0]);
+ assertEquals(colors[1], parsedColors[1]);
+ assertEquals(colors[2], parsedColors[2]);
+ }
+
+ public void testJsonToActivity() throws Exception {
+ String jsonActivity = "{userId : 5, id : 6, mediaItems : ["
+ + "{url : 'hello', mimeType : 'mimey', type : 'VIDEO'}" + "]}";
+ Activity result = beanJsonConverter.convertToObject(jsonActivity,
+ Activity.class);
+
+ assertEquals("5", result.getUserId());
+ assertEquals("6", result.getId());
+
+ assertEquals(1, result.getMediaItems().size());
+
+ MediaItem actualItem = result.getMediaItems().get(0);
+
+ assertEquals("hello", actualItem.getUrl());
+ assertEquals("mimey", actualItem.getMimeType());
+ assertEquals("video", actualItem.getType().toString());
+ }
+
+ public void testJsonToMap() throws Exception {
+ String jsonActivity = "{count : 0, favoriteColor : 'yellow'}";
+ Map<String, String> data = Maps.newHashMap();
+ data = beanJsonConverter.convertToObject(jsonActivity,
+ (Class<Map<String, String>>) data.getClass());
+
+ assertEquals(2, data.size());
+
+ for (String key : data.keySet()) {
+ Object value = data.get(key);
+ if (key.equals("count")) {
+ assertEquals(0, value);
+ } else if (key.equals("favoriteColor")) {
+ assertEquals("yellow", value);
+ }
+ }
+ }
+
+}
Added: incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/JsonConverterPerformancePerf.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/JsonConverterPerformancePerf.java?rev=678158&view=auto
==============================================================================
--- incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/JsonConverterPerformancePerf.java (added)
+++ incubator/shindig/trunk/java/social-api/src/test/java/org/apache/shindig/social/opensocial/util/JsonConverterPerformancePerf.java Sat Jul 19 06:51:03 2008
@@ -0,0 +1,271 @@
+/*
+ * 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.shindig.social.opensocial.util;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.shindig.social.JsonLibTestsGuiceModule;
+import org.apache.shindig.social.SocialApiTestsGuiceModule;
+import org.apache.shindig.social.opensocial.model.Activity;
+import org.apache.shindig.social.opensocial.model.ActivityImpl;
+import org.apache.shindig.social.opensocial.model.Address;
+import org.apache.shindig.social.opensocial.model.AddressImpl;
+import org.apache.shindig.social.opensocial.model.Email;
+import org.apache.shindig.social.opensocial.model.EmailImpl;
+import org.apache.shindig.social.opensocial.model.MediaItem;
+import org.apache.shindig.social.opensocial.model.MediaItemImpl;
+import org.apache.shindig.social.opensocial.model.NameImpl;
+import org.apache.shindig.social.opensocial.model.Person;
+import org.apache.shindig.social.opensocial.model.PersonImpl;
+import org.apache.shindig.social.opensocial.model.Phone;
+import org.apache.shindig.social.opensocial.model.PhoneImpl;
+import org.json.JSONObject;
+
+import com.google.common.collect.Lists;
+import com.google.inject.Guice;
+
+public class JsonConverterPerformancePerf extends TestCase {
+
+ private static final Log log = LogFactory
+ .getLog(JsonConverterPerformancePerf.class);
+ private static final int TEST_SIZE = 10000;
+ private Person johnDoe;
+ private Activity activity;
+
+ private BeanJsonLibConverter beanJsonLibConverter;
+ private APIValidator apiValidator;
+ // set to true to get loging output at info level
+ private boolean outputInfo = false;
+ private BeanJsonConverter beanJsonConverter;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ johnDoe = new PersonImpl("johnDoeId", new NameImpl("John Doe"));
+ johnDoe.setPhoneNumbers(Lists.<Phone> newArrayList(new PhoneImpl(
+ "+33H000000000", "home"), new PhoneImpl("+33M000000000", "mobile"),
+ new PhoneImpl("+33W000000000", "work")));
+
+ johnDoe.setAddresses(Lists.<Address> newArrayList(new AddressImpl(
+ "My home address")));
+
+ johnDoe.setEmails(Lists.<Email> newArrayList(new EmailImpl(
+ "john.doe@work.bar", "work"),
+ new EmailImpl("john.doe@home.bar", "home")));
+
+ activity = new ActivityImpl("activityId", johnDoe.getId());
+
+ activity.setMediaItems(Lists.<MediaItem> newArrayList(new MediaItemImpl(
+ "image/jpg", MediaItem.Type.IMAGE, "http://foo.bar")));
+
+ beanJsonLibConverter = new BeanJsonLibConverter(Guice
+ .createInjector(new JsonLibTestsGuiceModule()));
+
+ beanJsonConverter = new BeanJsonConverter(Guice
+ .createInjector(new SocialApiTestsGuiceModule()));
+
+ apiValidator = new APIValidator("opensocial-reference");
+
+ }
+
+ public static class SpecialPerson extends PersonImpl {
+ private String newfield;
+
+ public SpecialPerson() {
+ super();
+ }
+
+ public SpecialPerson(String id, String name, String newfield) {
+ super(id, new NameImpl(name));
+ this.newfield = newfield;
+ }
+
+ public String getNewfield() {
+ return newfield;
+ }
+
+ public void setNewfield(String newfield) {
+ this.newfield = newfield;
+ }
+
+ }
+
+ public void testToJsonLibOnInheritedClassOutput() throws Exception {
+ SpecialPerson[] spa = new SpecialPerson[TEST_SIZE];
+ for (int i = 0; i < TEST_SIZE; i++) {
+ spa[i] = new SpecialPerson(String.valueOf(i), "robot", "nonsense");
+ }
+ Runtime r = Runtime.getRuntime();
+ r.gc();
+ long memstart = r.totalMemory()-r.freeMemory();
+ long startOutput = System.currentTimeMillis();
+ String[] output = new String[TEST_SIZE];
+ for (int i = 0; i < TEST_SIZE; i++) {
+ output[i] = beanJsonLibConverter.convertToString(spa[i]);
+ }
+ long endOutput = System.currentTimeMillis();
+ long memend = r.totalMemory()-r.freeMemory();
+
+ String[] serializeOutput = new String[TEST_SIZE];
+ char[] source = output[0].toCharArray();
+ r.gc();
+
+ long stringsizeStart = r.totalMemory()-r.freeMemory();
+ for (int i = 0; i < TEST_SIZE; i++) {
+ serializeOutput[i] = new String(source);
+ }
+ long stringsizeEnd = r.totalMemory()-r.freeMemory();
+
+ /*
+ * Output the time per conversion and the memory usage - the output per
+ * conversion.
+ *
+ */
+
+ log.info("SF JSON Lib Output "
+ + average(startOutput, endOutput, TEST_SIZE)
+ + " ms/conversion, "
+ + (average(memstart, memend, TEST_SIZE)-average(stringsizeStart, stringsizeEnd, TEST_SIZE))
+ + " heap bytes/conversion, output packet consumed on average "
+ + average(stringsizeStart, stringsizeEnd, TEST_SIZE)+" for a string length of "+output[0].length());
+ log.info("Output Was ["+output[0]+"]");
+ }
+
+ public void testToJsonLibOnInheritedClassInput() throws Exception {
+ SpecialPerson[] spa = new SpecialPerson[TEST_SIZE];
+ SpecialPerson[] sparesult = new SpecialPerson[TEST_SIZE];
+ Runtime r = Runtime.getRuntime();
+ r.gc();
+ long personStart = r.totalMemory()-r.freeMemory();
+ for (int i = 0; i < TEST_SIZE; i++) {
+ spa[i] = new SpecialPerson(String.valueOf(i), "robot", "nonsense");
+ }
+ long personEnd = r.totalMemory()-r.freeMemory();
+
+ String[] serializeOutput = new String[TEST_SIZE];
+ r.gc();
+ for (int i = 0; i < TEST_SIZE; i++) {
+
+ serializeOutput[i] = beanJsonLibConverter.convertToString(spa[i]);
+ }
+
+ r.gc();
+ long memstart = r.totalMemory()-r.freeMemory();
+ long startInput = System.currentTimeMillis();
+ for (int i = 0; i < TEST_SIZE; i++) {
+ sparesult[i] = beanJsonLibConverter.convertToObject(
+ serializeOutput[i], SpecialPerson.class);
+ }
+ long endInput = System.currentTimeMillis();
+ long memend = r.totalMemory()-r.freeMemory();
+
+ log.info("SF JSON Lib Input "
+ + average(startInput, endInput, TEST_SIZE)
+ + " ms/conversion, "
+ + (average(memstart, memend, TEST_SIZE)-average(personStart, personEnd, TEST_SIZE))
+ + " heap bytes/conversion, person object consumed on average "
+ + average(personStart, personEnd, TEST_SIZE));
+ }
+
+ public void testToJsonOnInheritedClassOutput() throws Exception {
+ SpecialPerson[] spa = new SpecialPerson[TEST_SIZE];
+ for (int i = 0; i < TEST_SIZE; i++) {
+ spa[i] = new SpecialPerson(String.valueOf(i), "robot", "nonsense");
+ }
+ Runtime r = Runtime.getRuntime();
+ String[] output = new String[TEST_SIZE];
+ r.gc();
+ long memstart = r.totalMemory()-r.freeMemory();
+ long startOutput = System.currentTimeMillis();
+ for (int i = 0; i < TEST_SIZE; i++) {
+ output[i] = ((JSONObject) beanJsonConverter.convertToJson(spa[i])).toString();
+ }
+ long endOutput = System.currentTimeMillis();
+ long memend = r.totalMemory()-r.freeMemory();
+ String[] serializeOutput = new String[TEST_SIZE];
+ char[] source = output[0].toCharArray();
+ r.gc();
+
+ long stringsizeStart = r.totalMemory()-r.freeMemory();
+
+ for (int i = 0; i < TEST_SIZE; i++) {
+ serializeOutput[i] = new String(source);
+ }
+ long stringsizeEnd = r.totalMemory()-r.freeMemory();
+
+ log.info("ORG JSON Lib Output "
+ + average(startOutput, endOutput, TEST_SIZE)
+ + " ms/conversion, "
+ + (average(memstart, memend, TEST_SIZE)-average(stringsizeStart, stringsizeEnd, TEST_SIZE))
+ + " heap bytes/conversion, output packet consumed on average "
+ + average(stringsizeStart, stringsizeEnd, TEST_SIZE)+" for a string length of "+output[0].length());
+ log.info("Output Was ["+output[0]+"]");
+ }
+
+ /**
+ * @param endOutput
+ * @param startOutput
+ * @param testSize
+ * @return
+ */
+ private float average(long start, long end, int testSize) {
+ float r = end - start;
+ r = r / testSize;
+ return r;
+ }
+
+ public void XtestToJsonOnInheritedClassInput() throws Exception {
+ SpecialPerson[] spa = new SpecialPerson[TEST_SIZE];
+ SpecialPerson[] sparesult = new SpecialPerson[TEST_SIZE];
+ Runtime r = Runtime.getRuntime();
+ r.gc();
+ long personStart = r.totalMemory()-r.freeMemory();
+ for (int i = 0; i < TEST_SIZE; i++) {
+ spa[i] = new SpecialPerson(String.valueOf(i), "robot", "nonsense");
+ }
+ long personEnd = r.totalMemory()-r.freeMemory();
+
+ String[] serializeOutput = new String[TEST_SIZE];
+ r.gc();
+ for (int i = 0; i < TEST_SIZE; i++) {
+
+ serializeOutput[i] = beanJsonConverter.convertToString(spa[i]);
+ }
+
+ r.gc();
+ long memstart = r.totalMemory()-r.freeMemory();
+ long startInput = System.currentTimeMillis();
+
+ for (int i = 0; i < TEST_SIZE; i++) {
+ sparesult[i] = beanJsonConverter.convertToObject(
+ serializeOutput[i], SpecialPerson.class);
+ }
+ long endInput = System.currentTimeMillis();
+ long memend = r.totalMemory()-r.freeMemory();
+
+ log.info("SF JSON Lib Input "
+ + average(startInput, endInput, TEST_SIZE)
+ + " ms/conversion, "
+ + (average(memstart, memend, TEST_SIZE)-average(personStart, personEnd, TEST_SIZE))
+ + " heap bytes/conversion, person object consumed on average "
+ + average(personStart, personEnd, TEST_SIZE));
+ }
+
+}
Modified: incubator/shindig/trunk/pom.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/pom.xml?rev=678158&r1=678157&r2=678158&view=diff
==============================================================================
--- incubator/shindig/trunk/pom.xml (original)
+++ incubator/shindig/trunk/pom.xml Sat Jul 19 06:51:03 2008
@@ -853,6 +853,16 @@
<artifactId>htmlunit</artifactId>
<version>2.1</version>
</dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.13</version>
+ </dependency>
+ <dependency>
+ <groupId>rhino</groupId>
+ <artifactId>js</artifactId>
+ <version>1.6R7</version>
+ </dependency>
</dependencies>
</dependencyManagement>
</project>