use of org.sablo.specification.property.ChangeAwareMap in project servoy-client by Servoy.
the class CustomArrayAndObjectPropertyRhinoTest method testCustomTypeJavaBasedRhinoChanges.
@Test
public void testCustomTypeJavaBasedRhinoChanges() throws JSONException {
Context.enter();
try {
WebComponent component = new WebComponent("mycomponent", "testComponentName");
BrowserConverterContext allowingBrowserConverterContext = new BrowserConverterContext(component, PushToServerEnum.allow);
PropertyDescription arrayTPD = component.getSpecification().getProperty("arrayT");
// just some initial checks and setting a java value
assertNull(component.getProperty("arrayT"));
List<Map<String, Object>> javaV = new ArrayList<>();
HashMap<String, Object> hm = new HashMap<String, Object>();
javaV.add(hm);
hm.put("text", "Just some text");
component.setProperty("arrayT", javaV);
// set should turn it into a change-aware list
Object wrapped = component.getProperty("arrayT");
assertTrue(wrapped instanceof ChangeAwareList<?, ?>);
ChangeAwareList<Map<String, Object>, Map<String, Object>> cal = (ChangeAwareList) wrapped;
assertEquals("Just some text", cal.get(0).get("text"));
assertTrue(cal.get(0) instanceof ChangeAwareMap<?, ?>);
ChangeAwareMap cam = ((ChangeAwareMap<?, ?>) cal.get(0));
Changes chMap = cam.getChanges();
ChangeAwareList<Map<String, Object>, Map<String, Object>>.Changes chList = cal.getChanges();
// TODO I guess this kind of reference changes should be treated in the BaseWebObject directly when we have separate methods for changesToJSON and fullToJSON
// so for now the change aware things do not report as being changed...
assertTrue(!chList.mustSendAll());
assertTrue(!chMap.mustSendAll());
// still the component has to see them as changed!
TypedData<Map<String, Object>> changes = component.getAndClearChanges();
assertTrue(changes.content.get("arrayT") != null);
assertTrue(changes.contentType.getProperty("arrayT").getType() instanceof CustomJSONArrayType);
Object arrayCh = changes.content.get("arrayT");
assertTrue(arrayCh != null);
assertTrue(changes.contentType.getProperty("arrayT").getType() instanceof CustomJSONArrayType);
Object mapCh = ((ChangeAwareList) arrayCh).get(0);
assertTrue(mapCh != null);
assertTrue(((CustomJSONPropertyType<?>) changes.contentType.getProperty("arrayT").getType()).getCustomJSONTypeDefinition().getType() instanceof CustomJSONObjectType);
JSONUtils.writeDataWithConversions(changes.content, changes.contentType, allowingBrowserConverterContext);
// ok now that we called component.getChanges() no changes should be present any more
assertTrue(!chList.mustSendAll());
assertTrue(!chMap.mustSendAll());
assertEquals(0, component.getAndClearChanges().content.size());
assertFalse(chList.getGranularUpdatesKeeper().hasChanges());
// check changing java => change reflected in Rhino
ScriptableObject topLevel = new ScriptableObject() {
@Override
public String getClassName() {
return "test_top_level_scope";
}
};
Scriptable rhinoVal = (Scriptable) NGConversions.INSTANCE.convertSabloComponentToRhinoValue(component.getProperty("arrayT"), arrayTPD, component, topLevel);
assertEquals("Just some text", ((Scriptable) rhinoVal.get(0, rhinoVal)).get("text", rhinoVal));
cam.put("text", "Just some text 2");
assertEquals(1, chMap.getKeysChangedByRef().size());
assertEquals("text", chMap.getKeysChangedByRef().iterator().next());
ArrayOperation[] opSeq = chList.getGranularUpdatesKeeper().getEquivalentSequenceOfOperations();
assertEquals(1, opSeq.length);
assertGranularOpIs(0, 0, ArrayOperation.CHANGE, ChangeAwareList.GRANULAR_UPDATE_OP, opSeq[0]);
assertTrue(!chList.mustSendAll());
assertTrue(!chMap.mustSendAll());
assertEquals("Just some text 2", ((Scriptable) rhinoVal.get(0, rhinoVal)).get("text", rhinoVal));
cam.put("active", new ArrayList());
assertTrue(!chList.mustSendAll());
assertTrue(!chMap.mustSendAll());
assertEquals(2, chMap.getKeysChangedByRef().size());
assertTrue(chMap.getKeysChangedByRef().contains("text"));
assertTrue(chMap.getKeysChangedByRef().contains("active"));
cam.remove("active");
assertTrue(!chList.mustSendAll());
assertTrue(chMap.mustSendAll());
cal.add(new HashMap<String, Object>());
ChangeAwareMap cam1 = ((ChangeAwareMap<?, ?>) cal.get(1));
assertFalse(chList.mustSendAll());
opSeq = chList.getGranularUpdatesKeeper().getEquivalentSequenceOfOperations();
assertEquals(2, opSeq.length);
assertGranularOpIs(0, 0, ArrayOperation.CHANGE, ChangeAwareList.GRANULAR_UPDATE_OP, opSeq[0]);
assertGranularOpIs(1, 1, ArrayOperation.INSERT, null, opSeq[1]);
assertTrue(chMap.mustSendAll());
// ok clear changes
changes = component.getAndClearChanges();
JSONUtils.writeDataWithConversions(changes.content, changes.contentType, allowingBrowserConverterContext);
assertEquals(1, changes.content.size());
assertEquals(0, component.getAndClearChanges().content.size());
assertTrue(!chList.mustSendAll());
assertTrue(!chMap.mustSendAll());
assertFalse(chList.getGranularUpdatesKeeper().hasChanges());
assertEquals(0, chMap.getKeysChangedByRef().size());
assertEquals(0, chMap.getKeysWithUpdates().size());
// assign some native values
Scriptable oneO = Context.getCurrentContext().newObject(topLevel);
Scriptable activeA1 = Context.getCurrentContext().newArray(topLevel, 0);
Scriptable activeA1Obj = Context.getCurrentContext().newObject(topLevel);
rhinoVal.put(0, rhinoVal, oneO);
// same as 'cam' but in it's Rhino representation
Scriptable oneOScriptable = (Scriptable) rhinoVal.get(0, rhinoVal);
assertTrue(!chList.mustSendAll());
opSeq = chList.getGranularUpdatesKeeper().getEquivalentSequenceOfOperations();
assertEquals(1, opSeq.length);
assertGranularOpIs(0, 0, ArrayOperation.CHANGE, null, opSeq[0]);
cam = ((ChangeAwareMap<?, ?>) cal.get(0));
chMap = cam.getChanges();
activeA1Obj.put("field", activeA1Obj, 11);
activeA1.put(0, activeA1, activeA1Obj);
oneOScriptable.put("active", oneOScriptable, activeA1);
assertEquals(11, ((Map) ((List) ((Map) cal.get(0)).get("active")).get(0)).get("field"));
((Map) ((List) ((Map) cal.get(0)).get("active")).get(0)).put("percent", 0.22);
assertEquals(1, chMap.getKeysChangedByRef().size());
assertEquals(0, chMap.getKeysWithUpdates().size());
assertTrue(chMap.getKeysChangedByRef().contains("active"));
assertTrue(!chList.mustSendAll());
opSeq = chList.getGranularUpdatesKeeper().getEquivalentSequenceOfOperations();
assertEquals(1, opSeq.length);
assertGranularOpIs(0, 0, ArrayOperation.CHANGE, null, opSeq[0]);
// now change the native values using initial ref to see if it changed in java; this is no longer supported after case SVY-11027
// activeA1Obj.put("field", activeA1Obj, 98);
// assertEquals(98, ((Map)((List)((Map)cal.get(0)).get("active")).get(0)).get("field"));
// activeA1.put(1, activeA1, activeA2Obj);
// activeA2Obj.put("field", activeA2Obj, 45);
// assertEquals(45, ((Map)((List)((Map)cal.get(0)).get("active")).get(1)).get("field"));
changes = component.getAndClearChanges();
String msg = JSONUtils.writeChangesWithConversions(changes.content, changes.contentType, allowingBrowserConverterContext);
JSONAssert.assertEquals("{\"arrayT\":{\"vEr\":3,\"g\":[{\"op\":[0,0,0],\"d\":[{\"rt\":\"mycomponent.mytype007\",\"vEr\":5,\"v\":{\"active\":{\"vEr\":2,\"v\":[{\"rt\":\"mycomponent.activeType\",\"vEr\":2,\"v\":{\"field\":11,\"percent\":0.22}}],\"svy_types\":{\"0\":\"JSON_obj\"}}},\"svy_types\":{\"active\":\"JSON_arr\"}}],\"svy_types\":{\"0\":\"JSON_obj\"}}]},\"svy_types\":{\"arrayT\":\"JSON_arr\"}}", msg, JSONCompareMode.NON_EXTENSIBLE);
((Map) ((List) ((Map) cal.get(0)).get("active")).get(0)).put("percent", 0.33);
assertEquals(0, chMap.getKeysChangedByRef().size());
assertEquals(1, chMap.getKeysWithUpdates().size());
changes = component.getAndClearChanges();
msg = JSONUtils.writeChangesWithConversions(changes.content, changes.contentType, allowingBrowserConverterContext);
JSONAssert.assertEquals("{\"arrayT\":{\"vEr\":3,\"g\":[{\"op\":[0,0,0],\"d\":[{\"rt\":\"mycomponent.mytype007\",\"vEr\":5,\"u\":[{\"k\":\"active\",\"v\":{\"vEr\":2,\"g\":[{\"op\":[0,0,0],\"d\":[{\"rt\":\"mycomponent.activeType\",\"vEr\":2,\"u\":[{\"k\":\"percent\",\"v\":0.33}]}],\"svy_types\":{\"0\":\"JSON_obj\"}}]}}],\"svy_types\":{\"0\":{\"v\":\"JSON_arr\"}}}],\"svy_types\":{\"0\":\"JSON_obj\"}}]},\"svy_types\":{\"arrayT\":\"JSON_arr\"}}", msg, JSONCompareMode.NON_EXTENSIBLE);
((List) ((Map) cal.get(0)).get("active")).add(new HashMap<String, Object>());
((Map) ((List) ((Map) cal.get(0)).get("active")).get(1)).put("percent", 0.99);
component.getAndClearChanges();
// now simulate another request cycle that makes some change to the property from javascript
rhinoVal = (Scriptable) NGConversions.INSTANCE.convertSabloComponentToRhinoValue(component.getProperty("arrayT"), arrayTPD, component, topLevel);
Scriptable v = ((Scriptable) rhinoVal.get(0, rhinoVal));
v = (Scriptable) v.get("active", v);
v = (Scriptable) v.get(1, v);
assertEquals(0.99, v.get("percent", v));
v.put("percent", v, 0.56);
assertEquals(0.56, ((Map) ((List) ((Map) cal.get(0)).get("active")).get(1)).get("percent"));
assertTrue(!chMap.mustSendAll());
assertTrue(!chList.mustSendAll());
opSeq = chList.getGranularUpdatesKeeper().getEquivalentSequenceOfOperations();
assertEquals(1, opSeq.length);
assertGranularOpIs(0, 0, ArrayOperation.CHANGE, ChangeAwareList.GRANULAR_UPDATE_OP, opSeq[0]);
assertEquals(1, chMap.getKeysWithUpdates().size());
assertEquals("active", chMap.getKeysWithUpdates().iterator().next());
} finally {
Context.exit();
}
}
use of org.sablo.specification.property.ChangeAwareMap in project servoy-client by Servoy.
the class NGCustomJSONObjectType method toSabloComponentValue.
@Override
public Map<String, SabloT> toSabloComponentValue(final Object rhinoValue, final Map<String, SabloT> previousComponentValue, PropertyDescription pd, final IWebObjectContext webObjectContext) {
if (rhinoValue == null || RhinoConversion.isUndefinedOrNotFound(rhinoValue))
return null;
if (rhinoValue instanceof RhinoMapOrArrayWrapper) {
return (Map<String, SabloT>) ((RhinoMapOrArrayWrapper) rhinoValue).getWrappedValue();
} else {
final ChangeAwareMap<SabloT, SabloWT> previousSpecialMap = (ChangeAwareMap<SabloT, SabloWT>) previousComponentValue;
// if it's some kind of object, convert it (in depth, iterate over children)
if (rhinoValue instanceof NativeObject) {
Map<String, SabloT> rhinoObjectCopy = new HashMap<>();
NativeObject rhinoNativeObject = (NativeObject) rhinoValue;
CustomObjectContext<SabloT, SabloWT> customObjectContext = createComponentOrServiceExtension(webObjectContext);
Object[] keys = rhinoNativeObject.getIds();
Object value;
String keyAsString;
// perform the rhino-to-sablo conversions
for (Object key : keys) {
if (key instanceof String) {
keyAsString = (String) key;
value = rhinoNativeObject.get(keyAsString, rhinoNativeObject);
} else if (key instanceof Number) {
keyAsString = String.valueOf(((Number) key).intValue());
value = rhinoNativeObject.get(((Number) key).intValue(), rhinoNativeObject);
} else
throw new RuntimeException("JS Object key must be either String or Number.");
rhinoObjectCopy.put(keyAsString, (SabloT) NGConversions.INSTANCE.convertRhinoToSabloComponentValue(value, null, getCustomJSONTypeDefinition().getProperty(keyAsString), customObjectContext));
}
// create the new change-aware-map based on the converted sub-properties
ChangeAwareMap<SabloT, SabloWT> retVal = wrapAndKeepRhinoPrototype(rhinoObjectCopy, rhinoNativeObject.getPrototype(), previousSpecialMap, pd, new WrappingContext(webObjectContext.getUnderlyingWebObject(), pd.getName()), customObjectContext);
// after it is returned it and it's sub-properties will at some point get "attached" (ISmartPropertyValue)
return retVal;
} else
Debug.warn("Cannot convert value assigned from solution scripting into custom object property type; new value = " + rhinoValue + "; property = " + pd.getName() + "; component name = " + webObjectContext.getUnderlyingWebObject().getName());
}
// or should we return null or throw exception here? incompatible thing was assigned
return previousComponentValue;
}
use of org.sablo.specification.property.ChangeAwareMap in project servoy-client by Servoy.
the class NGFoundSetManager method executeMethod.
@SuppressWarnings("nls")
@Override
public Object executeMethod(String methodName, JSONObject args) throws Exception {
if ("getFoundSet".equals(methodName)) {
IFoundSetInternal foundset = FoundsetReferencePropertyTypeOld.INSTANCE.fromJSON(args, null, null, null, null);
String sort = args.optString("sort");
if (!"".equals(sort)) {
foundset.setSort(sort);
}
FoundsetTypeSabloValue value = getFoundsetTypeSabloValue(foundset, args.optJSONObject("dataproviders"));
ChangeAwareList<ChangeAwareMap<String, Object>, Object> foundsets = (ChangeAwareList<ChangeAwareMap<String, Object>, Object>) ((NGClient) getApplication()).getWebsocketSession().getClientService("foundset_manager").getProperty("foundsets");
if (foundsets == null) {
foundsets = new ChangeAwareList<ChangeAwareMap<String, Object>, Object>(new ArrayList<ChangeAwareMap<String, Object>>());
((NGClient) getApplication()).getWebsocketSession().getClientService("foundset_manager").setProperty("foundsets", foundsets);
}
boolean newFoundsetInfo = true;
for (ChangeAwareMap<String, Object> foundsetInfoMap : foundsets) {
if (foundsetInfoMap.containsValue(value)) {
newFoundsetInfo = false;
break;
}
}
if (newFoundsetInfo) {
HashMap<String, Object> foundsetinfoMap = new HashMap<String, Object>();
foundsetinfoMap.put("foundset", value);
foundsetinfoMap.put("foundsethash", args.optString("foundsethash"));
String childrelation = args.optString("childrelation");
if (childrelation != null) {
JSONObject childrelationinfo = new JSONObject();
childrelationinfo.put("name", childrelation);
for (int i = 0; i < foundset.getSize(); i++) {
IRecordInternal record = foundset.getRecord(i);
Object o = record.getValue(childrelation);
if (o instanceof IFoundSetInternal) {
childrelationinfo.put(record.getPKHashKey() + "_" + record.getParentFoundSet().getRecordIndex(record), ((IFoundSetInternal) o).getSize());
}
}
foundsetinfoMap.put("childrelationinfo", childrelationinfo);
}
CustomJSONObjectType dummyCustomObjectTypeForChildRelationInfo = (CustomJSONObjectType) TypesRegistry.createNewType(CustomJSONObjectType.TYPE_NAME, "svy__dummyCustomObjectTypeForDeprecatedFMServiceChildRelationInfo");
PropertyDescription dummyPD = new PropertyDescriptionBuilder().withType(dummyCustomObjectTypeForChildRelationInfo).build();
dummyCustomObjectTypeForChildRelationInfo.setCustomJSONDefinition(dummyPD);
foundsets.add(new ChangeAwareMap(foundsetinfoMap, null, dummyPD));
}
} else if ("getRelatedFoundSetHash".equals(methodName)) {
IFoundSetInternal foundset = FoundsetReferencePropertyTypeOld.INSTANCE.fromJSON(args, null, null, null, null);
String rowid = args.optString("rowid");
String relation = args.optString("relation");
Pair<String, Integer> splitHashAndIndex = FoundsetTypeSabloValue.splitPKHashAndIndex(rowid);
int recordIndex = foundset.getRecordIndex(splitHashAndIndex.getLeft(), splitHashAndIndex.getRight().intValue());
if (recordIndex != -1) {
IRecordInternal record = foundset.getRecord(recordIndex);
Object o = record.getValue(relation);
if (o instanceof IFoundSetInternal) {
IFoundSetInternal relatedFoundset = (IFoundSetInternal) o;
PropertyDescription foundsetRefProperty = new PropertyDescriptionBuilder().withType(FoundsetReferencePropertyTypeOld.INSTANCE).build();
return new TypedData<IFoundSetInternal>(relatedFoundset, foundsetRefProperty);
}
}
} else if ("updateFoundSetRow".equals(methodName)) {
IFoundSetInternal foundset = FoundsetReferencePropertyTypeOld.INSTANCE.fromJSON(args, null, null, null, null);
String rowid = args.optString("rowid");
String dataproviderid = args.optString("dataproviderid");
Object value = args.get("value");
Pair<String, Integer> splitHashAndIndex = FoundsetTypeSabloValue.splitPKHashAndIndex(rowid);
int recordIndex = foundset.getRecordIndex(splitHashAndIndex.getLeft(), splitHashAndIndex.getRight().intValue());
if (recordIndex != -1) {
IRecordInternal record = foundset.getRecord(recordIndex);
if (record.startEditing()) {
record.setValue(dataproviderid, value);
return Boolean.TRUE;
}
}
} else if ("removeFoundSetFromCache".equals(methodName)) {
IFoundSetInternal foundset = FoundsetReferencePropertyTypeOld.INSTANCE.fromJSON(args, null, null, null, null);
removeFoundSetTypeSabloValue(foundset);
} else if ("removeFoundSetsFromCache".equals(methodName)) {
ChangeAwareList<ChangeAwareMap<String, Object>, Object> foundsets = (ChangeAwareList<ChangeAwareMap<String, Object>, Object>) ((NGClient) getApplication()).getWebsocketSession().getClientService("foundset_manager").getProperty("foundsets");
if (foundsets != null) {
foundsets.clear();
}
foundsetTypeSabloValueMap.clear();
}
return null;
}
use of org.sablo.specification.property.ChangeAwareMap in project servoy-client by Servoy.
the class NGFoundSetManager method removeFoundSetTypeSabloValue.
public void removeFoundSetTypeSabloValue(IFoundSetInternal foundset) {
if (foundset != null) {
FoundsetTypeSabloValue value = foundsetTypeSabloValueMap.remove(foundset);
ChangeAwareList<ChangeAwareMap<String, Object>, Object> foundsets = (ChangeAwareList<ChangeAwareMap<String, Object>, Object>) ((NGClient) getApplication()).getWebsocketSession().getClientService("foundset_manager").getProperty("foundsets");
if (foundsets != null) {
int i = 0;
for (; i < foundsets.size(); i++) {
ChangeAwareMap<String, Object> foundsetInfoMap = foundsets.get(i);
if (foundsetInfoMap.containsValue(value))
break;
}
if (i < foundsets.size()) {
foundsets.remove(i);
}
}
}
}
use of org.sablo.specification.property.ChangeAwareMap in project servoy-client by Servoy.
the class NGCustomJSONObjectType method toRhinoValue.
@Override
public Object toRhinoValue(Map<String, SabloT> webComponentValue, PropertyDescription pd, IWebObjectContext componentOrService, Scriptable startScriptable) {
if (webComponentValue != null) {
CustomObjectContext<SabloT, SabloWT> ext = ((ChangeAwareMap<SabloT, SabloWT>) webComponentValue).getOrCreateComponentOrServiceExtension();
RhinoMapOrArrayWrapper rhinoValue = new RhinoMapOrArrayWrapper(webComponentValue, ext, pd, startScriptable);
return rhinoValue;
}
return null;
}
Aggregations