=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java 2014-06-06 07:40:49 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNode.java 2014-06-08 10:58:50 +0000 @@ -28,6 +28,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE */ +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import org.hisp.dhis.node.exception.InvalidTypeException; import org.hisp.dhis.node.types.SimpleNode; @@ -42,15 +44,17 @@ */ public abstract class AbstractNode implements Node { - private String name; - - private final NodeType nodeType; - - private String namespace; - - private String comment; - - private List children = Lists.newArrayList(); + protected String name; + + protected final NodeType nodeType; + + protected Node parent; + + protected String namespace; + + protected String comment; + + protected List children = Lists.newArrayList(); protected AbstractNode( String name, NodeType nodeType ) { @@ -76,6 +80,17 @@ } @Override + public Node getParent() + { + return parent; + } + + protected void setParent( Node parent ) + { + this.parent = parent; + } + + @Override public boolean is( NodeType type ) { return type.equals( nodeType ); @@ -130,6 +145,8 @@ } children.add( child ); + ((AbstractNode) child).setParent( this ); + return child; } @@ -147,7 +164,7 @@ { List clone = Lists.newArrayList( children ); Collections.sort( clone, OrderComparator.INSTANCE ); - return clone; + return ImmutableList.copyOf( clone ); } @Override @@ -196,12 +213,13 @@ @Override public String toString() { - return "Node{" + - "name='" + name + '\'' + - ", nodeType=" + nodeType + - ", namespace='" + namespace + '\'' + - ", comment='" + comment + '\'' + - ", children=" + children + - '}'; + return Objects.toStringHelper( this ) + .add( "name", name ) + .add( "nodeType", nodeType ) + .add( "parent", parent.getName() ) + .add( "namespace", namespace ) + .add( "comment", comment ) + .add( "children", children ) + .toString(); } } === added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNodeSerializer.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNodeSerializer.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/AbstractNodeSerializer.java 2014-06-08 10:58:50 +0000 @@ -0,0 +1,137 @@ +package org.hisp.dhis.node; + +/* + * Copyright (c) 2004-2014, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + */ + +import org.hisp.dhis.node.types.CollectionNode; +import org.hisp.dhis.node.types.ComplexNode; +import org.hisp.dhis.node.types.RootNode; +import org.hisp.dhis.node.types.SimpleNode; + +import java.io.OutputStream; + +/** + * @author Morten Olav Hansen + */ +public abstract class AbstractNodeSerializer implements NodeSerializer +{ + protected boolean startSerialize( RootNode rootNode, OutputStream outputStream ) throws Exception + { + return true; + } + + protected void endSerialize( RootNode rootNode, OutputStream outputStream ) throws Exception + { + } + + protected abstract void flushStream() throws Exception; + + @Override + public void serialize( RootNode rootNode, OutputStream outputStream ) throws Exception + { + startSerialize( rootNode, outputStream ); + writeRootNode( rootNode ); + endSerialize( rootNode, outputStream ); + } + + protected abstract void startWriteRootNode( RootNode rootNode ) throws Exception; + + protected void writeRootNode( RootNode rootNode ) throws Exception + { + startWriteRootNode( rootNode ); + + for ( Node node : rootNode.getChildren() ) + { + dispatcher( node ); + flushStream(); + } + + endWriteRootNode( rootNode ); + flushStream(); + } + + protected abstract void endWriteRootNode( RootNode rootNode ) throws Exception; + + protected abstract void startWriteSimpleNode( SimpleNode simpleNode ) throws Exception; + + protected void writeSimpleNode( SimpleNode simpleNode ) throws Exception + { + startWriteSimpleNode( simpleNode ); + endWriteSimpleNode( simpleNode ); + } + + protected abstract void endWriteSimpleNode( SimpleNode simpleNode ) throws Exception; + + protected abstract void startWriteComplexNode( ComplexNode complexNode ) throws Exception; + + protected void writeComplexNode( ComplexNode complexNode ) throws Exception + { + startWriteComplexNode( complexNode ); + + for ( Node node : complexNode.getChildren() ) + { + dispatcher( node ); + } + + endWriteComplexNode( complexNode ); + } + + protected abstract void endWriteComplexNode( ComplexNode complexNode ) throws Exception; + + protected abstract void startWriteCollectionNode( CollectionNode collectionNode ) throws Exception; + + protected void writeCollectionNode( CollectionNode collectionNode ) throws Exception + { + startWriteCollectionNode( collectionNode ); + + for ( Node node : collectionNode.getChildren() ) + { + dispatcher( node ); + } + + endWriteCollectionNode( collectionNode ); + } + + protected abstract void endWriteCollectionNode( CollectionNode collectionNode ) throws Exception; + + private void dispatcher( Node node ) throws Exception + { + switch ( node.getType() ) + { + case SIMPLE: + writeSimpleNode( (SimpleNode) node ); + break; + case COMPLEX: + writeComplexNode( (ComplexNode) node ); + break; + case COLLECTION: + writeCollectionNode( (CollectionNode) node ); + break; + } + } +} === added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Deserializer.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Deserializer.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Deserializer.java 2014-06-08 10:58:50 +0000 @@ -0,0 +1,42 @@ +package org.hisp.dhis.node; + +/* + * Copyright (c) 2004-2014, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + */ + +import java.io.InputStream; +import java.util.List; + +/** + * @author Morten Olav Hansen + */ +public interface Deserializer +{ + List contentTypes(); + + T deserialize( InputStream inputStream ) throws Exception; +} === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Node.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Node.java 2014-06-06 07:40:49 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Node.java 2014-06-08 10:58:50 +0000 @@ -53,6 +53,12 @@ NodeType getType(); /** + * Get parent node, or null if this is a top-level node. + * @return parent or null if node does not have parent + */ + Node getParent(); + + /** * @param type Type to check for * @return True if node is of this type */ === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeDeserializer.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeDeserializer.java 2014-06-04 20:15:48 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeDeserializer.java 2014-06-08 10:58:50 +0000 @@ -30,16 +30,15 @@ import org.hisp.dhis.node.types.RootNode; -import java.io.IOException; import java.io.InputStream; import java.util.List; /** * @author Morten Olav Hansen */ -public interface NodeDeserializer +public interface NodeDeserializer extends Deserializer { List contentTypes(); - RootNode deserialize( InputStream inputStream ) throws IOException; + RootNode deserialize( InputStream inputStream ) throws Exception; } === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeSerializer.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeSerializer.java 2014-06-04 16:22:56 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeSerializer.java 2014-06-08 10:58:50 +0000 @@ -30,16 +30,15 @@ import org.hisp.dhis.node.types.RootNode; -import java.io.IOException; import java.io.OutputStream; import java.util.List; /** * @author Morten Olav Hansen */ -public interface NodeSerializer +public interface NodeSerializer extends Serializer { List contentTypes(); - void serialize( RootNode rootNode, OutputStream outputStream ) throws IOException; + void serialize( RootNode rootNode, OutputStream outputStream ) throws Exception; } === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeService.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeService.java 2014-06-05 11:56:44 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/NodeService.java 2014-06-08 10:58:50 +0000 @@ -30,7 +30,6 @@ import org.hisp.dhis.node.types.RootNode; -import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -55,7 +54,7 @@ * @param contentType NodeSerializer contentType * @param outputStream Write to this outputStream */ - void serialize( RootNode rootNode, String contentType, OutputStream outputStream ) throws IOException; + void serialize( RootNode rootNode, String contentType, OutputStream outputStream ); /** * Find a nodeDeserializer that supports contentType or return null. @@ -71,5 +70,5 @@ * @param inputStream Read RootNode from this stream * @return RootNode deserialized from inputStream */ - RootNode deserialize( String contentType, InputStream inputStream ) throws IOException; + RootNode deserialize( String contentType, InputStream inputStream ); } === added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Serializer.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Serializer.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/Serializer.java 2014-06-08 10:58:50 +0000 @@ -0,0 +1,42 @@ +package org.hisp.dhis.node; + +/* + * Copyright (c) 2004-2014, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + */ + +import java.io.OutputStream; +import java.util.List; + +/** + * @author Morten Olav Hansen + */ +public interface Serializer +{ + List contentTypes(); + + void serialize( T object, OutputStream outputStream ) throws Exception; +} === added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/Jackson2JsonNodeSerializer.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/Jackson2JsonNodeSerializer.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/Jackson2JsonNodeSerializer.java 2014-06-08 10:58:50 +0000 @@ -0,0 +1,161 @@ +package org.hisp.dhis.node.serializers; + +/* + * Copyright (c) 2004-2014, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + */ + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.google.common.collect.Lists; +import org.hisp.dhis.node.AbstractNodeSerializer; +import org.hisp.dhis.node.types.CollectionNode; +import org.hisp.dhis.node.types.ComplexNode; +import org.hisp.dhis.node.types.RootNode; +import org.hisp.dhis.node.types.SimpleNode; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.stereotype.Component; + +import java.io.OutputStream; +import java.util.List; + +/** + * @author Morten Olav Hansen + */ +@Component +@Scope( value = "prototype", proxyMode = ScopedProxyMode.INTERFACES ) +public class Jackson2JsonNodeSerializer extends AbstractNodeSerializer +{ + public static final String CONTENT_TYPE = "application/json"; + + private final static ObjectMapper objectMapper = new ObjectMapper(); + + static + { + objectMapper.setSerializationInclusion( JsonInclude.Include.NON_NULL ); + objectMapper.configure( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false ); + objectMapper.configure( SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false ); + objectMapper.configure( SerializationFeature.WRAP_EXCEPTIONS, true ); + objectMapper.getFactory().enable( JsonGenerator.Feature.QUOTE_FIELD_NAMES ); + } + + private JsonGenerator generator; + + @Override + public List contentTypes() + { + return Lists.newArrayList( CONTENT_TYPE ); + } + + @Override + protected void flushStream() throws Exception + { + generator.flush(); + } + + @Override + protected boolean startSerialize( RootNode rootNode, OutputStream outputStream ) throws Exception + { + generator = objectMapper.getFactory().createGenerator( outputStream ); + return true; + } + + @Override + protected void startWriteRootNode( RootNode rootNode ) throws Exception + { + generator.writeStartObject(); + } + + @Override + protected void endWriteRootNode( RootNode rootNode ) throws Exception + { + generator.writeEndObject(); + } + + @Override + protected void startWriteSimpleNode( SimpleNode simpleNode ) throws Exception + { + if ( simpleNode.getValue() == null ) // add hint for this, exclude if null + { + return; + } + + if ( simpleNode.getParent().isCollection() ) + { + generator.writeObject( simpleNode.getValue() ); + } + else + { + generator.writeObjectField( simpleNode.getName(), simpleNode.getValue() ); + } + } + + @Override + protected void endWriteSimpleNode( SimpleNode simpleNode ) throws Exception + { + } + + @Override + protected void startWriteComplexNode( ComplexNode complexNode ) throws Exception + { + if ( complexNode.getParent().isCollection() ) + { + generator.writeStartObject(); + } + else + { + generator.writeObjectFieldStart( complexNode.getName() ); + } + } + + @Override + protected void endWriteComplexNode( ComplexNode complexNode ) throws Exception + { + generator.writeEndObject(); + } + + @Override + protected void startWriteCollectionNode( CollectionNode collectionNode ) throws Exception + { + if ( collectionNode.getParent().isCollection() ) + { + generator.writeStartArray(); + } + else + { + generator.writeArrayFieldStart( collectionNode.getName() ); + } + } + + @Override + protected void endWriteCollectionNode( CollectionNode collectionNode ) throws Exception + { + generator.writeEndArray(); + } +} === removed file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/JacksonJsonNodeSerializer.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/JacksonJsonNodeSerializer.java 2014-06-04 16:22:56 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/JacksonJsonNodeSerializer.java 1970-01-01 00:00:00 +0000 @@ -1,165 +0,0 @@ -package org.hisp.dhis.node.serializers; - -/* - * Copyright (c) 2004-2014, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE - */ - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.google.common.collect.Lists; -import org.hisp.dhis.node.Node; -import org.hisp.dhis.node.NodeSerializer; -import org.hisp.dhis.node.types.CollectionNode; -import org.hisp.dhis.node.types.ComplexNode; -import org.hisp.dhis.node.types.RootNode; -import org.hisp.dhis.node.types.SimpleNode; -import org.springframework.stereotype.Component; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.List; - -/** - * @author Morten Olav Hansen - */ -@Component -public class JacksonJsonNodeSerializer implements NodeSerializer -{ - public static final String CONTENT_TYPE = "application/json"; - - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Override - public List contentTypes() - { - return Lists.newArrayList( CONTENT_TYPE ); - } - - public JacksonJsonNodeSerializer() - { - objectMapper.setSerializationInclusion( JsonInclude.Include.NON_NULL ); - objectMapper.configure( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false ); - objectMapper.configure( SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false ); - objectMapper.configure( SerializationFeature.WRAP_EXCEPTIONS, true ); - objectMapper.getFactory().enable( JsonGenerator.Feature.QUOTE_FIELD_NAMES ); - } - - @Override - public void serialize( RootNode rootNode, OutputStream outputStream ) throws IOException - { - JsonGenerator generator = objectMapper.getFactory().createGenerator( outputStream ); - - writeRootNode( rootNode, generator ); - generator.flush(); - } - - private void writeRootNode( RootNode rootNode, JsonGenerator generator ) throws IOException - { - generator.writeStartObject(); - - for ( Node node : rootNode.getChildren() ) - { - dispatcher( node, generator, true ); - generator.flush(); - } - - generator.writeEndObject(); - } - - private void writeSimpleNode( SimpleNode simpleNode, JsonGenerator generator, boolean writeKey ) throws IOException - { - if ( simpleNode.getValue() == null ) // add hint for this, exclude if null - { - return; - } - - if ( writeKey ) - { - generator.writeObjectField( simpleNode.getName(), simpleNode.getValue() ); - } - else - { - generator.writeObject( simpleNode.getValue() ); - } - } - - private void writeComplexNode( ComplexNode complexNode, JsonGenerator generator, boolean writeKey ) throws IOException - { - if ( writeKey ) - { - generator.writeObjectFieldStart( complexNode.getName() ); - } - else - { - generator.writeStartObject(); - } - - for ( Node node : complexNode.getChildren() ) - { - dispatcher( node, generator, true ); - } - - generator.writeEndObject(); - } - - private void writeCollectionNode( CollectionNode collectionNode, JsonGenerator generator, boolean writeKey ) throws IOException - { - if ( writeKey ) - { - generator.writeArrayFieldStart( collectionNode.getName() ); - } - else - { - generator.writeStartArray(); - } - - for ( Node node : collectionNode.getChildren() ) - { - dispatcher( node, generator, false ); - } - - generator.writeEndArray(); - } - - private void dispatcher( Node node, JsonGenerator generator, boolean writeKey ) throws IOException - { - switch ( node.getType() ) - { - case SIMPLE: - writeSimpleNode( (SimpleNode) node, generator, writeKey ); - break; - case COMPLEX: - writeComplexNode( (ComplexNode) node, generator, writeKey ); - break; - case COLLECTION: - writeCollectionNode( (CollectionNode) node, generator, writeKey ); - break; - } - } -} === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java 2014-06-06 07:40:49 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/serializers/StAXNodeSerializer.java 2014-06-08 10:58:50 +0000 @@ -29,21 +29,20 @@ */ import com.google.common.collect.Lists; +import org.hisp.dhis.node.AbstractNodeSerializer; import org.hisp.dhis.node.Node; -import org.hisp.dhis.node.NodeSerializer; import org.hisp.dhis.node.types.CollectionNode; import org.hisp.dhis.node.types.ComplexNode; import org.hisp.dhis.node.types.RootNode; import org.hisp.dhis.node.types.SimpleNode; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import java.io.IOException; import java.io.OutputStream; import java.util.List; @@ -51,12 +50,19 @@ * @author Morten Olav Hansen */ @Component -@Scope( ConfigurableBeanFactory.SCOPE_PROTOTYPE ) -public class StAXNodeSerializer implements NodeSerializer +@Scope( value = "prototype", proxyMode = ScopedProxyMode.INTERFACES ) +public class StAXNodeSerializer extends AbstractNodeSerializer { public static final String CONTENT_TYPE = "application/xml"; - private final XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); + private static final XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance(); + + private XMLStreamWriter writer; + + static + { + xmlFactory.setProperty( "javax.xml.stream.isRepairingNamespaces", true ); + } @Override public List contentTypes() @@ -65,25 +71,21 @@ } @Override - public void serialize( RootNode rootNode, OutputStream outputStream ) throws IOException - { - XMLStreamWriter writer; - - try - { - xmlFactory.setProperty( "javax.xml.stream.isRepairingNamespaces", true ); - writer = xmlFactory.createXMLStreamWriter( outputStream ); - writer.setDefaultNamespace( rootNode.getDefaultNamespace() ); - writeRootNode( rootNode, writer ); - writer.flush(); - } - catch ( XMLStreamException e ) - { - throw new IOException( e.getMessage(), e.getCause() ); - } - } - - private void writeRootNode( RootNode rootNode, XMLStreamWriter writer ) throws IOException, XMLStreamException + protected boolean startSerialize( RootNode rootNode, OutputStream outputStream ) throws Exception + { + writer = xmlFactory.createXMLStreamWriter( outputStream ); + writer.setDefaultNamespace( rootNode.getDefaultNamespace() ); + return true; + } + + @Override + protected void flushStream() throws Exception + { + writer.flush(); + } + + @Override + protected void startWriteRootNode( RootNode rootNode ) throws Exception { writer.writeStartDocument( "UTF-8", "1.0" ); @@ -92,19 +94,18 @@ writer.writeComment( rootNode.getComment() ); } - writeStartElement( rootNode, writer ); - - for ( Node node : rootNode.getChildren() ) - { - dispatcher( node, writer ); - writer.flush(); - } - - writeEndElement( writer ); + writeStartElement( rootNode ); + } + + @Override + protected void endWriteRootNode( RootNode rootNode ) throws Exception + { + writer.writeEndElement(); writer.writeEndDocument(); } - private void writeSimpleNode( SimpleNode simpleNode, XMLStreamWriter writer ) throws XMLStreamException + @Override + protected void startWriteSimpleNode( SimpleNode simpleNode ) throws Exception { if ( simpleNode.getValue() == null ) // TODO include null or not? { @@ -117,7 +118,7 @@ { if ( !StringUtils.isEmpty( simpleNode.getNamespace() ) ) { - writer.writeAttribute( "", simpleNode.getNamespace(), simpleNode.getName(), value ); + writer.writeAttribute( simpleNode.getNamespace(), simpleNode.getName(), value ); } else { @@ -126,65 +127,57 @@ } else { - writeStartElement( simpleNode, writer ); + writeStartElement( simpleNode ); writer.writeCharacters( value ); - writeEndElement( writer ); - } - } - - private void writeComplexNode( ComplexNode complexNode, XMLStreamWriter writer ) throws XMLStreamException, IOException - { - writeStartElement( complexNode, writer ); - - for ( Node node : complexNode.getChildren() ) - { - dispatcher( node, writer ); - } - - writeEndElement( writer ); - } - - private void writeCollectionNode( CollectionNode collectionNode, XMLStreamWriter writer ) throws XMLStreamException, IOException - { - if ( collectionNode.isWrapping() ) - { - writeStartElement( collectionNode, writer ); - } - - for ( Node node : collectionNode.getChildren() ) - { - dispatcher( node, writer ); - } - - if ( collectionNode.isWrapping() ) - { - writeEndElement( writer ); - } - } - - private void dispatcher( Node node, XMLStreamWriter writer ) throws IOException, XMLStreamException + } + } + + @Override + protected void endWriteSimpleNode( SimpleNode simpleNode ) throws Exception + { + if ( !simpleNode.isAttribute() && simpleNode.getValue() != null ) + { + writer.writeEndElement(); + } + } + + @Override + protected void startWriteComplexNode( ComplexNode complexNode ) throws Exception + { + writeStartElement( complexNode ); + } + + @Override + protected void endWriteComplexNode( ComplexNode complexNode ) throws Exception + { + writer.writeEndElement(); + } + + @Override + protected void startWriteCollectionNode( CollectionNode collectionNode ) throws Exception + { + if ( collectionNode.isWrapping() ) + { + writeStartElement( collectionNode ); + } + } + + @Override + protected void endWriteCollectionNode( CollectionNode collectionNode ) throws Exception + { + if ( collectionNode.isWrapping() ) + { + writer.writeEndElement(); + } + } + + private void writeStartElement( Node node ) throws XMLStreamException { if ( !StringUtils.isEmpty( node.getComment() ) ) { writer.writeComment( node.getComment() ); } - switch ( node.getType() ) - { - case SIMPLE: - writeSimpleNode( (SimpleNode) node, writer ); - break; - case COMPLEX: - writeComplexNode( (ComplexNode) node, writer ); - break; - case COLLECTION: - writeCollectionNode( (CollectionNode) node, writer ); - break; - } - } - - private void writeStartElement( Node node, XMLStreamWriter writer ) throws XMLStreamException - { if ( !StringUtils.isEmpty( node.getNamespace() ) ) { writer.writeStartElement( node.getNamespace(), node.getName() ); @@ -194,9 +187,4 @@ writer.writeStartElement( node.getName() ); } } - - private void writeEndElement( XMLStreamWriter writer ) throws XMLStreamException - { - writer.writeEndElement(); - } } === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/SimpleNode.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/SimpleNode.java 2014-06-06 07:40:49 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/node/types/SimpleNode.java 2014-06-08 10:58:50 +0000 @@ -28,14 +28,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE */ -import com.google.common.collect.Lists; import org.hisp.dhis.node.AbstractNode; import org.hisp.dhis.node.Node; import org.hisp.dhis.node.NodeType; import org.hisp.dhis.node.exception.InvalidTypeException; -import java.util.List; - /** * @author Morten Olav Hansen */ @@ -52,12 +49,6 @@ this.attribute = false; } - public SimpleNode( String name, Object value, boolean attribute ) - { - this( name, value ); - this.attribute = attribute; - } - public Object getValue() { return value; === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/DefaultNodeService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/DefaultNodeService.java 2014-06-06 07:40:49 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/DefaultNodeService.java 2014-06-08 10:58:50 +0000 @@ -34,7 +34,6 @@ import org.springframework.beans.factory.annotation.Autowired; import javax.annotation.PostConstruct; -import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; @@ -45,10 +44,10 @@ */ public class DefaultNodeService implements NodeService { - @Autowired( required = false ) + @Autowired(required = false) private List nodeSerializers = Lists.newArrayList(); - @Autowired( required = false ) + @Autowired(required = false) private List nodeDeserializers = Lists.newArrayList(); private Map nodeSerializerMap = Maps.newHashMap(); @@ -87,7 +86,7 @@ } @Override - public void serialize( RootNode rootNode, String contentType, OutputStream outputStream ) throws IOException + public void serialize( RootNode rootNode, String contentType, OutputStream outputStream ) { NodeSerializer nodeSerializer = getNodeSerializer( contentType ); @@ -96,7 +95,14 @@ return; // TODO throw exception? } - nodeSerializer.serialize( rootNode, outputStream ); + try + { + nodeSerializer.serialize( rootNode, outputStream ); + } + catch ( Exception e ) + { + e.printStackTrace(); + } } @Override @@ -111,7 +117,7 @@ } @Override - public RootNode deserialize( String contentType, InputStream inputStream ) throws IOException + public RootNode deserialize( String contentType, InputStream inputStream ) { NodeDeserializer nodeDeserializer = getNodeDeserializer( contentType ); @@ -120,6 +126,15 @@ return null; // TODO throw exception? } - return nodeDeserializer.deserialize( inputStream ); + try + { + return nodeDeserializer.deserialize( inputStream ); + } + catch ( Exception e ) + { + e.printStackTrace(); + } + + return null; } }