diff --git a/common/src/main/java/com/genexus/GXBaseCollection.java b/common/src/main/java/com/genexus/GXBaseCollection.java index 7ec319851..297897d81 100644 --- a/common/src/main/java/com/genexus/GXBaseCollection.java +++ b/common/src/main/java/com/genexus/GXBaseCollection.java @@ -23,6 +23,7 @@ public class GXBaseCollection extends GXSimpleColle private static final long serialVersionUID = 1L; public GXBaseCollection() { + super(); } public GXBaseCollection(Class elementsType, String elementsName, String containedXmlNamespace) @@ -42,7 +43,7 @@ public GXBaseCollection(Class elementsType, String elementsName, String conta public GXBaseCollection(Class elementsType, String elementsName, String containedXmlNamespace, Vector data, int remoteHandle) { - + super(); this.elementsType = elementsType; this.elementsName = elementsName; xmlElementsName = elementsName; diff --git a/common/src/main/java/com/genexus/GXBaseList.java b/common/src/main/java/com/genexus/GXBaseList.java new file mode 100644 index 000000000..775b84ca4 --- /dev/null +++ b/common/src/main/java/com/genexus/GXBaseList.java @@ -0,0 +1,82 @@ +package com.genexus; + +import java.io.Serializable; +import java.util.Vector; +import com.genexus.internet.IGxJSONAble; +import com.genexus.internet.IGxJSONSerializable; + +public abstract class GXBaseList extends Vector implements Serializable, IGxJSONAble, IGxJSONSerializable, IGXAssigned +{ + private boolean IsAssigned; + + public GXBaseList() + { + IsAssigned = true; + } + + public boolean getIsAssigned() + { + return this.IsAssigned; + } + public void setIsAssigned(boolean bAssigned) + { + this.IsAssigned = bAssigned; + } + public void removeAllItems() + { + super.clear(); + IsAssigned = true; + } + public byte removeItem(int index) + { + T item = null; + if(index > 0 && index <= size()) + { + item = super.remove((int)index - 1);//Vector.remove(int) + IsAssigned = true; + return (byte)1; + } + return (byte)0; + } + public byte removeElement(double index) + { + if(index > 0 && index <= size()) + { + super.remove((int)index - 1);//Vector.remove(int) + IsAssigned = true; + return (byte)1; + } + else + { + return (byte)0; + } + } + + @SuppressWarnings("unchecked") + public void addObject(Object obj){ + super.add((T)obj); + IsAssigned = true; + } + @SuppressWarnings("unchecked") + public void add(Object item, int index) + { + if(index < 1 || index > size()) + { + add((T)item); //this.add, GXBCLevelCollection.add for example + } + else + { + super.add(index - 1, (T)item); //Vector insert element + IsAssigned = true; + } + } + @SuppressWarnings("unchecked") + public void addBase( Object item) + { + super.add((T)item); + IsAssigned = true; + } +} + + + diff --git a/common/src/main/java/com/genexus/GXSimpleCollection.java b/common/src/main/java/com/genexus/GXSimpleCollection.java index 1226b381c..6869176f8 100644 --- a/common/src/main/java/com/genexus/GXSimpleCollection.java +++ b/common/src/main/java/com/genexus/GXSimpleCollection.java @@ -37,7 +37,7 @@ import org.simpleframework.xml.*; @Root(name="Collection") -public class GXSimpleCollection extends Vector implements Serializable, IGxJSONAble, IGxJSONSerializable { +public class GXSimpleCollection extends GXBaseList { @ElementList(entry="item",inline=true) GXSimpleCollection list; @@ -50,6 +50,7 @@ public class GXSimpleCollection extends Vector implements Serializable, IG public GXSimpleCollection() { + super(); } public GXSimpleCollection(Class elementsType, String elementsName, String containedXmlNamespace) @@ -69,6 +70,7 @@ public GXSimpleCollection(Class elementsType, String elementsName, String con public GXSimpleCollection(Class elementsType, String elementsName, String containedXmlNamespace, Vector data, int remoteHandle) { + super(); this.elementsType = elementsType; this.elementsName = elementsName; xmlElementsName = elementsName; @@ -432,11 +434,6 @@ public Object currentItem() //-- Este add se usa cuando se quiere agregar a las lineas de un BC sin usar la logica de manteniomiento del estado // de la linea - @SuppressWarnings("unchecked") - public void addBase( Object item) - { - super.add((T)item); - } protected String getMethodName(boolean isGet, String method) { String getName = elementsType.getName(); @@ -456,19 +453,6 @@ public void addInternal(Object item) super.add((T)item); } - @SuppressWarnings("unchecked") - public void add(Object item, int index) - { - if(index < 1 || index > size()) - { - add((T)item); //this.add, GXBCLevelCollection.add for example - } - else - { - super.add(index - 1, (T)item); //Vector insert element - } - } - public void add(byte item) { addInternal(new Byte(item)); @@ -520,11 +504,6 @@ public void addIntegralConstant(double item) } } - @SuppressWarnings("unchecked") - public void addObject(Object obj){ - super.add((T)obj); - } - public void add(long item) { addInternal(new Long(item)); @@ -602,11 +581,6 @@ public void add(double item, int index) addIntegralConstant(item, index); } - public void removeAllItems() - { - super.clear(); - } - public void clearCollection() { removeAllItems(); @@ -694,30 +668,6 @@ public boolean remove(char item) return remove(new Character(item)); } - public byte removeItem(int index) - { - T item = null; - if(index > 0 && index <= size()) - { - item = super.remove((int)index - 1);//Vector.remove(int) - return (byte)1; - } - return (byte)0; - } - - public byte removeElement(double index) - { - if(index > 0 && index <= size()) - { - super.remove((int)index - 1);//Vector.remove(int) - return (byte)1; - } - else - { - return (byte)0; - } - } - /** Ordena la Collection de acuerdo a un proc pasado por parametro * El proc tiene que recibir como parms * parm(IN: &SDT1, IN: &SDT2, OUT: INT) diff --git a/common/src/main/java/com/genexus/IGXAssigned.java b/common/src/main/java/com/genexus/IGXAssigned.java new file mode 100644 index 000000000..de292d593 --- /dev/null +++ b/common/src/main/java/com/genexus/IGXAssigned.java @@ -0,0 +1,6 @@ +package com.genexus; +public interface IGXAssigned +{ + boolean getIsAssigned(); + void setIsAssigned(boolean bAssigned); +} diff --git a/java/src/main/java/com/genexus/GxUserType.java b/java/src/main/java/com/genexus/GxUserType.java new file mode 100644 index 000000000..e3a991116 --- /dev/null +++ b/java/src/main/java/com/genexus/GxUserType.java @@ -0,0 +1,31 @@ +package com.genexus; + +import com.genexus.xml.GXXMLSerializable; + +public abstract class GxUserType extends GXXMLSerializable implements Cloneable, java.io.Serializable, IGXAssigned +{ + + public GxUserType(ModelContext context, String type) + { + super(-1, context, type); + } + + public GxUserType(int remoteHandle, ModelContext context, String type) + { + super( remoteHandle, context, type); + } + + boolean bIsAssigned = true; + + public abstract String getJsonMap( String value ); + + @Override + public boolean getIsAssigned() { + return bIsAssigned; + } + + @Override + public void setIsAssigned(boolean bAssigned) { + bIsAssigned = bAssigned; + } +} diff --git a/java/src/main/java/com/genexus/internet/HttpAjaxContext.java b/java/src/main/java/com/genexus/internet/HttpAjaxContext.java index 4884f1cf9..a04a09591 100644 --- a/java/src/main/java/com/genexus/internet/HttpAjaxContext.java +++ b/java/src/main/java/com/genexus/internet/HttpAjaxContext.java @@ -7,8 +7,11 @@ import java.util.Hashtable; import java.util.Stack; +import com.genexus.IGXAssigned; import com.genexus.diagnostics.core.ILogger; import com.genexus.diagnostics.core.LogManager; +import com.genexus.webpanels.DynAjaxEventContext; +import com.genexus.webpanels.GXWebPanel; import com.genexus.webpanels.GXWebRow; import json.org.json.IJsonFormattable; @@ -44,8 +47,13 @@ public abstract class HttpAjaxContext public void setAjaxOnSessionTimeout( String ajaxOnSessionTimeout){ this._ajaxOnSessionTimeout = ajaxOnSessionTimeout;} public String ajaxOnSessionTimeout(){ return _ajaxOnSessionTimeout;} + DynAjaxEventContext dynAjaxEventContext = new DynAjaxEventContext(); - public abstract boolean isMultipartContent(); + public DynAjaxEventContext getDynAjaxEventContext() { + return dynAjaxEventContext; + } + + public abstract boolean isMultipartContent(); public abstract void ajax_rsp_assign_prop_as_hidden(String Control, String Property, String Value); public abstract boolean isSpaRequest(); @@ -319,7 +327,19 @@ public void ajax_rsp_assign_attri( String CmpContext, boolean IsMasterPage, Stri } } - public void ajax_rsp_assign_sdt_attri( String CmpContext, boolean IsMasterPage, String AttName, Object SdtObj) + private boolean isUndefinedOutParam(String key, Object SdtObj) { + if (!dynAjaxEventContext.isInputParm(key)) + { + if (SdtObj instanceof IGXAssigned) + { + return !((IGXAssigned)SdtObj).getIsAssigned(); + } + } + return false; + } + + + public void ajax_rsp_assign_sdt_attri( String CmpContext, boolean IsMasterPage, String AttName, Object SdtObj) { if (isJsOutputEnabled) { @@ -327,8 +347,8 @@ public void ajax_rsp_assign_sdt_attri( String CmpContext, boolean IsMasterPage, { try { JSONObject obj = getGxObject(AttValues, CmpContext, IsMasterPage); - if (obj != null) - { + if (obj != null && (dynAjaxEventContext.isParmModified(AttName, SdtObj) || !isUndefinedOutParam( AttName, SdtObj))) + { if (SdtObj instanceof IGxJSONAble) obj.put(AttName, ((IGxJSONAble)SdtObj).GetJSONObject()); else diff --git a/java/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java b/java/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java new file mode 100644 index 000000000..20192448f --- /dev/null +++ b/java/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java @@ -0,0 +1,48 @@ +package com.genexus.webpanels; + +import com.genexus.GXutil; +import com.genexus.internet.IGxJSONSerializable; +import json.org.json.JSONArray; + +import java.util.HashSet; +import java.util.Hashtable; + +public class DynAjaxEventContext implements GXWebPanel.IDynAjaxEventContext { + JSONArray inParmsMetadata; + HashSet inParmsMetadataHash = new HashSet(); + JSONArray outParmsMetadata; + HashSet outParmsMetadataHash = new HashSet(); + private Hashtable inParmsHashValue = new Hashtable(); + + public void ClearParmsMetadata() { + inParmsMetadata = new JSONArray(); + inParmsMetadataHash = new HashSet(); + outParmsMetadata = new JSONArray(); + outParmsMetadataHash = new HashSet(); + } + + public boolean isInputParm(String key) { + return inParmsMetadataHash.contains(key); + } + + public void Clear() { + inParmsHashValue.clear(); + } + + public void SetParmHash(String fieldName, Object value) { + IGxJSONSerializable jsonValue = (value instanceof IGxJSONSerializable) ? (IGxJSONSerializable) value : null; + if (jsonValue != null) { + inParmsHashValue.put(fieldName, GXutil.getHash(jsonValue.toJSonString())); + } + } + + public boolean isParmModified(String fieldName, Object value) { + IGxJSONSerializable jsonValue = (value instanceof IGxJSONSerializable) ? (IGxJSONSerializable) value : null; + if (value != null) { + if (!inParmsHashValue.containsKey(fieldName)) + return true; + return !GXutil.getHash(jsonValue.toJSonString()).equals(inParmsHashValue.get(fieldName)); + } + return true; + } +} diff --git a/java/src/main/java/com/genexus/webpanels/GXWebPanel.java b/java/src/main/java/com/genexus/webpanels/GXWebPanel.java index b32b37285..b318081ab 100644 --- a/java/src/main/java/com/genexus/webpanels/GXWebPanel.java +++ b/java/src/main/java/com/genexus/webpanels/GXWebPanel.java @@ -460,7 +460,7 @@ public void doExecute() throws Exception public void webAjaxEvent() throws Exception { httpContext.setAjaxCallMode(); httpContext.setFullAjaxMode(); - DynAjaxEvent dynAjaxEvent = new DynAjaxEvent(); + DynAjaxEvent dynAjaxEvent = new DynAjaxEvent(httpContext.getDynAjaxEventContext()); String jsonRequest; if (httpContext.isMultipartContent()) jsonRequest = httpContext.cgiGet(GX_AJAX_MULTIPART_ID); @@ -499,9 +499,17 @@ else if ( context.nUserReturn == 1 ) return false; } + public interface IDynAjaxEventContext + { + void Clear(); + void ClearParmsMetadata(); + boolean isInputParm(String key); + void SetParmHash(String fieldName, Object value); + boolean isParmModified(String fieldName, Object value); + + } + protected class DynAjaxEvent { - JSONArray inParmsValues = new JSONArray(); - JSONArray inHashValues = new JSONArray(); JSONArray events = new JSONArray(); GXWebPanel targetObj; String[] eventHandlers; @@ -510,9 +518,14 @@ protected class DynAjaxEvent { int grid; String row; String pRow = ""; - JSONArray inParmsMetadata; - HashSet inParmsMetadataHash; boolean anyError; + JSONArray inParmsValues = new JSONArray(); + JSONArray inHashValues = new JSONArray(); + DynAjaxEventContext dynAjaxEventContext; + DynAjaxEvent( DynAjaxEventContext dynAjaxEventContext) + { + this.dynAjaxEventContext = dynAjaxEventContext; + } private void parseInputJSonMessage(String jsonMessage, GXWebPanel targetObj) throws JSONException { try { @@ -615,19 +628,13 @@ private void parseGXStateParms(JSONObject gxState) { private String buildOutputJSonMessage() { return targetObj.httpContext.getJSONResponse(cmpContext); } - private void clearInputParmsMetadata() - { - inParmsMetadata = new JSONArray(); - inParmsMetadataHash = new HashSet(); - } private boolean IsInternalParm(JSONObject parm) { return parm.has("sPrefix") || parm.has("sSFPrefix") || parm.has("sCompEvt"); } - private void addInputParmsMetadata(JSONObject inputParm) throws JSONException - { + private void addParmsMetadata(JSONObject inputParm, JSONArray ParmsList, HashSet ParmsListHash) throws JSONException { String key = ""; if (inputParm.has("av") && inputParm.has("ctrl") && inputParm.has("prop")) { @@ -645,18 +652,17 @@ else if (inputParm.has("ctrl")) { key = inputParm.getString("ctrl"); } - if (key==null || key.equals("") || !inParmsMetadataHash.contains(key)) - { - inParmsMetadata.put(inputParm); - if (key!=null && !key.equals("")) - { - inParmsMetadataHash.add(key); + if (key==null || key.equals("") || !ParmsListHash.contains(key)) { + ParmsList.put(inputParm); + if (key!=null && !key.equals("")) { + ParmsListHash.add(key); } } } + private void parseMetadata() { try { - clearInputParmsMetadata(); + dynAjaxEventContext.ClearParmsMetadata(); eventHandlers = new String[events.length()]; eventUseInternalParms = new boolean[events.length()]; int eventCount = 0; @@ -668,9 +674,13 @@ private void parseMetadata() { JSONArray eventInputParms = eventMetadata.getJSONArray("iparms"); for (int j=0; j< eventInputParms.length(); j++ ) { - addInputParmsMetadata(eventInputParms.getJSONObject(j)); + addParmsMetadata(eventInputParms.getJSONObject(j), dynAjaxEventContext.inParmsMetadata, dynAjaxEventContext.inParmsMetadataHash); eventUseInternalParms[eventCount] = eventUseInternalParms[eventCount] || IsInternalParm(eventInputParms.getJSONObject(j)); } + JSONArray eventOutputParms = eventMetadata.getJSONArray("oparms"); + for (int j = 0; j < eventOutputParms.length(); j++) { + addParmsMetadata(eventOutputParms.getJSONObject(j), dynAjaxEventContext.outParmsMetadata, dynAjaxEventContext.outParmsMetadataHash); + } eventCount++; } } catch (Exception ex) { @@ -839,17 +849,40 @@ private Object getArrayFieldValue(Class fieldType, Object value) throws JSONExce return null; } - private Object [] beforeInvoke() throws JSONException, Exception { + private void initializeOutParms() throws JSONException { + dynAjaxEventContext.Clear(); + for (int j = 0; j < dynAjaxEventContext.outParmsMetadata.length(); j++) { + JSONObject parm = dynAjaxEventContext.outParmsMetadata.getJSONObject(j); + String parmName = ""; + if (parm.has("av")) { + parmName = parm.getString("av"); + if (!parmName.isEmpty()) { + Object TypedValue = null; + try { + TypedValue = getFieldValue(parmName, parmName); + dynAjaxEventContext.SetParmHash(parmName, TypedValue); + if (!dynAjaxEventContext.isInputParm(parmName) && TypedValue instanceof IGXAssigned) { + ((IGXAssigned) TypedValue).setIsAssigned(false); + } + } catch (java.lang.Exception e) { + logger.error(String.format("initializeOutParms param:'%s'", parmName, e)); + } + } + } + } + } + + private Object[] beforeInvoke() throws JSONException, Exception { ArrayList MethodParms = new ArrayList(); int hash_i = 0; int parm_i = 0; int hashValuesLen = inHashValues.length(); if (!anyError) { int nParm = 0; - int len = inParmsMetadata.length(); + int len = dynAjaxEventContext.inParmsMetadata.length(); boolean multipart = targetObj.httpContext.isMultipartContent(); for (int i = 0; i < len; i++) { - JSONObject parm = (JSONObject) inParmsMetadata.getJSONObject(i); + JSONObject parm = (JSONObject) dynAjaxEventContext.inParmsMetadata.getJSONObject(i); try{ if (parm.has("postForm")) { @@ -926,7 +959,7 @@ private Object getArrayFieldValue(Class fieldType, Object value) throws JSONExce if (httpContext.useSecurityTokenValidation()) { SetScalarOrCollectionValue(parm.has("av") ? parm.getString("av") : null, parm.has("prop") ? parm.getString("prop") : null, columnValues.get(j), columnValues); Object TypedValue = getFieldValue(parm.has("av") ? parm.getString("av") : null, parm.has("prop") ? parm.getString("prop") : null); - checkParmIntegrity( TypedValue, columnHash, sRow, inParmsMetadata.get(parm_i), hash_i, picture); + checkParmIntegrity(TypedValue, columnHash, sRow, dynAjaxEventContext.inParmsMetadata.get(parm_i), hash_i, picture); } rowIdx++; } @@ -996,7 +1029,7 @@ private Object getArrayFieldValue(Class fieldType, Object value) throws JSONExce } SetScalarOrCollectionValue(parm.has("av") ? parm.getString("av") : null, parm.has("prop") ? parm.getString("prop") : null, value, columnValues); Object TypedValue = getFieldValue(parm.has("av") ? parm.getString("av") : null, parm.has("prop") ? parm.getString("prop") : null); - checkParmIntegrity( TypedValue, hash, sRow, inParmsMetadata.get(parm_i), hash_i, picture); + checkParmIntegrity(TypedValue, hash, sRow, dynAjaxEventContext.inParmsMetadata.get(parm_i), hash_i, picture); } catch (Exception ex) { @@ -1046,6 +1079,7 @@ private Object getArrayFieldValue(Class fieldType, Object value) throws JSONExce } SetFieldValue("wbLoad", true); } + initializeOutParms(); return MethodParms.toArray(); }