Skip to content

Commit

Permalink
Merge branch 'GAMA_1.8.2' of https://github.com/gama-platform/gama in…
Browse files Browse the repository at this point in the history
…to GAMA_1.8.2
  • Loading branch information
agrignard committed May 8, 2022
2 parents a5409dd + c120ae7 commit 9183c43
Show file tree
Hide file tree
Showing 13 changed files with 209 additions and 29 deletions.
1 change: 1 addition & 0 deletions msi.gama.core/META-INF/MANIFEST.MF
Expand Up @@ -266,6 +266,7 @@ Export-Package: msi.gama.common,
msi.gaml.types",
msi.gama.util.path,
msi.gama.util.random,
msi.gama.util.serialize,
msi.gama.util.tree,
msi.gaml.architecture;
uses:="msi.gaml.species,
Expand Down
124 changes: 113 additions & 11 deletions msi.gama.core/src/msi/gama/util/file/json/Jsoner.java
Expand Up @@ -15,13 +15,38 @@
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

import org.geotools.data.DataUtilities;
import org.geotools.feature.SchemaException;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import msi.gama.common.interfaces.IKeyword;
import msi.gama.metamodel.agent.IAgent;
import msi.gama.metamodel.population.IPopulation;
import msi.gama.metamodel.shape.IShape;
import msi.gama.metamodel.topology.projection.IProjection;
import msi.gama.runtime.IScope;
import msi.gama.runtime.exceptions.GamaRuntimeException;
import msi.gama.util.GamaColor;
import msi.gama.util.GamaListFactory;
import msi.gama.util.GamaMapFactory;
import msi.gama.util.serialize.IStreamConverter;
import msi.gaml.descriptions.SpeciesDescription;
import msi.gaml.expressions.IExpression;
import msi.gaml.statements.SaveStatement;

/**
* Jsoner provides JSON utilities for escaping strings to be JSON compatible, thread safe parsing (RFC 4627) JSON
* strings, and serializing data to strings in JSON format.
Expand All @@ -41,6 +66,8 @@ private enum DeserializationOptions {
/** Whether a JsonObject can be deserialized as a root element. */
ALLOW_JSON_OBJECTS;
}

public static IStreamConverter streamConverter;

/** Flags to tweak the behavior of the primary serialization method. */
private enum SerializationOptions {
Expand Down Expand Up @@ -717,7 +744,17 @@ private static void serialize(final Object jsonSerializable, final Writer writab
writableDestination.write(jsonSerializable.toString());
} else if (jsonSerializable instanceof Boolean) {
writableDestination.write(jsonSerializable.toString());
} else if (jsonSerializable instanceof Map) {
} else if (jsonSerializable instanceof GamaColor) {
GamaColor col = (GamaColor) jsonSerializable;
writableDestination.write('{');
writableDestination.write('"'+"r"+'"'+":");
Jsoner.serialize(col.red(), writableDestination, flags);
writableDestination.write("," + '"'+"g"+'"'+":");
Jsoner.serialize(col.blue(), writableDestination, flags);
writableDestination.write("," + '"'+"b"+'"'+":");
Jsoner.serialize(col.green(), writableDestination, flags);
writableDestination.write('}');
} else if (jsonSerializable instanceof Map) {
/* Writes the map in JSON object format. */
boolean isFirstEntry = true;
@SuppressWarnings ("rawtypes") final Iterator entries = ((Map) jsonSerializable).entrySet().iterator();
Expand Down Expand Up @@ -874,21 +911,86 @@ private static void serialize(final Object jsonSerializable, final Writer writab
}
}
writableDestination.write(']');
} else if (jsonSerializable instanceof IAgent) {
IAgent agent = (IAgent) jsonSerializable;
final SpeciesDescription species = agent.getSpecies().getDescription();

writableDestination.write('{');
writableDestination.write('"'+"species"+'"'+":");
Jsoner.serialize(species.getSpeciesExpr().getName(), writableDestination, flags);

for (final String var : species.getAttributeNames()) {
if (!NON_JSONABLE_ATTRIBUTE_NAMES.contains(var)) {
writableDestination.write(',');
writableDestination.write('"'+var+'"');
writableDestination.write(":");

Object attrValue = species.getVarExpr(var, false).value(agent.getScope()) ;
if(attrValue instanceof IAgent) {
Jsoner.serialize(((IAgent) attrValue).getName(), writableDestination, flags);
} else {
Jsoner.serialize(attrValue, writableDestination, flags);
}
}
}
writableDestination.write('}');

} else if (jsonSerializable instanceof IShape) {
IShape agentOrIShape = (IShape) jsonSerializable;
final StringBuilder specs = new StringBuilder(1 * 20);
final String geomType = SaveStatement.getGeometryType(Arrays.asList( agentOrIShape ));
specs.append("geometry:" + geomType);
try {
final SimpleFeatureType type = DataUtilities.createType("geojson", specs.toString());
final SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
final SimpleFeature ff = builder.buildFeature("");

SaveStatement.buildFeature(null, ff, agentOrIShape, null, Collections.EMPTY_LIST);

final FeatureJSON io = new FeatureJSON(new GeometryJSON(20));
writableDestination.write(io.toString(ff));
} catch (final ClassCastException e) {
e.printStackTrace();
} catch (SchemaException e) {
e.printStackTrace();
}
} else {
/* It cannot by any measure be safely serialized according to specification. */
if (flags.contains(SerializationOptions.ALLOW_INVALIDS)) {
/* Can be helpful for debugging how it isn't valid. */
writableDestination.write(jsonSerializable.toString());
} else {
/* Notify the caller the cause of failure for the serialization. */
throw new IllegalArgumentException("Encountered a: " + jsonSerializable.getClass().getName() + " as: "
+ jsonSerializable.toString()
+ " that isn't JSON serializable.\n Try:\n 1) Implementing the Jsonable interface for the object to return valid JSON. If it already does it probably has a bug.\n 2) If you cannot edit the source of the object or couple it with this library consider wrapping it in a class that does implement the Jsonable interface.\n 3) Otherwise convert it to a boolean, null, number, JsonArray, JsonObject, or String value before serializing it.\n 4) If you feel it should have serialized you could use a more tolerant serialization for debugging purposes.");
try {
writableDestination.write(streamConverter.convertObjectToJSONStream(null,jsonSerializable));
} catch(Exception e) {
/* It cannot by any measure be safely serialized according to specification. */
if (flags.contains(SerializationOptions.ALLOW_INVALIDS)) {
/* Can be helpful for debugging how it isn't valid. */
writableDestination.write(jsonSerializable.toString());
} else {
/* Notify the caller the cause of failure for the serialization. */
throw new IllegalArgumentException("Encountered a: " + jsonSerializable.getClass().getName() + " as: "
+ jsonSerializable.toString()
+ " that isn't JSON serializable.\n Try:\n 1) Implementing the Jsonable interface for the object to return valid JSON. If it already does it probably has a bug.\n 2) If you cannot edit the source of the object or couple it with this library consider wrapping it in a class that does implement the Jsonable interface.\n 3) Otherwise convert it to a boolean, null, number, JsonArray, JsonObject, or String value before serializing it.\n 4) If you feel it should have serialized you could use a more tolerant serialization for debugging purposes.");
}
}
}
// System.out.println(writableDestination.toString());

// else {
// /* It cannot by any measure be safely serialized according to specification. */
// if (flags.contains(SerializationOptions.ALLOW_INVALIDS)) {
// /* Can be helpful for debugging how it isn't valid. */
// writableDestination.write(jsonSerializable.toString());
// } else {
// /* Notify the caller the cause of failure for the serialization. */
// throw new IllegalArgumentException("Encountered a: " + jsonSerializable.getClass().getName() + " as: "
// + jsonSerializable.toString()
// + " that isn't JSON serializable.\n Try:\n 1) Implementing the Jsonable interface for the object to return valid JSON. If it already does it probably has a bug.\n 2) If you cannot edit the source of the object or couple it with this library consider wrapping it in a class that does implement the Jsonable interface.\n 3) Otherwise convert it to a boolean, null, number, JsonArray, JsonObject, or String value before serializing it.\n 4) If you feel it should have serialized you could use a more tolerant serialization for debugging purposes.");
// }
// }
// System.out.println(writableDestination.toString());
}

/** The Constant NON_SAVEABLE_ATTRIBUTE_NAMES. */
private static final Set<String> NON_JSONABLE_ATTRIBUTE_NAMES = new HashSet<>(Arrays.asList(IKeyword.PEERS,
IKeyword.HOST, IKeyword.AGENTS, IKeyword.MEMBERS));


/**
* Serializes like the first version of this library. It has been adapted to use Jsonable for serializing custom
* objects, but otherwise works like the old JSON string serializer. It will allow non-JSON values in its output
Expand Down
@@ -0,0 +1,7 @@
package msi.gama.util.serialize;

import msi.gama.runtime.IScope;

public interface IStreamConverter {
abstract String convertObjectToJSONStream(final IScope scope, final Object o);
}
2 changes: 1 addition & 1 deletion msi.gama.core/src/msi/gaml/statements/SaveStatement.java
Expand Up @@ -1113,7 +1113,7 @@ public String toCleanString(final Object o) {
* the var
* @return the string
*/
public String type(final ITyped var) {
public static String type(final ITyped var) {
switch (var.getGamlType().id()) {
case IType.BOOL:
return "Boolean";
Expand Down
Expand Up @@ -761,11 +761,13 @@ public void selectAgentsAroundMouse() {
final int yc = mousey - origin.y;
final List<ILayer> layers = layerManager.getLayersIntersecting(xc, yc);
if (layers.isEmpty()) return;
try {
EventQueue.invokeAndWait(() -> menuManager.buildMenu(mousex, mousey, xc, yc, layers));
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
EventQueue.invokeLater(() -> menuManager.buildMenu(mousex, mousey, xc, yc, layers));
// Modified for Issue #3404 -- now calls the menu asynchronously
// try {
// EventQueue.invokeAndWait(() -> menuManager.buildMenu(mousex, mousey, xc, yc, layers));
// } catch (InvocationTargetException | InterruptedException e) {
// e.printStackTrace();
// }
}

@Override
Expand Down
Expand Up @@ -25,9 +25,9 @@ species NetworkingAgent skills:[network] {
reflex send when: cycle = 0 {
write "sending message ";

// do send to: "/api/user/" contents: ["POST",map(["toto"::34,"titi"::12]), map(["Content-Type"::"application/json"])];
// do send to: "/api/user/" contents: ["PUT",map(["toto"::34,"titi"::12]), map(["Content-Type"::"application/json"])];
do send to: "/api/user/" contents: ["DELETE"];
do send to: "/api/user/" contents: ["POST",["toto"::34,"titi"::world], ["Content-Type"::"application/json"] ];
// do send to: "/api/user/" contents: ["PUT",["toto"::34,"titi"::12], ["Content-Type"::"application/json"]];
// do send to: "/api/user/" contents: ["DELETE"];

}

Expand Down
13 changes: 9 additions & 4 deletions ummisco.gama.serialize/.classpath
@@ -1,14 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry exported="true" kind="lib" path="ext/mxparser-1.2.2.jar"/>
<classpathentry exported="true" kind="lib" path="ext/xstream-1.4.18.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gaml">
<attributes>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="lib" path="ext/mxparser-1.2.2.jar"/>
<classpathentry exported="true" kind="lib" path="ext/xstream-1.4.18.jar"/>
<classpathentry exported="true" kind="lib" path="ext/jettison-1.4.1.jar"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="bin"/>
</classpath>
7 changes: 5 additions & 2 deletions ummisco.gama.serialize/META-INF/MANIFEST.MF
Expand Up @@ -8,7 +8,8 @@ Require-Bundle: msi.gama.core,
msi.gaml.architecture.simplebdi;bundle-version="1.8.2"
Bundle-ClassPath: .,
ext/mxparser-1.2.2.jar,
ext/xstream-1.4.18.jar
ext/xstream-1.4.18.jar,
ext/jettison-1.4.1.jar
Export-Package: com.thoughtworks.xstream,
com.thoughtworks.xstream.annotations,
com.thoughtworks.xstream.converters,
Expand All @@ -34,7 +35,9 @@ Export-Package: com.thoughtworks.xstream,
ummisco.gama.serializer.gamaType.converters,
ummisco.gama.serializer.gamaType.reduced,
ummisco.gama.serializer.gaml
Import-Package: org.apache.commons.lang
Import-Package: org.apache.commons.lang,
org.osgi.framework;version="1.10.0"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-17
Automatic-Module-Name: ummisco.gama.serialize
Bundle-Activator: ummisco.gama.serializer.Activator
3 changes: 2 additions & 1 deletion ummisco.gama.serialize/build.properties
Expand Up @@ -6,4 +6,5 @@ bin.includes = META-INF/,\
plugin.xml,\
models/,\
ext/mxparser-1.2.2.jar,\
ext/xstream-1.4.18.jar
ext/xstream-1.4.18.jar,\
ext/jettison-1.4.1.jar
Binary file added ummisco.gama.serialize/ext/jettison-1.4.1.jar
Binary file not shown.
19 changes: 19 additions & 0 deletions ummisco.gama.serialize/src/ummisco/gama/serializer/Activator.java
@@ -0,0 +1,19 @@
package ummisco.gama.serializer;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

import msi.gama.util.file.json.Jsoner;
import ummisco.gama.serializer.inject.ConverterJSON;

public class Activator implements BundleActivator {

@Override
public void start(BundleContext context) throws Exception {
Jsoner.streamConverter = new ConverterJSON();
}

@Override
public void stop(BundleContext context) throws Exception {
// TODO Auto-generated method stub
}
}
Expand Up @@ -16,6 +16,7 @@

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.security.AnyTypePermission;

Expand All @@ -39,14 +40,23 @@ public abstract class StreamConverter {
private static Map<Class<?>, XStream> xStreamMap = Collections.synchronizedMap(new HashMap<Class<?>, XStream>());

private static XStream getXStreamInstance(Class<?> clazz) {
return getXStreamInstance(clazz, false);
}

private static XStream getXStreamInstance(Class<?> clazz, boolean toJSON) {
if (xStreamMap.containsKey(clazz)) {
return xStreamMap.get(clazz);
}
synchronized (clazz) {
if (xStreamMap.containsKey(clazz)) {
return xStreamMap.get(clazz);
}
XStream xStream = new XStream(new DomDriver());
XStream xStream;
if(toJSON) {
xStream = new XStream(new JettisonMappedXmlDriver());
} else {
xStream = new XStream(new DomDriver());
}
xStream.ignoreUnknownElements();
xStream.processAnnotations(clazz);
xStream.addPermission(AnyTypePermission.ANY);
Expand Down Expand Up @@ -76,6 +86,19 @@ public static void registerConverter(final XStream st,final Converter c) {
st.registerConverter(c);
}

/**
* Convert object to stream in JSON.
*
* @param scope
* the scope
* @param o
* the o
* @return the string
*/
public static synchronized String convertObjectToJSONStream(final IScope scope, final Object o) {
return loadAndBuild(new ConverterScope(scope),o, true).toXML(o);
}

/**
* Load and build.
*
Expand All @@ -84,9 +107,13 @@ public static void registerConverter(final XStream st,final Converter c) {
* @return the x stream
*/
public static XStream loadAndBuild(final ConverterScope cs, final Object o) {
return loadAndBuild(cs, o, false);
}

public static XStream loadAndBuild(final ConverterScope cs, final Object o, final boolean toJSON) {

final Converter[] cnv = Converters.converterFactory(cs);
XStream streamer=getXStreamInstance(o.getClass());
XStream streamer = getXStreamInstance(o.getClass(),toJSON);
for (final Converter c : cnv) { StreamConverter.registerConverter(streamer,c); }
// dataStreamer.setMode(XStream.ID_REFERENCES);
return streamer;
Expand Down
@@ -0,0 +1,13 @@
package ummisco.gama.serializer.inject;

import msi.gama.runtime.IScope;
import msi.gama.util.serialize.IStreamConverter;
import ummisco.gama.serializer.factory.StreamConverter;

public class ConverterJSON implements IStreamConverter {

@Override
public String convertObjectToJSONStream(IScope scope, Object o) {
return StreamConverter.convertObjectToJSONStream(scope,o);
}
}

0 comments on commit 9183c43

Please sign in to comment.