/* * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.core.runtime.help.impl; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.TimeUnit; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter; import com.thoughtworks.xstream.converters.reflection.ReflectionProvider; import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver; import com.thoughtworks.xstream.mapper.Mapper; import org.drools.core.command.impl.ExecutableCommand; import org.drools.core.command.runtime.AdvanceSessionTimeCommand; import org.drools.core.command.runtime.BatchExecutionCommandImpl; import org.drools.core.command.runtime.GetGlobalCommand; import org.drools.core.command.runtime.GetSessionTimeCommand; import org.drools.core.command.runtime.SetGlobalCommand; import org.drools.core.command.runtime.process.AbortWorkItemCommand; import org.drools.core.command.runtime.process.CompleteWorkItemCommand; import org.drools.core.command.runtime.process.SignalEventCommand; import org.drools.core.command.runtime.process.StartProcessCommand; import org.drools.core.command.runtime.rule.DeleteCommand; import org.drools.core.command.runtime.rule.FireAllRulesCommand; import org.drools.core.command.runtime.rule.FireUntilHaltCommand; import org.drools.core.command.runtime.rule.GetObjectCommand; import org.drools.core.command.runtime.rule.GetObjectsCommand; import org.drools.core.command.runtime.rule.InsertElementsCommand; import org.drools.core.command.runtime.rule.InsertObjectCommand; import org.drools.core.command.runtime.rule.ModifyCommand; import org.drools.core.command.runtime.rule.QueryCommand; import org.drools.core.common.DefaultFactHandle; import org.drools.core.runtime.impl.ExecutionResultImpl; import org.drools.core.runtime.rule.impl.FlatQueryResults; import org.drools.core.util.StringUtils; import org.kie.api.command.Command; import org.kie.api.command.Setter; import org.kie.api.runtime.ExecutionResults; import org.kie.api.runtime.rule.FactHandle; import org.kie.api.runtime.rule.QueryResults; import org.kie.api.runtime.rule.QueryResultsRow; import org.kie.internal.command.CommandFactory; public class XStreamJSon { public static volatile boolean SORT_MAPS = false; public static XStream newJSonMarshaller() { JettisonMappedXmlDriver jet = new JettisonMappedXmlDriver(); XStream xstream = new XStream( jet ); XStreamHelper.setAliases( xstream ); xstream.alias( "commands", CommandsObjectContainer.class ); xstream.alias( "objects", ObjectsObjectContainer.class ); xstream.alias( "item", RowItemContainer.class ); xstream.alias( "parameters", ParameterContainer.class ); xstream.alias( "results", WorkItemResultsContainer.class ); xstream.setMode( XStream.NO_REFERENCES ); xstream.registerConverter( new JSonFactHandleConverter( xstream ) ); xstream.registerConverter( new JSonBatchExecutionResultConverter( xstream ) ); xstream.registerConverter( new JSonInsertConverter( xstream ) ); xstream.registerConverter( new JSonFireAllRulesConverter( xstream ) ); xstream.registerConverter( new JSonBatchExecutionCommandConverter( xstream ) ); xstream.registerConverter( new CommandsContainerConverter( xstream ) ); xstream.registerConverter( new JSonGetObjectConverter( xstream ) ); xstream.registerConverter( new JSonRetractConverter( xstream ) ); xstream.registerConverter( new JSonModifyConverter( xstream ) ); xstream.registerConverter( new JSonSetGlobalConverter( xstream ) ); xstream.registerConverter( new JSonInsertElementsConverter( xstream ) ); xstream.registerConverter( new JSonGetGlobalConverter( xstream ) ); xstream.registerConverter( new JSonGetObjectsConverter( xstream ) ); xstream.registerConverter( new JSonQueryConverter( xstream ) ); xstream.registerConverter( new JSonQueryResultsConverter( xstream ) ); xstream.registerConverter( new RowItemConverter( xstream ) ); xstream.registerConverter( new JSonStartProcessConvert( xstream ) ); xstream.registerConverter( new JSonSignalEventConverter( xstream ) ); xstream.registerConverter( new JSonCompleteWorkItemConverter( xstream ) ); xstream.registerConverter( new JSonAbortWorkItemConverter( xstream ) ); xstream.registerConverter( new JSonGetSessionTimeConverter( xstream ) ); xstream.registerConverter( new JSonAdvanceSessionTimeConverter( xstream ) ); return xstream; } public static class CommandsContainerConverter extends AbstractCollectionConverter { public CommandsContainerConverter(XStream xstream) { super( xstream.getMapper() ); } public boolean canConvert(Class type) { return CommandsObjectContainer.class.isAssignableFrom( type ); } @Override public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { CommandsObjectContainer container = (CommandsObjectContainer) object; writeItem( container.getContainedObject(), context, writer ); } @Override public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { throw new UnsupportedOperationException(); } } public static class RowItemConverter extends AbstractCollectionConverter { public RowItemConverter(XStream xstream) { super( xstream.getMapper() ); } public boolean canConvert(Class type) { return RowItemContainer.class.isAssignableFrom( type ); } @Override public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { RowItemContainer container = (RowItemContainer) object; writer.startNode( "identifier" ); writer.setValue( container.getIdentifier() ); writer.endNode(); writer.startNode( "external-form" ); writer.setValue( container.getFactHandle().toExternalForm() ); writer.endNode(); writer.startNode( "object" ); writeItem( container.getObject(), context, writer ); writer.endNode(); } @Override public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { String identifier = null; String externalForm = null; Object object = null; while ( reader.hasMoreChildren() ) { reader.moveDown(); String nodeName = reader.getNodeName(); if ( "identifier".equals( nodeName ) ) { identifier = reader.getValue(); } else if ( "external-form".equals( nodeName ) ) { externalForm = reader.getValue(); } else if ( "object".equals( nodeName ) ) { reader.moveDown(); object = readItem( reader, context, null ); reader.moveUp(); } reader.moveUp(); } return new RowItemContainer( identifier, DefaultFactHandle.createFromExternalFormat( externalForm ), object ); } } public static class JSonBatchExecutionCommandConverter extends AbstractCollectionConverter implements Converter { public JSonBatchExecutionCommandConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { BatchExecutionCommandImpl cmds = (BatchExecutionCommandImpl) object; if ( cmds.getLookup() != null ) { writer.startNode( "lookup" ); writer.setValue( cmds.getLookup() ); writer.endNode(); } for ( Command cmd : cmds.getCommands() ) { writeItem( new CommandsObjectContainer( cmd ), context, writer ); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { List<Command> list = new ArrayList<Command>(); String lookup = null; while ( reader.hasMoreChildren() ) { reader.moveDown(); if ( "commands".equals( reader.getNodeName() ) ) { while ( reader.hasMoreChildren() ) { reader.moveDown(); ExecutableCommand cmd = (ExecutableCommand) readItem( reader, context, null ); list.add( cmd ); reader.moveUp(); } } else if ( "lookup".equals( reader.getNodeName() ) ) { lookup = reader.getValue(); } else { throw new IllegalArgumentException( "batch-execution does not support the child element name=''" + reader.getNodeName() + "' value=" + reader.getValue() + "'" ); } reader.moveUp(); } return new BatchExecutionCommandImpl( list, lookup ); } public boolean canConvert(Class clazz) { return clazz.equals( BatchExecutionCommandImpl.class ); } } public static class JSonInsertConverter extends BaseConverter implements Converter { public JSonInsertConverter(XStream xstream) { super( xstream ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { InsertObjectCommand cmd = (InsertObjectCommand) object; if ( cmd.getOutIdentifier() != null ) { writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); writer.startNode( "return-object" ); writer.setValue( Boolean.toString( cmd.isReturnObject() ) ); writer.endNode(); } if ( !StringUtils.isEmpty( cmd.getEntryPoint() ) ) { writer.startNode( "entry-point" ); writer.setValue( cmd.getEntryPoint() ); writer.endNode(); } writeValue( writer, context, "object", cmd.getObject() ); } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { InsertObjectCommand cmd = new InsertObjectCommand(); while ( reader.hasMoreChildren() ) { reader.moveDown(); String nodeName = reader.getNodeName(); if ( "out-identifier".equals( nodeName ) ) { cmd.setOutIdentifier( reader.getValue() ); } else if ( "return-object".equals( nodeName ) ) { cmd.setReturnObject( Boolean.parseBoolean( reader.getValue() ) ); } else if ( "object".equals( nodeName ) ) { cmd.setObject( readValue( reader, context, cmd.getObject(), "object" ) ); } else if ( "entry-point".equals( nodeName ) ) { cmd.setEntryPoint( reader.getValue() ); } reader.moveUp(); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( InsertObjectCommand.class ); } } public static class JSonFactHandleConverter extends AbstractCollectionConverter implements Converter { public JSonFactHandleConverter(XStream xstream) { super( xstream.getMapper() ); } public boolean canConvert(Class aClass) { return FactHandle.class.isAssignableFrom( aClass ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext marshallingContext) { FactHandle fh = (FactHandle) object; writer.startNode( "external-form" ); writer.setValue( fh.toExternalForm() ); writer.endNode(); } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext unmarshallingContext) { reader.moveDown(); DefaultFactHandle factHandle = DefaultFactHandle.createFromExternalFormat( reader.getValue() ); reader.moveUp(); return factHandle; } } public static class JSonFireAllRulesConverter extends AbstractCollectionConverter implements Converter { public JSonFireAllRulesConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { FireAllRulesCommand cmd = (FireAllRulesCommand) object; if ( cmd.getMax() != -1 ) { writer.startNode( "max" ); writer.setValue( Integer.toString( cmd.getMax() ) ); writer.endNode(); } if ( cmd.getOutIdentifier() != null ) { writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { String max = null; String outIdentifier = null; while ( reader.hasMoreChildren() ) { reader.moveDown(); if ( "max".equals( reader.getNodeName() ) ) { max = reader.getValue(); } else if ( "out-identifier".equals( reader.getNodeName() ) ) { outIdentifier = reader.getValue(); } else { throw new IllegalArgumentException( "fire-all-rules does not support the child element name=''" + reader.getNodeName() + "' value=" + reader.getValue() + "'" ); } reader.moveUp(); } FireAllRulesCommand cmd; if ( max != null ) { cmd = new FireAllRulesCommand( Integer.parseInt( max ) ); } else { cmd = new FireAllRulesCommand(); } if ( outIdentifier != null ) { cmd.setOutIdentifier(outIdentifier); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( FireAllRulesCommand.class ); } } public static class JSonFireUntilHaltConverter extends AbstractCollectionConverter implements Converter { public JSonFireUntilHaltConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { if ( reader.hasMoreChildren() ) { throw new IllegalArgumentException( "fire-until-halt does not support the child element name=''" + reader.getNodeName() + "' value=" + reader.getValue() + "'" ); } return new FireAllRulesCommand(); } public boolean canConvert(Class clazz) { return clazz.equals( FireUntilHaltCommand.class ); } } public static class JSonGetObjectConverter extends AbstractCollectionConverter implements Converter { public JSonGetObjectConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { GetObjectCommand cmd = (GetObjectCommand) object; writer.startNode( "fact-handle" ); writer.setValue( cmd.getFactHandle().toExternalForm() ); writer.endNode(); if ( cmd.getOutIdentifier() != null ) { writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { FactHandle factHandle = null; String outIdentifier = null; while ( reader.hasMoreChildren() ) { reader.moveDown(); String name = reader.getNodeName(); if ( "fact-handle".equals( name ) ) { factHandle = DefaultFactHandle.createFromExternalFormat( reader.getValue() ); } else if ( "out-identifier".equals( name ) ) { outIdentifier = reader.getValue(); } reader.moveUp(); } GetObjectCommand cmd = new GetObjectCommand( factHandle ); if ( outIdentifier != null ) { cmd.setOutIdentifier( outIdentifier ); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( GetObjectCommand.class ); } } public static class JSonRetractConverter extends AbstractCollectionConverter implements Converter { public JSonRetractConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { DeleteCommand cmd = (DeleteCommand) object; writer.startNode( "fact-handle" ); writer.setValue( cmd.getFactHandle().toExternalForm() ); writer.endNode(); } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { reader.moveDown(); FactHandle factHandle = DefaultFactHandle.createFromExternalFormat( reader.getValue() ); reader.moveUp(); return CommandFactory.newDelete(factHandle); } public boolean canConvert(Class clazz) { return clazz.equals( DeleteCommand.class ); } } public static class JSonModifyConverter extends AbstractCollectionConverter implements Converter { public JSonModifyConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { ModifyCommand cmd = (ModifyCommand) object; writer.startNode( "fact-handle" ); writer.setValue( cmd.getFactHandle().toExternalForm() ); writer.endNode(); List<Setter> setters = cmd.getSetters(); for ( Setter setter : setters ) { writeItem( setter, context, writer ); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { reader.moveDown(); FactHandle factHandle = DefaultFactHandle.createFromExternalFormat( reader.getValue() ); reader.moveUp(); List<Setter> setters = new ArrayList<Setter>(); while ( reader.hasMoreChildren() ) { reader.moveDown(); reader.moveDown(); String accessor = reader.getValue(); reader.moveUp(); reader.moveDown(); String value = reader.getValue(); reader.moveUp(); Setter setter = CommandFactory.newSetter( accessor, value ); setters.add( setter ); reader.moveUp(); } return CommandFactory.newModify( factHandle, setters ); } public boolean canConvert(Class clazz) { return clazz.equals( ModifyCommand.class ); } } public static class JSonInsertElementsConverter extends AbstractCollectionConverter implements Converter { public JSonInsertElementsConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { InsertElementsCommand cmd = (InsertElementsCommand) object; if ( cmd.getOutIdentifier() != null ) { writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); writer.startNode( "return-objects" ); writer.setValue( Boolean.toString( cmd.isReturnObject() ) ); writer.endNode(); } if ( !StringUtils.isEmpty( cmd.getEntryPoint() ) ) { writer.startNode( "entry-point" ); writer.setValue( cmd.getEntryPoint() ); writer.endNode(); } for ( Object element : cmd.getObjects() ) { writeItem( new ObjectsObjectContainer( element ), context, writer ); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { List<Object> objects = new ArrayList<Object>(); String outIdentifier = null; String returnObjects = null; String entryPoint = null; while ( reader.hasMoreChildren() ) { reader.moveDown(); String nodeName = reader.getNodeName(); if ( "objects".equals( nodeName ) ) { while ( reader.hasMoreChildren() ) { reader.moveDown(); Object o = readItem( reader, context, null ); objects.add( o ); reader.moveUp(); } } else if ( "out-identifier".equals( nodeName ) ) { outIdentifier = reader.getValue(); } else if ( "return-objects".equals( nodeName ) ) { returnObjects = reader.getValue(); } else if ( "entry-point".equals( nodeName ) ) { entryPoint = reader.getValue(); } else { throw new IllegalArgumentException( "insert-elements does not support the child element name=''" + reader.getNodeName() + "' value=" + reader.getValue() + "'" ); } reader.moveUp(); } InsertElementsCommand cmd = new InsertElementsCommand( objects ); if ( outIdentifier != null ) { cmd.setOutIdentifier( outIdentifier ); if ( returnObjects != null ) { cmd.setReturnObject( Boolean.parseBoolean( returnObjects ) ); } } if ( entryPoint != null ) { cmd.setEntryPoint( entryPoint ); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( InsertElementsCommand.class ); } } public static class JSonBatchExecutionResultConverter extends AbstractCollectionConverter implements Converter { public JSonBatchExecutionResultConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { ExecutionResults result = (ExecutionResults) object; writer.startNode( "results" ); if ( !result.getIdentifiers().isEmpty() ) { Collection<String> identifiers = result.getIdentifiers(); // this gets sorted, otherwise unit tests will not pass if ( SORT_MAPS ) { String[] array = identifiers.toArray( new String[identifiers.size()]); Arrays.sort(array); identifiers = Arrays.asList(array); } for ( String identifier : identifiers ) { writer.startNode( "result" ); writer.startNode( "identifier" ); writer.setValue( identifier ); writer.endNode(); writer.startNode( "value" ); Object value = result.getValue( identifier ); if ( value instanceof org.kie.api.runtime.rule.QueryResults ) { String name = mapper().serializedClass(FlatQueryResults.class); ExtendedHierarchicalStreamWriterHelper.startNode(writer, name, FlatQueryResults.class); context.convertAnother(value); writer.endNode(); } else { writeItem( value, context, writer ); } writer.endNode(); writer.endNode(); } } Collection<String> handles = ((ExecutionResultImpl) result).getFactHandles().keySet(); // this gets sorted, otherwise unit tests will not pass if (SORT_MAPS) { String[] array = handles.toArray( new String[handles.size()]); Arrays.sort(array); handles = Arrays.asList(array); } for ( String identifier : handles ) { Object handle = result.getFactHandle( identifier ); if ( handle instanceof FactHandle ) { writer.startNode( "fact-handle" ); writer.startNode( "identifier" ); writer.setValue( identifier ); writer.endNode(); writer.startNode( "external-form" ); writer.setValue( ((FactHandle) handle).toExternalForm() ); writer.endNode(); writer.endNode(); } else if ( handle instanceof Collection ) { writer.startNode( "fact-handles" ); writer.startNode( "identifier" ); writer.setValue( identifier ); writer.endNode(); //writer.startNode( "xxx" ); for ( FactHandle factHandle : (Collection<FactHandle>) handle ) { writeItem( factHandle.toExternalForm(), context, writer ); } //writer.endNode(); writer.endNode(); } } writer.endNode(); } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { ExecutionResultImpl result = new ExecutionResultImpl(); Map<String, Object> results = result.getResults(); Map<String, Object> facts = result.getFactHandles(); reader.moveDown(); if ( "results".equals( reader.getNodeName() ) ) { while ( reader.hasMoreChildren() ) { reader.moveDown(); if ( reader.getNodeName().equals( "result" ) ) { reader.moveDown(); String identifier = reader.getValue(); reader.moveUp(); reader.moveDown(); reader.moveDown(); Object value = readItem( reader, context, null ); results.put( identifier, value ); reader.moveUp(); reader.moveUp(); } else if ( reader.getNodeName().equals( "fact-handle" ) ) { reader.moveDown(); String identifier = reader.getValue(); reader.moveUp(); reader.moveDown(); String externalForm = reader.getValue(); reader.moveUp(); facts.put( identifier, DefaultFactHandle.createFromExternalFormat( externalForm ) ); } else if ( reader.getNodeName().equals( "fact-handles" ) ) { List<FactHandle> list = new ArrayList<FactHandle>(); String identifier = null; while ( reader.hasMoreChildren() ) { reader.moveDown(); identifier = reader.getValue(); reader.moveUp(); while ( reader.hasMoreChildren() ) { reader.moveDown(); FactHandle factHandle = DefaultFactHandle.createFromExternalFormat( (String) readItem( reader, context, null ) ); list.add( factHandle ); reader.moveUp(); } } facts.put( identifier, list ); } else { throw new IllegalArgumentException( "Element '" + reader.getNodeName() + "' is not supported here" ); } reader.moveUp(); } } else { throw new IllegalArgumentException( "Element '" + reader.getNodeName() + "' is not supported here" ); } reader.moveUp(); return result; } public boolean canConvert(Class clazz) { return ExecutionResults.class.isAssignableFrom( clazz ); } } public static abstract class BaseConverter { protected Mapper mapper; protected ReflectionProvider reflectionProvider; public BaseConverter(XStream xstream) { this.mapper = xstream.getMapper(); this.reflectionProvider = xstream.getReflectionProvider(); } protected void writeValue(HierarchicalStreamWriter writer, MarshallingContext context, String fieldName, Object object) { writer.startNode( fieldName ); String name = this.mapper.serializedClass( object.getClass() ); ExtendedHierarchicalStreamWriterHelper.startNode( writer, name, Mapper.Null.class ); context.convertAnother( object ); writer.endNode(); writer.endNode(); } protected Object readValue(HierarchicalStreamReader reader, UnmarshallingContext context, Object object, Object fieldName) { reader.moveDown(); Class type = readClassType( reader, this.mapper); Object o = context.convertAnother( null, type ); reader.moveUp(); return o; } // methods borrowed directly from com.thoughtworks.xstream.core.util.HierarchicalStreams to make sure we don't // depend on that package (it is XStream internal package and using it causes issues in OSGi) // see https://issues.jboss.org/browse/DROOLS-558 for more details private Class readClassType( HierarchicalStreamReader reader, Mapper mapper ) { String classAttribute = readClassAttribute( reader, mapper ); Class type; if ( classAttribute == null ) { type = mapper.realClass( reader.getNodeName() ); } else { type = mapper.realClass( classAttribute ); } return type; } private String readClassAttribute( HierarchicalStreamReader reader, Mapper mapper ) { String attributeName = mapper.aliasForSystemAttribute( "resolves-to" ); String classAttribute = attributeName == null ? null : reader.getAttribute( attributeName ); if (classAttribute == null) { attributeName = mapper.aliasForSystemAttribute( "class" ); if (attributeName != null) { classAttribute = reader.getAttribute( attributeName ); } } return classAttribute; } } public static class JSonSetGlobalConverter extends BaseConverter implements Converter { public JSonSetGlobalConverter(XStream xstream) { super( xstream ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { SetGlobalCommand cmd = (SetGlobalCommand) object; writer.startNode( "identifier" ); writer.setValue( cmd.getIdentifier() ); writer.endNode(); if ( cmd.getOutIdentifier() != null ) { writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); } writeValue( writer, context, "object", cmd.getObject() ); } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { String identifier = null; boolean out = false; String outIdentifier = null; SetGlobalCommand cmd = new SetGlobalCommand(); while ( reader.hasMoreChildren() ) { reader.moveDown(); String nodeName = reader.getNodeName(); if ( "identifier".equals( nodeName ) ) { identifier = reader.getValue(); } else if ( "out".equals( nodeName ) ) { out = Boolean.valueOf(reader.getValue()); } else if ( "out-identifier".equals( nodeName ) ) { outIdentifier = reader.getValue(); } else if ( "object".equals( nodeName ) ) { cmd.setObject( readValue( reader, context, cmd.getObject(), "object" ) ); } reader.moveUp(); } cmd.setIdentifier( identifier ); if ( outIdentifier != null ) { cmd.setOutIdentifier( outIdentifier ); } else if (out) { cmd.setOutIdentifier( identifier ); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( SetGlobalCommand.class ); } } public static class JSonGetGlobalConverter extends BaseConverter implements Converter { public JSonGetGlobalConverter(XStream xstream) { super( xstream ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { GetGlobalCommand cmd = (GetGlobalCommand) object; writer.startNode( "identifier" ); writer.setValue( cmd.getIdentifier() ); writer.endNode(); if ( cmd.getOutIdentifier() != null ) { writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { String identifier = null; String outIdentifier = null; GetGlobalCommand cmd = new GetGlobalCommand(); while ( reader.hasMoreChildren() ) { reader.moveDown(); String nodeName = reader.getNodeName(); if ( "identifier".equals( nodeName ) ) { identifier = reader.getValue(); } else if ( "out-identifier".equals( nodeName ) ) { outIdentifier = reader.getValue(); } reader.moveUp(); } cmd.setIdentifier( identifier ); if ( outIdentifier != null ) { cmd.setOutIdentifier( outIdentifier ); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( GetGlobalCommand.class ); } } public static class JSonGetObjectsConverter extends AbstractCollectionConverter implements Converter { public JSonGetObjectsConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { GetObjectsCommand cmd = (GetObjectsCommand) object; if ( cmd.getOutIdentifier() != null ) { writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { String outIdentifier = null; while ( reader.hasMoreChildren() ) { reader.moveDown(); if ( "out-identifier".equals( reader.getNodeName() ) ) { outIdentifier = reader.getValue(); } reader.moveUp(); } GetObjectsCommand cmd = new GetObjectsCommand(); if ( outIdentifier != null ) { cmd.setOutIdentifier( outIdentifier ); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( GetObjectsCommand.class ); } } public static class JSonQueryConverter extends AbstractCollectionConverter implements Converter { public JSonQueryConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { QueryCommand cmd = (QueryCommand) object; writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); writer.startNode( "name" ); writer.setValue( cmd.getName() ); writer.endNode(); if ( cmd.getArguments() != null && cmd.getArguments().size() > 0 ) { writer.startNode( "args" ); for ( Object arg : cmd.getArguments() ) { writeItem( arg, context, writer ); } writer.endNode(); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { String outIdentifier = null; String name = null; List<Object> args = null; while ( reader.hasMoreChildren() ) { reader.moveDown(); String nodeName = reader.getNodeName(); if ( "out-identifier".equals( nodeName ) ) { outIdentifier = reader.getValue(); } else if ( "name".equals( nodeName ) ) { name = reader.getValue(); } else if ( "args".equals( nodeName ) ) { args = new ArrayList<Object>(); while ( reader.hasMoreChildren() ) { reader.moveDown(); Object arg = readItem( reader, context, null ); args.add( arg ); reader.moveUp(); } } reader.moveUp(); } return new QueryCommand( outIdentifier, name, (args != null) ? args.toArray( new Object[args.size()] ) : null ); } public boolean canConvert(Class clazz) { return clazz.equals( QueryCommand.class ); } } public static class JSonQueryResultsConverter extends AbstractCollectionConverter implements Converter { public JSonQueryResultsConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { QueryResults results = (QueryResults) object; // write out identifiers String[] identifiers = results.getIdentifiers(); writer.startNode( "identifiers" ); for ( String identifier : identifiers ) { writeItem( identifier, context, writer ); } writer.endNode(); for ( QueryResultsRow result : results ) { writer.startNode( "row" ); for ( String identifier : identifiers ) { Object value = result.get( identifier ); FactHandle factHandle = result.getFactHandle( identifier ); writeItem( new RowItemContainer( identifier, factHandle, value), context, writer ); } writer.endNode(); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { reader.moveDown(); Set<String> identifiers = new TreeSet<String>(); while ( reader.hasMoreChildren() ) { reader.moveDown(); identifiers.add( (String) readItem( reader, context, null ) ); reader.moveUp(); } reader.moveUp(); ArrayList<Map<String, Object>> idResults = new ArrayList<Map<String,Object>>(); ArrayList<Map<String, FactHandle>> idHandles = new ArrayList<Map<String, FactHandle>>(); while ( reader.hasMoreChildren() ) { reader.moveDown(); Map<String, Object> idResultMap = new HashMap<String, Object>(); Map<String, FactHandle> idFactHandleMap = new HashMap<String, FactHandle>(); while ( reader.hasMoreChildren() ) { reader.moveDown(); RowItemContainer container = (RowItemContainer) readItem( reader, context, null ); String id = container.getIdentifier(); idResultMap.put(id, container.getObject()); idFactHandleMap.put(id, container.getFactHandle()); reader.moveUp(); } idResults.add( idResultMap ); idHandles.add( idFactHandleMap ); reader.moveUp(); } return new FlatQueryResults( identifiers, idHandles, idResults ); } public boolean canConvert(Class clazz) { return QueryResults.class.isAssignableFrom( clazz ); } } public static class JSonStartProcessConvert extends AbstractCollectionConverter implements Converter { public JSonStartProcessConvert(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { StartProcessCommand cmd = (StartProcessCommand) object; writer.startNode( "process-id" ); writer.setValue( cmd.getProcessId() ); writer.endNode(); if ( cmd.getOutIdentifier() != null ) { writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); } for ( Entry<String, Object> entry : cmd.getParameters().entrySet() ) { writeItem( new ParameterContainer( entry.getKey(), entry.getValue() ), context, writer ); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { reader.moveDown(); String processId = reader.getValue(); reader.moveUp(); String outIdentifier = null; HashMap<String, Object> params = new HashMap<String, Object>(); while ( reader.hasMoreChildren() ) { reader.moveDown(); if ( "parameters".equals( reader.getNodeName() ) ) { ParameterContainer parameterContainer = (ParameterContainer) readItem( reader, context, null ); params.put( parameterContainer.getIdentifier(), parameterContainer.getObject() ); } else if ( "out-identifier".equals( reader.getNodeName() ) ) { outIdentifier = reader.getValue(); } else { throw new IllegalArgumentException( "start-process does not support the child element name=''" + reader.getNodeName() + "' value=" + reader.getValue() + "'" ); } reader.moveUp(); } StartProcessCommand cmd = new StartProcessCommand(); cmd.setProcessId( processId ); cmd.setParameters( params ); if ( outIdentifier != null ) { cmd.setOutIdentifier( outIdentifier ); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( StartProcessCommand.class ); } } public static class JSonSignalEventConverter extends AbstractCollectionConverter implements Converter { public JSonSignalEventConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { SignalEventCommand cmd = (SignalEventCommand) object; long processInstanceId = cmd.getProcessInstanceId(); String eventType = cmd.getEventType(); Object event = cmd.getEvent(); if ( processInstanceId != -1 ) { writer.startNode( "process-instance-id" ); writer.setValue( Long.toString( processInstanceId ) ); writer.endNode(); } writer.addAttribute( "event-type", eventType ); writer.startNode( "event-type" ); writer.setValue( eventType ); writer.endNode(); writer.startNode( "object" ); writeItem( event, context, writer ); writer.endNode(); } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { String processInstanceId = null; String eventType = null; Object event = null; while ( reader.hasMoreChildren() ) { reader.moveDown(); String nodeName = reader.getNodeName(); if ( "process-instance-id".equals( nodeName ) ) { processInstanceId = reader.getValue(); } else if ( "event-type".equals( nodeName ) ) { eventType = reader.getValue(); } else if ( "object".equals( nodeName ) ) { reader.moveDown(); event = readItem( reader, context, null ); reader.moveUp(); } reader.moveUp(); } Command cmd; if ( processInstanceId != null ) { cmd = CommandFactory.newSignalEvent( Long.parseLong( processInstanceId ), eventType, event ); } else { cmd = CommandFactory.newSignalEvent( eventType, event ); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( SignalEventCommand.class ); } } public static class JSonCompleteWorkItemConverter extends AbstractCollectionConverter implements Converter { public JSonCompleteWorkItemConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { CompleteWorkItemCommand cmd = (CompleteWorkItemCommand) object; writer.startNode( "id" ); writer.setValue( Long.toString( cmd.getWorkItemId() ) ); writer.endNode(); for ( Entry<String, Object> entry : cmd.getResults().entrySet() ) { writeItem( new WorkItemResultsContainer( entry.getKey(), entry.getValue() ), context, writer ); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { String id = null; Map<String, Object> results = new HashMap<String, Object>(); while ( reader.hasMoreChildren() ) { reader.moveDown(); String nodeName = reader.getNodeName(); if ( "id".equals( nodeName ) ) { id = reader.getValue(); } else if ( "results".equals( nodeName ) ) { while ( reader.hasMoreChildren() ) { WorkItemResultsContainer res = (WorkItemResultsContainer) readItem( reader, context, null ); results.put( res.getIdentifier(), res.getObject() ); } } reader.moveUp(); } return new CompleteWorkItemCommand( Long.parseLong( id ), results ); } public boolean canConvert(Class clazz) { return clazz.equals( CompleteWorkItemCommand.class ); } } public static class JSonAbortWorkItemConverter extends AbstractCollectionConverter implements Converter { public JSonAbortWorkItemConverter(XStream xstream) { super( xstream.getMapper() ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { AbortWorkItemCommand cmd = (AbortWorkItemCommand) object; writer.startNode( "id" ); writer.setValue( Long.toString( cmd.getWorkItemId() ) ); writer.endNode(); } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { reader.moveDown(); String id = reader.getValue(); reader.moveUp(); return CommandFactory.newAbortWorkItem( Long.parseLong( id ) ); } public boolean canConvert(Class clazz) { return clazz.equals( AbortWorkItemCommand.class ); } } public static class JSonGetSessionTimeConverter extends BaseConverter implements Converter { public JSonGetSessionTimeConverter(XStream xstream) { super( xstream ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { GetSessionTimeCommand cmd = (GetSessionTimeCommand) object; if ( cmd.getOutIdentifier() != null ) { writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { GetSessionTimeCommand cmd = new GetSessionTimeCommand(); while ( reader.hasMoreChildren() ) { reader.moveDown(); String nodeName = reader.getNodeName(); if ( "out-identifier".equals( nodeName ) ) { cmd.setOutIdentifier( reader.getValue() ); } reader.moveUp(); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( GetSessionTimeCommand.class ); } } public static class JSonAdvanceSessionTimeConverter extends BaseConverter implements Converter { public JSonAdvanceSessionTimeConverter(XStream xstream) { super( xstream ); } public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { AdvanceSessionTimeCommand cmd = (AdvanceSessionTimeCommand) object; if ( cmd.getOutIdentifier() != null ) { writer.startNode( "out-identifier" ); writer.setValue( cmd.getOutIdentifier() ); writer.endNode(); } writer.startNode( "amount" ); writer.setValue( "" + cmd.getAmount() ); writer.endNode(); writer.startNode( "unit" ); writer.setValue( "" + cmd.getUnit() ); writer.endNode(); } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { AdvanceSessionTimeCommand cmd = new AdvanceSessionTimeCommand(); while ( reader.hasMoreChildren() ) { reader.moveDown(); String nodeName = reader.getNodeName(); if ( "out-identifier".equals( nodeName ) ) { cmd.setOutIdentifier( reader.getValue() ); } else if ( "amount".equals( nodeName ) ) { cmd.setAmount( Long.parseLong( reader.getAttribute( "amount" ) ) ); } else if ( "unit".equals( nodeName ) ) { cmd.setUnit( TimeUnit.valueOf( reader.getAttribute( "unit" ).toUpperCase() ) ); } reader.moveUp(); } return cmd; } public boolean canConvert(Class clazz) { return clazz.equals( AdvanceSessionTimeCommand.class ); } } }