Progress on JSON
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 18 Sep 2009 15:06:13 +0000 (15:06 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 18 Sep 2009 15:06:13 +0000 (15:06 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@2966 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

28 files changed:
security/demo/org.argeo.security.demo.log4j/log4j.properties
security/demo/pom.xml
security/modules/.classpath [new file with mode: 0644]
security/modules/.project [new file with mode: 0644]
security/modules/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
security/modules/.settings/org.maven.ide.eclipse.prefs [new file with mode: 0644]
security/modules/org.argeo.security.webapp/META-INF/MANIFEST.MF
security/modules/org.argeo.security.webapp/WEB-INF/osgi.xml
security/modules/org.argeo.security.webapp/WEB-INF/security-servlet.xml
security/modules/pom.xml
security/runtime/org.argeo.security.core/.classpath
security/runtime/org.argeo.security.core/pom.xml
security/runtime/org.argeo.security.core/src/main/resources/META-INF/spring/natures.xml [new file with mode: 0644]
security/runtime/org.argeo.security.core/src/main/resources/META-INF/spring/osgi.xml [new file with mode: 0644]
security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/UsersRolesController.java
server/runtime/org.argeo.server.core/pom.xml
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/DeserializingEditor.java [new file with mode: 0644]
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/ServerAnswer.java
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/ServerDeserializer.java
server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/mvc/DefaultHandlerExceptionResolver.java
server/runtime/org.argeo.server.json/.classpath
server/runtime/org.argeo.server.json/pom.xml
server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/GenericJsonDeserializer.java [new file with mode: 0644]
server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonObjectFactory.java [new file with mode: 0644]
server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonObjectFactoryImpl.java [new file with mode: 0644]
server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonServerMapper.java
server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonServerSerializer.java [new file with mode: 0644]
server/runtime/org.argeo.server.json/src/test/java/org/argeo/server/json/JsonServerMapperTest.java [new file with mode: 0644]

index c9d2a9118c802a510024c0b76b53bfd02200266d..f54a84e41dea899f17356516b0ec5389d159d0f0 100644 (file)
@@ -8,7 +8,7 @@ log4j.logger.org.hibernate=WARN
 log4j.logger.org.springframework=WARN
 #log4j.logger.org.springframework.web=DEBUG
 #log4j.logger.org.springframework.jms=WARN
-log4j.logger.org.springframework.security=DEBUG
+log4j.logger.org.springframework.security=WARN
 
 log4j.org.apache.directory=ERROR
 
index 8c9dfe992e77d892d67f674c925f46b20f5487a2..bc46b0d3608144e1736567746b220e17fbce6a25 100644 (file)
@@ -34,6 +34,7 @@
                                                        org.argeo.security.manager.ldap,
                                                        org.argeo.security.webapp,
                                                        org.argeo.security.ria,
+                                                       org.argeo.security.core,
                                                        org.argeo.server.ads.server
                                                </slc.osgi.start>
                                                <slc.osgi.bundles>
diff --git a/security/modules/.classpath b/security/modules/.classpath
new file mode 100644 (file)
index 0000000..d0bec0f
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+       <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+       <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/security/modules/.project b/security/modules/.project
new file mode 100644 (file)
index 0000000..c47b78c
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.security.modules</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.maven.ide.eclipse.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.maven.ide.eclipse.maven2Nature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/security/modules/.settings/org.eclipse.jdt.core.prefs b/security/modules/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..7d22597
--- /dev/null
@@ -0,0 +1,5 @@
+#Fri Sep 18 15:22:32 CEST 2009
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/security/modules/.settings/org.maven.ide.eclipse.prefs b/security/modules/.settings/org.maven.ide.eclipse.prefs
new file mode 100644 (file)
index 0000000..3a44ef1
--- /dev/null
@@ -0,0 +1,9 @@
+#Fri Sep 18 15:22:23 CEST 2009
+activeProfiles=
+eclipse.preferences.version=1
+fullBuildGoals=process-test-resources
+includeModules=false
+resolveWorkspaceProjects=true
+resourceFilterGoals=process-resources resources\:testResources
+skipCompilerPlugin=true
+version=1
index 35682dd8e6d6c52a37a80e7cc5d6a6ea9289dbd1..74c67491f46744a902172d166b88b84a8c92d45d 100644 (file)
@@ -3,6 +3,7 @@ Bundle-Version: 0.1.1.SNAPSHOT
 Import-Package: javax.servlet,
  javax.servlet.http,
  javax.servlet.resources,
+ org.argeo.security,
  org.argeo.security.dao,
  org.argeo.security.mvc,
  org.argeo.server.json,
index 22cec14a5b4e51d6b89775cc0743ffecbbe07b88..aa2f7164a22d25c8828b0cf124c46867beb30d5a 100644 (file)
@@ -12,4 +12,6 @@
        <reference id="userDao" interface="org.argeo.security.dao.UserDao" />\r
        <reference id="roleDao" interface="org.argeo.security.dao.RoleDao" />\r
 \r
+       <list id="objectFactories" interface="org.argeo.server.json.JsonObjectFactory"\r
+               cardinality="0..N" />\r
 </beans:beans>
\ No newline at end of file
index b2938510a99e1b5ae6446600cbf562e3b6dbc968..97d3b121ae9402083bb8a63001a5769fe9ed5067 100644 (file)
        <bean id="controller" class="org.argeo.security.mvc.UsersRolesController">
                <property name="userDao" ref="userDao" />
                <property name="roleDao" ref="roleDao" />
+               <property name="userDeserializer">
+                       <bean class="org.argeo.server.json.JsonServerMapper">
+                               <property name="targetClass" value="org.argeo.security.BasicArgeoUser" />
+                               <property name="deserializers">
+                                       <map>
+                                               <entry key="org.argeo.security.UserNature">
+                                                       <bean class="org.argeo.server.json.GenericJsonDeserializer">
+                                                               <property name="objectFactories" ref="objectFactories" />
+                                                       </bean>
+                                               </entry>
+                                       </map>
+                               </property>
+                       </bean>
+               </property>
        </bean>
 
        <bean id="viewResolver" class="org.argeo.server.mvc.SerializingViewResolver">
index fb9ed57590218189b148d10a54d0d0eaa41c0da5..ff5031d4dac409d00d1e3707896604d58f490af5 100644 (file)
@@ -1,4 +1,5 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
                <groupId>org.argeo.commons</groupId>
                        </plugin>
                </plugins>
        </build>
+       <dependencies>
+               <!-- Argeo -->
+               <dependency>
+                       <groupId>org.argeo.commons.security</groupId>
+                       <artifactId>org.argeo.security.mvc</artifactId>
+                       <version>0.1.1-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons.security</groupId>
+                       <artifactId>org.argeo.security.ria</artifactId>
+                       <version>0.1.1-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons.server</groupId>
+                       <artifactId>org.argeo.server.json</artifactId>
+                       <version>0.1.1-SNAPSHOT</version>
+               </dependency>
+
+               <!-- OSGi -->
+               <dependency>
+                       <groupId>org.argeo.commons.osgi</groupId>
+                       <artifactId>org.argeo.osgi.boot</artifactId>
+                       <version>0.1.1-SNAPSHOT</version>
+               </dependency>
+
+               <!--  Commons Dep -->
+               <dependency>
+                       <groupId>org.argeo.commons.server</groupId>
+                       <artifactId>org.argeo.server.dep.tomcat</artifactId>
+                       <version>0.1.1-SNAPSHOT</version>
+                       <type>pom</type>
+               </dependency>
+               <dependency>
+                       <groupId>org.argeo.commons.server</groupId>
+                       <artifactId>org.argeo.server.dep.ads</artifactId>
+                       <version>0.1.1-SNAPSHOT</version>
+                       <type>pom</type>
+               </dependency>
+
+               <!-- Spring -->
+               <dependency>
+                       <groupId>org.springframework.osgi</groupId>
+                       <artifactId>org.springframework.osgi.extender</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework.osgi</groupId>
+                       <artifactId>org.springframework.osgi.web.extender</artifactId>
+               </dependency>
+       </dependencies>
 </project>
\ No newline at end of file
index bab5b6519cb35d626d1749afcb047740c3971f90..98f38b674654ac1df29fe62bc57ba707b6bb7ac9 100644 (file)
@@ -1,7 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
        <classpathentry kind="src" output="target/classes" path="src/main/java"/>
-       <classpathentry kind="src" path="src/test/java"/>
+       <classpathentry kind="src" output="target/classes" path="src/main/resources"/>
+       <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
        <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
        <classpathentry kind="output" path="target/classes"/>
index 753d5d711c6fd88d8cf3653771cee8f77bd3020e..3fd7ae8890994d3638d2a57c6981dfd396516059 100644 (file)
@@ -32,6 +32,9 @@
                                                <Export-Package>
                                                        org.argeo.security.*
                                                </Export-Package>
+                                               <Import-Package>*,
+                                                       org.argeo.server.json;resolution:=optional
+                                               </Import-Package>
                                        </instructions>
                                </configuration>
                        </plugin>
diff --git a/security/runtime/org.argeo.security.core/src/main/resources/META-INF/spring/natures.xml b/security/runtime/org.argeo.security.core/src/main/resources/META-INF/spring/natures.xml
new file mode 100644 (file)
index 0000000..b2ac117
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+
+       <bean id="jsonObjectFactory" class="org.argeo.server.json.JsonObjectFactoryImpl">
+       </bean>
+</beans>
\ No newline at end of file
diff --git a/security/runtime/org.argeo.security.core/src/main/resources/META-INF/spring/osgi.xml b/security/runtime/org.argeo.security.core/src/main/resources/META-INF/spring/osgi.xml
new file mode 100644 (file)
index 0000000..649157f
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans:beans xmlns="http://www.springframework.org/schema/osgi"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"\r
+       xsi:schemaLocation="http://www.springframework.org/schema/osgi  \r
+       http://www.springframework.org/schema/osgi/spring-osgi-1.1.xsd\r
+       http://www.springframework.org/schema/beans   \r
+       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">\r
+\r
+       <service ref="jsonObjectFactory" interface="org.argeo.server.json.JsonObjectFactory" />\r
+\r
+</beans:beans>
\ No newline at end of file
index 4b91075cee17e1d23fb3437ae60730cd944db0ff..c95d909841ced8b24d83a6828c3efe949303a317 100644 (file)
@@ -1,26 +1,47 @@
 package org.argeo.security.mvc;
 
+import java.io.Reader;
+import java.io.StringReader;
 import java.util.List;
 
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.argeo.security.ArgeoUser;
+import org.argeo.security.BasicArgeoUser;
 import org.argeo.security.core.ArgeoUserDetails;
 import org.argeo.security.dao.RoleDao;
 import org.argeo.security.dao.UserDao;
 import org.argeo.server.BooleanAnswer;
+import org.argeo.server.DeserializingEditor;
 import org.argeo.server.ServerAnswer;
+import org.argeo.server.ServerDeserializer;
 import org.argeo.server.mvc.MvcConstants;
 import org.springframework.security.Authentication;
 import org.springframework.security.context.SecurityContextHolder;
 import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
 import org.springframework.web.bind.annotation.ModelAttribute;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 
 @Controller
 public class UsersRolesController implements MvcConstants {
+       private final static Log log = LogFactory
+                       .getLog(UsersRolesController.class);
+
        private UserDao userDao;
        private RoleDao roleDao;
 
+       private ServerDeserializer userDeserializer = null;
+
+       @InitBinder
+       public void initBinder(WebDataBinder binder) {
+               binder.registerCustomEditor(BasicArgeoUser.class,
+                               new DeserializingEditor(userDeserializer));
+       }
+
        /* USER */
 
        @RequestMapping("/getCredentials.security")
@@ -43,6 +64,38 @@ public class UsersRolesController implements MvcConstants {
                return new BooleanAnswer(userDao.userExists(username));
        }
 
+       @RequestMapping("/createUser.security")
+       @ModelAttribute(ANSWER_MODEL_KEY)
+       public ServerAnswer createUser(Reader reader) {
+               ArgeoUser user = (ArgeoUser) userDeserializer.deserialize(reader);
+               userDao.create(user);
+               return ServerAnswer.ok("User " + user.getUsername() + " created");
+       }
+
+       @RequestMapping("/updateUser.security")
+       @ModelAttribute(ANSWER_MODEL_KEY)
+       public ServerAnswer updateUser(Reader reader) {
+               ArgeoUser user = (ArgeoUser) userDeserializer.deserialize(reader);
+               userDao.update(user);
+               return ServerAnswer.ok("User " + user.getUsername() + " updated");
+       }
+
+       @RequestMapping("/createUser2.security")
+       @ModelAttribute(ANSWER_MODEL_KEY)
+       public ServerAnswer createUser(@RequestParam("body") String body) {
+               if (log.isDebugEnabled())
+                       log.debug("body:\n" + body);
+               StringReader reader = new StringReader(body);
+               ArgeoUser user = null;
+               try {
+                       user = (ArgeoUser) userDeserializer.deserialize(reader);
+               } finally {
+                       IOUtils.closeQuietly(reader);
+               }
+               userDao.create(user);
+               return ServerAnswer.ok("User " + user.getUsername() + " created");
+       }
+
        @RequestMapping("/deleteUser.security")
        @ModelAttribute(ANSWER_MODEL_KEY)
        public ServerAnswer deleteUser(@RequestParam("username") String username) {
@@ -85,4 +138,8 @@ public class UsersRolesController implements MvcConstants {
                this.roleDao = roleDao;
        }
 
+       public void setUserDeserializer(ServerDeserializer userDeserializer) {
+               this.userDeserializer = userDeserializer;
+       }
+
 }
index 51d1267b46a359541bdd4991b103f241bb8c10bf..89c480ddbb0a67b4951b2f65e7b31b2b3e2d7a9e 100644 (file)
                        <artifactId>com.springsource.javax.servlet</artifactId>
                </dependency>
 
+               <!-- Logging -->
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>com.springsource.slf4j.org.apache.commons.logging</artifactId>
+               </dependency>
+
        </dependencies>
 </project>
diff --git a/server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/DeserializingEditor.java b/server/runtime/org.argeo.server.core/src/main/java/org/argeo/server/DeserializingEditor.java
new file mode 100644 (file)
index 0000000..4c8dc6d
--- /dev/null
@@ -0,0 +1,26 @@
+package org.argeo.server;
+
+import java.beans.PropertyEditorSupport;
+import java.io.StringReader;
+
+import org.apache.commons.io.IOUtils;
+
+public class DeserializingEditor extends PropertyEditorSupport {
+       private ServerDeserializer deserializer;
+
+       public DeserializingEditor(ServerDeserializer deserializer) {
+               super();
+               this.deserializer = deserializer;
+       }
+
+       @Override
+       public void setAsText(String text) throws IllegalArgumentException {
+               StringReader reader = new StringReader(text);
+               try {
+                       setValue(deserializer.deserialize(reader));
+               } finally {
+                       IOUtils.closeQuietly(reader);
+               }
+       }
+
+}
index c3e747608dcf10fc264ca87ecbdc4127c5829482..9bf2634ae35ca7ab76403dc480470a981e39c41b 100644 (file)
@@ -69,4 +69,9 @@ public class ServerAnswer {
                return new ServerAnswer(OK, message);
        }
 
+       @Override
+       public String toString() {
+               return "ServerAnswer{status:"+status+", message:"+message+"}";
+       }
+
 }
index 98b7f71ebfc7f3a990a40fd03d8bc60d4fa6f988..7c15b066c5a20a30429a893af739d5226173357e 100644 (file)
@@ -1,7 +1,8 @@
 package org.argeo.server;
 
-import javax.servlet.http.HttpServletRequest;
+import java.io.Reader;
+
 
 public interface ServerDeserializer {
-       public Object deserialize(Object obj, HttpServletRequest request);
+       public Object deserialize(Reader str);
 }
index d075d320513acfedf81e629ef33cb513a2e6af53..ff5ee02877bf41a0f5ac7f532e5e2fa38f6db90e 100644 (file)
@@ -3,17 +3,28 @@ package org.argeo.server.mvc;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.argeo.server.ServerAnswer;
 import org.springframework.web.servlet.HandlerExceptionResolver;
 import org.springframework.web.servlet.ModelAndView;
 
 public class DefaultHandlerExceptionResolver implements
                HandlerExceptionResolver {
+       private final static Log log = LogFactory
+                       .getLog(DefaultHandlerExceptionResolver.class);
 
        public ModelAndView resolveException(HttpServletRequest request,
                        HttpServletResponse response, Object handler, Exception ex) {
                ModelAndView mv = new ModelAndView();
-               mv.addObject(ServerAnswer.error(ex));
+               ServerAnswer serverAnswer = ServerAnswer.error(ex);
+               mv.addObject(serverAnswer);
+
+               if (log.isDebugEnabled())
+                       log.error(serverAnswer);
+
+               mv.setViewName("500");
+               // response.setStatus(500);
                return mv;
        }
 
index 16f01e2ee7b671c44c26c453773dab706e98da1e..6254cacb822d545ae357ff1397b90b66aeb73564 100644 (file)
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
        <classpathentry kind="src" output="target/classes" path="src/main/java"/>
+       <classpathentry kind="src" path="src/test/java" output="target/test-classes"/>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
        <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
        <classpathentry kind="output" path="target/classes"/>
index 182f74d4cef52d6d1a727a456a9552bede28dd17..b12c17b1a53bca9c3ab6c66c5f80bba301eb6eee 100644 (file)
                        <groupId>org.springframework</groupId>
                        <artifactId>org.springframework.web.servlet</artifactId>
                </dependency>
+               <dependency>
+                       <groupId>org.springframework.osgi</groupId>
+                       <artifactId>org.springframework.osgi.core</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.eclipse.osgi</groupId>
+                       <artifactId>org.eclipse.osgi</artifactId>
+               </dependency>
 
                <!-- J2EE -->
                <dependency>
                        <artifactId>com.springsource.javax.servlet</artifactId>
                </dependency>
 
+               <!-- Logging -->
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>com.springsource.slf4j.org.apache.commons.logging</artifactId>
+               </dependency>
+
+               <!-- TEST -->
+               <dependency>
+                       <groupId>org.junit</groupId>
+                       <artifactId>com.springsource.junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+
        </dependencies>
 </project>
diff --git a/server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/GenericJsonDeserializer.java b/server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/GenericJsonDeserializer.java
new file mode 100644 (file)
index 0000000..c91f76d
--- /dev/null
@@ -0,0 +1,73 @@
+package org.argeo.server.json;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.server.ArgeoServerException;
+import org.codehaus.jackson.JsonFactory;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.ObjectCodec;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.JsonDeserializer;
+import org.codehaus.jackson.map.ObjectMapper;
+
+public class GenericJsonDeserializer<T> extends JsonDeserializer<T> {
+       private final static Log log = LogFactory
+                       .getLog(GenericJsonDeserializer.class);
+
+       private JsonFactory jsonFactory = new JsonFactory();
+       private ObjectCodec objectCodec = new ObjectMapper();
+
+       private String typeField = "type";
+
+       private List<JsonObjectFactory> objectFactories = new ArrayList<JsonObjectFactory>();
+
+       @Override
+       public T deserialize(JsonParser parser, DeserializationContext ctxt)
+                       throws IOException, JsonProcessingException {
+               // first read as Json DOM in order to extract the type
+               // TODO: optimize with streaming API
+               JsonNode root = parser.readValueAsTree();
+               String type = root.get(typeField).getTextValue();
+
+               // Write it back as a string
+               StringWriter writer = new StringWriter();
+               JsonGenerator generator = jsonFactory.createJsonGenerator(writer);
+               generator.setCodec(objectCodec);
+               generator.writeTree(root);
+               String str = writer.toString();
+
+               if (log.isDebugEnabled())
+                       log.debug("Deserialize object of type=" + type + ", str=" + str);
+
+               JsonObjectFactory objectFactory = null;
+               jofs: for (JsonObjectFactory jof : objectFactories) {
+                       if (jof.supports(type)) {
+                               objectFactory = jof;
+                               break jofs;
+                       }
+               }
+
+               if (objectFactory == null)
+                       throw new ArgeoServerException(
+                                       "Cannot find JSON object factory for type " + type);
+
+               return (T) objectFactory.readValue(type, str);
+       }
+
+       public void setTypeField(String typeField) {
+               this.typeField = typeField;
+       }
+
+       public void setObjectFactories(List<JsonObjectFactory> objectFactories) {
+               this.objectFactories = objectFactories;
+       }
+
+}
diff --git a/server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonObjectFactory.java b/server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonObjectFactory.java
new file mode 100644 (file)
index 0000000..b3ef50f
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.server.json;
+
+
+public interface JsonObjectFactory {
+       public Boolean supports(String type);
+
+       public <T> T readValue(String type, String str);
+}
diff --git a/server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonObjectFactoryImpl.java b/server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonObjectFactoryImpl.java
new file mode 100644 (file)
index 0000000..cd6c00e
--- /dev/null
@@ -0,0 +1,113 @@
+package org.argeo.server.json;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.server.ArgeoServerException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.osgi.framework.BundleContext;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.osgi.context.BundleContextAware;
+import org.springframework.osgi.util.BundleDelegatingClassLoader;
+
+public class JsonObjectFactoryImpl implements JsonObjectFactory,
+               BundleContextAware, InitializingBean {
+       private final static Log log = LogFactory
+                       .getLog(JsonObjectFactoryImpl.class);
+
+       private BundleContext bundleContext;
+       private BundleDelegatingClassLoader classLoader;
+
+       private ObjectMapper objectMapper = new ObjectMapper();
+       private Map<String, Class> supportedTypes = new HashMap<String, Class>();
+
+       public Boolean supports(String type) {
+               if (supportedTypes.containsKey(type))
+                       return true;
+
+               return loadClass(type) != null ? true : false;
+               // try {
+               // // Class.forName(type);
+               // Thread.currentThread().getContextClassLoader().loadClass(type);
+               // return true;
+               // } catch (ClassNotFoundException e) {
+               // return false;
+               // }
+       }
+
+       public <T> T readValue(String type, String str) {
+               final Class clss;
+               if (supportedTypes.containsKey(type))
+                       clss = supportedTypes.get(type);
+               else {
+                       clss = loadClass(type);
+                       if (clss == null)
+                               throw new ArgeoServerException("Cannot find type " + type);
+                       // try {
+                       // // clss = Class.forName(type);
+                       // clss = Thread.currentThread().getContextClassLoader()
+                       // .loadClass(type);
+                       // } catch (ClassNotFoundException e) {
+                       // throw new ArgeoServerException("Cannot find type " + type, e);
+                       // }
+               }
+
+               try {
+                       return (T) objectMapper.readValue(str, clss);
+               } catch (Exception e) {
+                       throw new ArgeoServerException("Cannot deserialize " + str
+                                       + " (type=" + type + ")", e);
+               }
+       }
+
+       public void setSupportedTypes(Map<String, Class> supportedTypes) {
+               this.supportedTypes = supportedTypes;
+       }
+
+       protected Class loadClass(String type) {
+               Class clss;
+//             try {
+//                     return Class.forName(type);
+//             } catch (ClassNotFoundException e) {
+//                     if (log.isDebugEnabled())
+//                             log.debug("Class.forName failed: " + e);
+//             }
+//
+//             try {
+//                     return Thread.currentThread().getContextClassLoader().loadClass(
+//                                     type);
+//             } catch (ClassNotFoundException e) {
+//                     if (log.isDebugEnabled())
+//                             log
+//                                             .debug("Thread.currentThread().getContextClassLoader().loadClass failed: "
+//                                                             + e);
+//             }
+//
+//             try {
+//                     return getClass().getClassLoader().loadClass(type);
+//             } catch (ClassNotFoundException e) {
+//                     if (log.isDebugEnabled())
+//                             log.debug("getClass().getClassLoader().loadClass failed: " + e);
+//             }
+//
+               try {
+                       return classLoader.loadClass(type);
+               } catch (ClassNotFoundException e) {
+                       if (log.isDebugEnabled())
+                               log.debug("BundleDelegatingClassLoader.loadClass failed: " + e);
+               }
+
+               return null;
+       }
+
+       public void setBundleContext(BundleContext bundleContext) {
+               this.bundleContext = bundleContext;
+       }
+
+       public void afterPropertiesSet() throws Exception {
+               classLoader = BundleDelegatingClassLoader
+                               .createBundleClassLoaderFor(bundleContext.getBundle());
+       }
+}
index 4ab128e0b51f24605ad98cb75f9c7646dd0634df..8fef8e6b2fa7772638bbcdae89280d0c218cc201 100644 (file)
@@ -1,53 +1,78 @@
 package org.argeo.server.json;
 
-import java.io.BufferedReader;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Map;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.argeo.server.ArgeoServerException;
 import org.argeo.server.ServerDeserializer;
-import org.argeo.server.ServerSerializer;
-import org.codehaus.jackson.JsonFactory;
-import org.codehaus.jackson.JsonGenerator;
-import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.DeserializationContext;
+import org.codehaus.jackson.map.DeserializationProblemHandler;
+import org.codehaus.jackson.map.JsonDeserializer;
+import org.codehaus.jackson.map.deser.CustomDeserializerFactory;
+import org.codehaus.jackson.map.deser.StdDeserializerProvider;
+import org.springframework.beans.factory.InitializingBean;
 
-public class JsonServerMapper implements ServerSerializer, ServerDeserializer {
-       private JsonFactory jsonFactory = new JsonFactory();
-       private ObjectMapper objectMapper = new ObjectMapper();
+public class JsonServerMapper extends JsonServerSerializer implements
+               ServerDeserializer, InitializingBean {
+       private final static Log log = LogFactory.getLog(JsonServerMapper.class);
 
-       public void serialize(Object obj, HttpServletRequest request,
-                       HttpServletResponse response) {
-               try {
-                       response.setContentType("application/json");
+       private Class targetClass;
 
-                       JsonGenerator jsonGenerator = jsonFactory
-                                       .createJsonGenerator(response.getWriter());
-                       jsonGenerator.useDefaultPrettyPrinter();
+       private Map<Class, JsonDeserializer> deserializers = new HashMap<Class, JsonDeserializer>();
 
-                       objectMapper.writeValue(jsonGenerator, obj);
-               } catch (Exception e) {
-                       throw new ArgeoServerException("Cannot serialize " + obj, e);
+       public void afterPropertiesSet() throws Exception {
+               CustomDeserializerFactory dsf = new CustomDeserializerFactory();
+               for (Class clss : deserializers.keySet()) {
+                       dsf.addSpecificMapping(clss, deserializers.get(clss));
                }
+               StdDeserializerProvider sdp = new StdDeserializerProvider(dsf);
+               getObjectMapper().setDeserializerProvider(sdp);
+               // ignore unkown properties
+               getObjectMapper().getDeserializationConfig().addHandler(
+                               new DeserializationProblemHandler() {
+                                       public boolean handleUnknownProperty(
+                                                       DeserializationContext ctxt,
+                                                       JsonDeserializer<?> deserializer, Object bean,
+                                                       String propertyName) throws IOException,
+                                                       JsonProcessingException {
+                                               if (log.isDebugEnabled())
+                                                       log.debug("Ignore property " + propertyName);
+                                               return true;
+                                       }
+                               });
        }
 
-       public Object deserialize(Object obj, HttpServletRequest request) {
+       public Object deserialize(Reader reader) {
                try {
-                       String body = request.getParameter("body");
-                       if (body == null) {
-                               // lets read the message body instead
-                               BufferedReader reader = request.getReader();
-                               StringBuffer buffer = new StringBuffer();
-                               String line = null;
-                               while (((line = reader.readLine()) != null)) {
-                                       buffer.append(line);
-                               }
-                               body = buffer.toString();
-                       }
-                       return objectMapper.readValue(body, Object.class);
+                       // String body = request.getParameter("body");
+                       // if (body == null) {
+                       // // lets read the message body instead
+                       // BufferedReader reader = request.getReader();
+                       // StringBuffer buffer = new StringBuffer();
+                       // String line = null;
+                       // while (((line = reader.readLine()) != null)) {
+                       // buffer.append(line);
+                       // }
+                       // body = buffer.toString();
+                       // }
+                       return getObjectMapper().readValue(reader, targetClass);
                } catch (Exception e) {
-                       throw new ArgeoServerException("Cannot deserialize " + request, e);
+                       throw new ArgeoServerException("Cannot deserialize " + reader, e);
                }
+
+       }
+
+       public void setTargetClass(Class targetClass) {
+               this.targetClass = targetClass;
+       }
+
+       public void setDeserializers(Map<Class, JsonDeserializer> deserializers) {
+               this.deserializers = deserializers;
        }
 
 }
diff --git a/server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonServerSerializer.java b/server/runtime/org.argeo.server.json/src/main/java/org/argeo/server/json/JsonServerSerializer.java
new file mode 100644 (file)
index 0000000..1c38bbe
--- /dev/null
@@ -0,0 +1,59 @@
+package org.argeo.server.json;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.server.ArgeoServerException;
+import org.argeo.server.ServerSerializer;
+import org.codehaus.jackson.JsonFactory;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.map.ObjectMapper;
+
+public class JsonServerSerializer implements ServerSerializer {
+       private final static Log log = LogFactory
+                       .getLog(JsonServerSerializer.class);
+
+       private JsonFactory jsonFactory = new JsonFactory();
+       private ObjectMapper objectMapper = new ObjectMapper();
+
+       private Boolean prettyPrint = true;
+
+       public void serialize(Object obj, HttpServletRequest request,
+                       HttpServletResponse response) {
+               JsonGenerator jsonGenerator = null;
+               try {
+                       response.setContentType("application/json");
+
+                       jsonGenerator = jsonFactory.createJsonGenerator(response
+                                       .getWriter());
+                       if (prettyPrint)
+                               jsonGenerator.useDefaultPrettyPrinter();
+
+                       objectMapper.writeValue(jsonGenerator, obj);
+
+                       jsonGenerator.close();
+               } catch (Exception e) {
+                       throw new ArgeoServerException("Cannot serialize " + obj, e);
+               } finally {
+                       if (jsonGenerator != null)
+                               try {
+                                       jsonGenerator.close();
+                               } catch (IOException e) {
+                                       if (log.isTraceEnabled())
+                                               log.error("Cannot close JSON generator", e);
+                               }
+               }
+       }
+
+       public void setPrettyPrint(Boolean prettyPrint) {
+               this.prettyPrint = prettyPrint;
+       }
+
+       protected ObjectMapper getObjectMapper() {
+               return objectMapper;
+       }
+}
diff --git a/server/runtime/org.argeo.server.json/src/test/java/org/argeo/server/json/JsonServerMapperTest.java b/server/runtime/org.argeo.server.json/src/test/java/org/argeo/server/json/JsonServerMapperTest.java
new file mode 100644 (file)
index 0000000..d73c598
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.server.json;
+
+public class JsonServerMapperTest {
+       public void testDeserialize() {
+               JsonServerMapper mapper = new JsonServerMapper();
+               //mapper.setTargetClass(targetClass)
+       }
+}