/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2014 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.server.ngclient.property; import java.awt.Dimension; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.rmi.RemoteException; import java.util.HashMap; import java.util.List; import java.util.Map; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONStringer; import org.json.JSONWriter; import org.junit.Assert; import org.junit.Test; import org.sablo.Container; import org.sablo.InMemPackageReader; import org.sablo.specification.WebObjectSpecification.PushToServerEnum; import org.sablo.specification.property.BrowserConverterContext; import org.sablo.websocket.utils.DataConversion; import org.sablo.websocket.utils.JSONUtils.FullValueToJSONConverter; import com.servoy.base.query.IBaseSQLCondition; import com.servoy.j2db.dataprocessing.BufferedDataSet; import com.servoy.j2db.dataprocessing.IFoundSetInternal; import com.servoy.j2db.persistence.Column; import com.servoy.j2db.persistence.Form; import com.servoy.j2db.persistence.IColumnTypes; import com.servoy.j2db.persistence.IServer; import com.servoy.j2db.persistence.ITable; import com.servoy.j2db.persistence.Relation; import com.servoy.j2db.persistence.RepositoryException; import com.servoy.j2db.persistence.Table; import com.servoy.j2db.persistence.WebComponent; import com.servoy.j2db.query.ISQLJoin; import com.servoy.j2db.server.ngclient.IWebFormController; import com.servoy.j2db.server.ngclient.WebFormComponent; import com.servoy.j2db.server.ngclient.utils.NGUtils; import com.servoy.j2db.util.ServoyException; import com.servoy.j2db.util.ServoyJSONObject; /** * @author jcompagner * */ @SuppressWarnings("nls") public class FoundsetTest extends AbstractSolutionTest { @Override protected InMemPackageReader getTestComponents() throws IOException { InputStream is = getClass().getResourceAsStream("FoundSetTest.manifest"); byte[] bytes = new byte[is.available()]; is.read(bytes); String manifest = new String(bytes); is.close(); is = getClass().getResourceAsStream("FoundSetTest-mycomponent.spec"); bytes = new byte[is.available()]; is.read(bytes); String comp1 = new String(bytes); is.close(); is = getClass().getResourceAsStream("FoundSetTest-mydynamiccomponent.spec"); bytes = new byte[is.available()]; is.read(bytes); String comp2 = new String(bytes); is.close(); HashMap<String, String> components = new HashMap<>(); components.put("mycomponent.spec", comp1); components.put("mydynamiccomponent.spec", comp2); InMemPackageReader inMemPackageReader = new InMemPackageReader(manifest, components); return inMemPackageReader; } @Override protected void fillTestSolution() throws ServoyException { try { Form form = solution.createNewForm(validator, null, "test", "mem:test", false, new Dimension(600, 400)); WebComponent bean = form.createNewWebComponent("mycustombean", "my-component"); bean.setProperty("myfoundset", new ServoyJSONObject("{dataproviders:{firstname:'test1',lastname:'test2'}}", false)); bean.setProperty("myfoundsetWithAllow", new ServoyJSONObject("{dataproviders:{firstname:'test1',lastname:'test2'}}", false)); WebComponent bean1 = form.createNewWebComponent("mydynamiccustombean", "my-dynamiccomponent"); bean1.setProperty("myfoundset", new ServoyJSONObject("{foundsetSelector:'test_to_relatedtest', dataproviders:{dp1:'relatedtest1',dp2:'relatedtest2'}}", false)); bean1.setProperty("myfoundsetWithAllow", new ServoyJSONObject("{foundsetSelector:'test_to_relatedtest', dataproviders:{dp1:'relatedtest1',dp2:'relatedtest2'}}", false)); WebComponent bean2 = form.createNewWebComponent("mycustomseparatefoundsetbean", "my-component"); bean2.setProperty("myfoundset", new ServoyJSONObject( "{foundsetSelector: \"mem:testseparatefoundset\", loadAllRecords: true, dataproviders:{firstname:'test1',lastname:'test2'}}", false)); } catch (JSONException e) { e.printStackTrace(); throw new ServoyException(); } } @Override protected void setupData() throws ServoyException { BufferedDataSet ds = new BufferedDataSet(new String[] { "pk", "test1", "test2" }, new int[] { IColumnTypes.INTEGER, IColumnTypes.TEXT, IColumnTypes.TEXT }); ds.addRow(new Object[] { Integer.valueOf(1), "value1", "value2" }); ds.addRow(new Object[] { Integer.valueOf(2), "value3", "value4" }); ds.addRow(new Object[] { Integer.valueOf(3), "value1", "value2" }); ds.addRow(new Object[] { Integer.valueOf(4), "value3", "value4" }); ds.addRow(new Object[] { Integer.valueOf(5), "value1", "value2" }); ds.addRow(new Object[] { Integer.valueOf(6), "value3", "value4" }); ds.addRow(new Object[] { Integer.valueOf(7), "value1", "value2" }); ds.addRow(new Object[] { Integer.valueOf(8), "value3", "value4" }); ds.addRow(new Object[] { Integer.valueOf(9), "value1", "value2" }); ds.addRow(new Object[] { Integer.valueOf(10), "value3", "value4" }); ds.addRow(new Object[] { Integer.valueOf(11), "value1", "value2" }); ds.addRow(new Object[] { Integer.valueOf(12), "value3", "value4" }); ds.addRow(new Object[] { Integer.valueOf(13), "value1", "value2" }); ds.addRow(new Object[] { Integer.valueOf(14), "value3", "value4" }); ds.addRow(new Object[] { Integer.valueOf(15), "value1", "value2" }); ds.addRow(new Object[] { Integer.valueOf(16), "value3", "value4" }); ds.addRow(new Object[] { Integer.valueOf(17), "value1", "value2" }); ds.addRow(new Object[] { Integer.valueOf(18), "value3", "value4" }); client.getFoundSetManager().createDataSourceFromDataSet("test", ds, null, new String[] { "pk" }); BufferedDataSet separateDSs = new BufferedDataSet(new String[] { "pk", "test1", "test2" }, new int[] { IColumnTypes.INTEGER, IColumnTypes.TEXT, IColumnTypes.TEXT }); for (int i = 0; i < 943; i++) { separateDSs.addRow(new Object[] { Integer.valueOf(i), "value" + i + "0", "value" + i + "1" }); } client.getFoundSetManager().createDataSourceFromDataSet("testseparatefoundset", separateDSs, null, new String[] { "pk" }); BufferedDataSet relatedDS = new BufferedDataSet(new String[] { "relatedtestpk", "testpk", "relatedtest1", "relatedtest2" }, new int[] { IColumnTypes.INTEGER, IColumnTypes.INTEGER, IColumnTypes.TEXT, IColumnTypes.TEXT }); relatedDS.addRow(new Object[] { Integer.valueOf(1), Integer.valueOf(1), "relatedvalue111", "relatedvalue112" }); relatedDS.addRow(new Object[] { Integer.valueOf(2), Integer.valueOf(1), "relatedvalue121", "relatedvalue122" }); relatedDS.addRow(new Object[] { Integer.valueOf(3), Integer.valueOf(1), "relatedvalue131", "relatedvalue132" }); relatedDS.addRow(new Object[] { Integer.valueOf(4), Integer.valueOf(2), "relatedvalue241", "relatedvalue242" }); relatedDS.addRow(new Object[] { Integer.valueOf(5), Integer.valueOf(1), "relatedvalue111", "relatedvalue112" }); relatedDS.addRow(new Object[] { Integer.valueOf(6), Integer.valueOf(1), "relatedvalue121", "relatedvalue122" }); relatedDS.addRow(new Object[] { Integer.valueOf(7), Integer.valueOf(1), "relatedvalue131", "relatedvalue132" }); relatedDS.addRow(new Object[] { Integer.valueOf(8), Integer.valueOf(2), "relatedvalue241", "relatedvalue242" }); relatedDS.addRow(new Object[] { Integer.valueOf(9), Integer.valueOf(1), "relatedvalue111", "relatedvalue112" }); relatedDS.addRow(new Object[] { Integer.valueOf(10), Integer.valueOf(1), "relatedvalue121", "relatedvalue122" }); relatedDS.addRow(new Object[] { Integer.valueOf(11), Integer.valueOf(1), "relatedvalue131", "relatedvalue132" }); relatedDS.addRow(new Object[] { Integer.valueOf(12), Integer.valueOf(2), "relatedvalue241", "relatedvalue242" }); relatedDS.addRow(new Object[] { Integer.valueOf(13), Integer.valueOf(1), "relatedvalue111", "relatedvalue112" }); relatedDS.addRow(new Object[] { Integer.valueOf(14), Integer.valueOf(1), "relatedvalue121", "relatedvalue122" }); relatedDS.addRow(new Object[] { Integer.valueOf(15), Integer.valueOf(1), "relatedvalue131", "relatedvalue132" }); relatedDS.addRow(new Object[] { Integer.valueOf(16), Integer.valueOf(2), "relatedvalue241", "relatedvalue242" }); client.getFoundSetManager().createDataSourceFromDataSet("relatedtest", relatedDS, null, new String[] { "relatedtestpk" }); HashMap<String, IServer> serverProxies = new HashMap<String, IServer>(); serverProxies.put("_sv_inmem", new IServer() { @Override public ITable getTable(String tableName) throws RepositoryException, RemoteException { // TODO Auto-generated method stub return null; } @Override public ITable getTableBySqlname(String tableSQLName) throws RepositoryException, RemoteException { // TODO Auto-generated method stub return null; } @Override public List<String> getTableAndViewNames(boolean hideTemporary) throws RepositoryException, RemoteException { // TODO Auto-generated method stub return null; } @Override public List<String> getTableNames(boolean hideTempTables) throws RepositoryException, RemoteException { // TODO Auto-generated method stub return null; } @Override public Map<String, ITable> getInitializedTables() throws RepositoryException, RemoteException { // TODO Auto-generated method stub return null; } @Override public List<String> getViewNames(boolean hideTempViews) throws RepositoryException, RemoteException { // TODO Auto-generated method stub return null; } @Override public int getTableType(String tableName) throws RepositoryException, RemoteException { // TODO Auto-generated method stub return 0; } @Override public String getName() throws RemoteException { // TODO Auto-generated method stub return null; } @Override public boolean isValid() throws RemoteException { return true; } @Override public String getDatabaseProductName() throws RepositoryException, RemoteException { // TODO Auto-generated method stub return null; } @Override public String getQuotedIdentifier(String tableSqlName, String columnSqlName) throws RepositoryException, RemoteException { // TODO Auto-generated method stub return null; } @Override public String[] getDataModelClonesFrom() throws RemoteException { // TODO Auto-generated method stub return null; } }); solution.setServerProxies(serverProxies); Relation relation = solution.createNewRelation(validator, "test_to_relatedtest", "mem:test", "mem:relatedtest", ISQLJoin.LEFT_OUTER_JOIN); Column primaryColumn = ((Table)client.getFoundSetManager().getTable(relation.getPrimaryDataSource())).getColumn("pk"); Column foreignColumn = ((Table)client.getFoundSetManager().getTable(relation.getForeignDataSource())).getColumn("testpk"); relation.createNewRelationItem(client.getFoundSetManager(), primaryColumn, IBaseSQLCondition.EQUALS_OPERATOR, foreignColumn); } @Test public void foundsetReadByDataprovidersPushToServerReject() throws JSONException { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); Assert.assertNotNull(form); String full = NGUtils.formComponentPropertiesToString(form.getFormUI(), FullValueToJSONConverter.INSTANCE); JSONObject object = new JSONObject(full); JSONObject bean = object.getJSONObject("mycustombean"); JSONObject foundset = bean.getJSONObject("myfoundset"); Assert.assertEquals(18, foundset.getInt("serverSize")); JSONObject viewPort = foundset.getJSONObject("viewPort"); Assert.assertEquals(0, viewPort.getInt("startIndex")); // 15 is default preferredViewPortSize Assert.assertEquals(15, viewPort.getInt("size")); Assert.assertEquals(15, viewPort.getJSONArray("rows").length()); // fake incomming request for view port change. endpoint.incoming( "{\"methodname\":\"dataPush\",\"args\":{\"beanname\":\"mycustombean\",\"formname\":\"test\",\"changes\":{\"myfoundset\":[{\"newViewPort\":{\"startIndex\":0,\"size\":18}}]}},\"service\":\"formService\"}", true); String changes = NGUtils.formChangesToString(((Container)form.getFormUI()), FullValueToJSONConverter.INSTANCE); object = new JSONObject(changes).getJSONObject("changes"); bean = object.getJSONObject("mycustombean"); foundset = bean.getJSONObject("myfoundset"); Assert.assertEquals(18, foundset.getInt("serverSize")); viewPort = foundset.getJSONObject("viewPort"); Assert.assertEquals(0, viewPort.getInt("startIndex")); Assert.assertEquals(18, viewPort.getInt("size")); JSONArray rows = viewPort.getJSONArray("rows"); Assert.assertEquals(18, rows.length()); JSONObject row0 = rows.getJSONObject(0); Assert.assertEquals("value1", row0.getString("firstname")); Assert.assertEquals("value2", row0.getString("lastname")); JSONObject row1 = rows.getJSONObject(1); Assert.assertEquals("value3", row1.getString("firstname")); Assert.assertEquals("value4", row1.getString("lastname")); // fake an update endpoint.incoming( "{\"methodname\":\"dataPush\",\"args\":{\"beanname\":\"mycustombean\",\"formname\":\"test\",\"changes\":{\"myfoundset\":[{\"viewportDataChanged\":{\"_svyRowId\":\"" + row1.getString("_svyRowId") + "\",\"value\":\"value5\",\"dp\":\"lastname\"}}]}},\"service\":\"formService\"}", true); Assert.assertEquals("value4", form.getFormModel().getRecord(1).getValue("test2")); // not value 5 cause pushToServer is rejected! } @Test public void foundsetReadByDataprovidersPushToServerAllow() throws JSONException { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); Assert.assertNotNull(form); String full = NGUtils.formComponentPropertiesToString(form.getFormUI(), FullValueToJSONConverter.INSTANCE); JSONObject object = new JSONObject(full); JSONObject bean = object.getJSONObject("mycustombean"); JSONObject foundset = bean.getJSONObject("myfoundsetWithAllow"); Assert.assertEquals(18, foundset.getInt("serverSize")); JSONObject viewPort = foundset.getJSONObject("viewPort"); Assert.assertEquals(0, viewPort.getInt("startIndex")); // 15 is default preferredViewPortSize Assert.assertEquals(15, viewPort.getInt("size")); Assert.assertEquals(15, viewPort.getJSONArray("rows").length()); // fake incomming request for view port change. endpoint.incoming( "{\"methodname\":\"dataPush\",\"args\":{\"beanname\":\"mycustombean\",\"formname\":\"test\",\"changes\":{\"myfoundsetWithAllow\":[{\"newViewPort\":{\"startIndex\":0,\"size\":18}}]}},\"service\":\"formService\"}", true); String changes = NGUtils.formChangesToString(((Container)form.getFormUI()), FullValueToJSONConverter.INSTANCE); object = new JSONObject(changes).getJSONObject("changes"); bean = object.getJSONObject("mycustombean"); foundset = bean.getJSONObject("myfoundsetWithAllow"); Assert.assertEquals(18, foundset.getInt("serverSize")); viewPort = foundset.getJSONObject("viewPort"); Assert.assertEquals(0, viewPort.getInt("startIndex")); Assert.assertEquals(18, viewPort.getInt("size")); JSONArray rows = viewPort.getJSONArray("rows"); Assert.assertEquals(18, rows.length()); JSONObject row0 = rows.getJSONObject(0); Assert.assertEquals("value1", row0.getString("firstname")); Assert.assertEquals("value2", row0.getString("lastname")); JSONObject row1 = rows.getJSONObject(1); Assert.assertEquals("value3", row1.getString("firstname")); Assert.assertEquals("value4", row1.getString("lastname")); // fake an update endpoint.incoming( "{\"methodname\":\"dataPush\",\"args\":{\"beanname\":\"mycustombean\",\"formname\":\"test\",\"changes\":{\"myfoundsetWithAllow\":[{\"viewportDataChanged\":{\"_svyRowId\":\"" + row1.getString("_svyRowId") + "\",\"value\":\"value5\",\"dp\":\"lastname\"}}]}},\"service\":\"formService\"}", true); Assert.assertEquals("value5", form.getFormModel().getRecord(1).getValue("test2")); } @Test public void foundsetWithDynamicDataproviders() throws JSONException { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); WebFormComponent webComponent = form.getFormUI().getWebComponent("mydynamiccustombean"); FoundsetTypeSabloValue property = (FoundsetTypeSabloValue)webComponent.getProperty("myfoundset"); JSONArray json = new JSONArray("[{" + FoundsetTypeSabloValue.PREFERRED_VIEWPORT_SIZE + ":1}]"); property.browserUpdatesReceived(json, webComponent.getSpecification().getProperty("myfoundset"), new BrowserConverterContext(webComponent, PushToServerEnum.allow)); Assert.assertNotNull(form); String full = NGUtils.formComponentPropertiesToString(form.getFormUI(), FullValueToJSONConverter.INSTANCE); JSONObject object = new JSONObject(full); JSONObject bean = object.getJSONObject("mydynamiccustombean"); JSONObject foundset = bean.getJSONObject("myfoundset"); Assert.assertEquals(12, foundset.getInt("serverSize")); JSONObject viewPort = foundset.getJSONObject("viewPort"); Assert.assertEquals(0, viewPort.getInt("startIndex")); Assert.assertEquals(12, viewPort.getInt("size")); Assert.assertEquals(12, viewPort.getJSONArray("rows").length()); // fake incomming request for view port change. endpoint.incoming( "{\"methodname\":\"dataPush\",\"args\":{\"beanname\":\"mydynamiccustombean\",\"formname\":\"test\",\"changes\":{\"myfoundset\":[{\"newViewPort\":{\"startIndex\":0,\"size\":3}}]}},\"service\":\"formService\"}", true); String changes = NGUtils.formChangesToString(((Container)form.getFormUI()), FullValueToJSONConverter.INSTANCE); object = new JSONObject(changes).getJSONObject("changes"); bean = object.getJSONObject("mydynamiccustombean"); foundset = bean.getJSONObject("myfoundset"); Assert.assertEquals(12, foundset.getInt("serverSize")); viewPort = foundset.getJSONObject("viewPort"); Assert.assertEquals(0, viewPort.getInt("startIndex")); Assert.assertEquals(3, viewPort.getInt("size")); JSONArray rows = viewPort.getJSONArray("rows"); Assert.assertEquals(3, rows.length()); JSONObject row0 = rows.getJSONObject(0); Assert.assertEquals("relatedvalue111", row0.getString("dp1")); Assert.assertEquals("relatedvalue112", row0.getString("dp2")); JSONObject row1 = rows.getJSONObject(1); Assert.assertEquals("relatedvalue121", row1.getString("dp1")); Assert.assertEquals("relatedvalue122", row1.getString("dp2")); } @Test public void foundsetRelated() throws JSONException// change selected index in main foundset and related foundset should change { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); Assert.assertNotNull(form); BrowserConverterContext allowBrowserConverterContext2 = new BrowserConverterContext(form.getFormUI().getWebComponent("mydynamiccustombean"), PushToServerEnum.allow); FoundsetTypeSabloValue customBeanFoundSet = (FoundsetTypeSabloValue)form.getFormUI().getWebComponent("mycustombean").getRawPropertyValue("myfoundset", true); FoundsetTypeSabloValue dynamicBeanRelatedFoundset = (FoundsetTypeSabloValue)form.getFormUI().getWebComponent("mydynamiccustombean").getRawPropertyValue( "myfoundset", true); dynamicBeanRelatedFoundset.getViewPort().setBounds(1, 1); customBeanFoundSet.getFoundset().setSelectedIndex(1);//selection is now 0, so set to 1 and then back again customBeanFoundSet.getFoundset().setSelectedIndex(0); Assert.assertEquals(12, dynamicBeanRelatedFoundset.getViewPort().getSize()); Assert.assertEquals(0, dynamicBeanRelatedFoundset.getViewPort().getStartIndex()); dynamicBeanRelatedFoundset.getViewPort().setBounds(1, 1); StringWriter stringWriter = new StringWriter(); JSONWriter jsonWriter = new JSONWriter(stringWriter); dynamicBeanRelatedFoundset.addViewPort(jsonWriter); Assert.assertEquals("{\"startIndex\":1,\"size\":1,\"rows\":[{\"_svyRowId\":\"1.2;_1\",\"dp1\":\"relatedvalue121\",\"dp2\":\"relatedvalue122\"}]}", stringWriter.toString()); stringWriter.getBuffer().setLength(0); jsonWriter = new JSONWriter(stringWriter); dynamicBeanRelatedFoundset.changesToJSON(jsonWriter, new DataConversion(), allowBrowserConverterContext2); Assert.assertEquals( "{\"upd_serverSize\":12,\"upd_selectedRowIndexes\":[0],\"upd_viewPort\":{\"startIndex\":1,\"size\":1,\"rows\":[{\"_svyRowId\":\"1.2;_1\",\"dp1\":\"relatedvalue121\",\"dp2\":\"relatedvalue122\"}]}}", stringWriter.toString()); customBeanFoundSet.getFoundset().setSelectedIndex(1); dynamicBeanRelatedFoundset.getViewPort().setBounds(0, 1); stringWriter.getBuffer().setLength(0); jsonWriter = new JSONWriter(stringWriter); dynamicBeanRelatedFoundset.changesToJSON(jsonWriter, new DataConversion(), allowBrowserConverterContext2); Assert.assertEquals( "{\"upd_serverSize\":4,\"upd_selectedRowIndexes\":[0],\"upd_viewPort\":{\"startIndex\":0,\"size\":1,\"rows\":[{\"_svyRowId\":\"1.4;_0\",\"dp1\":\"relatedvalue241\",\"dp2\":\"relatedvalue242\"}]}}", stringWriter.toString()); } @Test public void setPreferredViewport() throws JSONException// change selected index in main foundset and related foundset should change { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); Assert.assertNotNull(form); WebFormComponent wc1 = form.getFormUI().getWebComponent("mycustombean"); WebFormComponent wc2 = form.getFormUI().getWebComponent("mydynamiccustombean"); FoundsetTypeSabloValue customBeanFoundSet = (FoundsetTypeSabloValue)wc1.getRawPropertyValue("myfoundset", true); FoundsetTypeSabloValue dynamicBeanRelatedFoundset = (FoundsetTypeSabloValue)wc2.getRawPropertyValue("myfoundset", true); BrowserConverterContext allowBrowserConverterContext2 = new BrowserConverterContext(wc1, PushToServerEnum.allow); dynamicBeanRelatedFoundset.getViewPort().setPreferredViewportSize(8); customBeanFoundSet.getFoundset().setSelectedIndex(1);//selection is now 0, so set to 1 and then back again customBeanFoundSet.getFoundset().setSelectedIndex(0); Assert.assertEquals(8, dynamicBeanRelatedFoundset.getViewPort().getSize()); Assert.assertEquals(0, dynamicBeanRelatedFoundset.getViewPort().getStartIndex()); StringWriter stringWriter = new StringWriter(); JSONWriter jsonWriter = new JSONWriter(stringWriter); dynamicBeanRelatedFoundset.toJSON(jsonWriter, new DataConversion(), allowBrowserConverterContext2); Assert.assertEquals( "{\"serverSize\":12,\"selectedRowIndexes\":[0],\"multiSelect\":false,\"hasMoreRows\":false,\"viewPort\":{\"startIndex\":0,\"size\":8,\"rows\":[{\"_svyRowId\":\"1.1;_0\",\"dp1\":\"relatedvalue111\",\"dp2\":\"relatedvalue112\"},{\"_svyRowId\":\"1.2;_1\",\"dp1\":\"relatedvalue121\",\"dp2\":\"relatedvalue122\"},{\"_svyRowId\":\"1.3;_2\",\"dp1\":\"relatedvalue131\",\"dp2\":\"relatedvalue132\"},{\"_svyRowId\":\"1.5;_3\",\"dp1\":\"relatedvalue111\",\"dp2\":\"relatedvalue112\"},{\"_svyRowId\":\"1.6;_4\",\"dp1\":\"relatedvalue121\",\"dp2\":\"relatedvalue122\"},{\"_svyRowId\":\"1.7;_5\",\"dp1\":\"relatedvalue131\",\"dp2\":\"relatedvalue132\"},{\"_svyRowId\":\"1.9;_6\",\"dp1\":\"relatedvalue111\",\"dp2\":\"relatedvalue112\"},{\"_svyRowId\":\"2.10;_7\",\"dp1\":\"relatedvalue121\",\"dp2\":\"relatedvalue122\"}]}}", stringWriter.toString()); stringWriter = new StringWriter(); jsonWriter = new JSONWriter(stringWriter); customBeanFoundSet.getFoundset().setSelectedIndex(1);//selection is now 0, so set to 1 and then back again dynamicBeanRelatedFoundset.changesToJSON(jsonWriter, new DataConversion(), allowBrowserConverterContext2); Assert.assertEquals( "{\"upd_serverSize\":4,\"upd_selectedRowIndexes\":[0],\"upd_viewPort\":{\"startIndex\":0,\"size\":4,\"rows\":[{\"_svyRowId\":\"1.4;_0\",\"dp1\":\"relatedvalue241\",\"dp2\":\"relatedvalue242\"},{\"_svyRowId\":\"1.8;_1\",\"dp1\":\"relatedvalue241\",\"dp2\":\"relatedvalue242\"},{\"_svyRowId\":\"2.12;_2\",\"dp1\":\"relatedvalue241\",\"dp2\":\"relatedvalue242\"},{\"_svyRowId\":\"2.16;_3\",\"dp1\":\"relatedvalue241\",\"dp2\":\"relatedvalue242\"}]}}", stringWriter.toString()); stringWriter = new StringWriter(); jsonWriter = new JSONWriter(stringWriter); customBeanFoundSet.getFoundset().setSelectedIndex(0); dynamicBeanRelatedFoundset.changesToJSON(jsonWriter, new DataConversion(), allowBrowserConverterContext2); Assert.assertEquals( "{\"upd_serverSize\":12,\"upd_selectedRowIndexes\":[0],\"upd_viewPort\":{\"startIndex\":0,\"size\":8,\"rows\":[{\"_svyRowId\":\"1.1;_0\",\"dp1\":\"relatedvalue111\",\"dp2\":\"relatedvalue112\"},{\"_svyRowId\":\"1.2;_1\",\"dp1\":\"relatedvalue121\",\"dp2\":\"relatedvalue122\"},{\"_svyRowId\":\"1.3;_2\",\"dp1\":\"relatedvalue131\",\"dp2\":\"relatedvalue132\"},{\"_svyRowId\":\"1.5;_3\",\"dp1\":\"relatedvalue111\",\"dp2\":\"relatedvalue112\"},{\"_svyRowId\":\"1.6;_4\",\"dp1\":\"relatedvalue121\",\"dp2\":\"relatedvalue122\"},{\"_svyRowId\":\"1.7;_5\",\"dp1\":\"relatedvalue131\",\"dp2\":\"relatedvalue132\"},{\"_svyRowId\":\"1.9;_6\",\"dp1\":\"relatedvalue111\",\"dp2\":\"relatedvalue112\"},{\"_svyRowId\":\"2.10;_7\",\"dp1\":\"relatedvalue121\",\"dp2\":\"relatedvalue122\"}]}}", stringWriter.toString()); } @Test public void foundsetViewportChangeData() throws JSONException, ServoyException// change rows in/near viewport { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); Assert.assertNotNull(form); WebFormComponent wc = form.getFormUI().getWebComponent("mycustombean"); FoundsetTypeSabloValue rawPropertyValue = (FoundsetTypeSabloValue)wc.getRawPropertyValue("myfoundset", true); // right now the viewport change monitor will ignore updates because the value wasn't yet sent to the client - so no use keeping track of changes FoundsetTypeViewport viewPort = rawPropertyValue.getViewPort(); viewPort.setBounds(1, 1); viewPort.changeMonitor.clearChanges(); rawPropertyValue.getFoundset().getRecord(0).startEditing(); rawPropertyValue.getFoundset().getRecord(0).setValue("test1", "not test1 any more"); rawPropertyValue.getFoundset().getRecord(0).stopEditing(); Assert.assertEquals(0, viewPort.changeMonitor.viewPortDataChangeMonitor.getViewPortChanges().size()); rawPropertyValue.getFoundset().getRecord(1).startEditing(); rawPropertyValue.getFoundset().getRecord(1).setValue("test2", "not test2 any more"); rawPropertyValue.getFoundset().getRecord(1).stopEditing(); Assert.assertEquals(0, viewPort.changeMonitor.viewPortDataChangeMonitor.getViewPortChanges().size()); // no simulate a send to client (from this point on, the change monitor will be interested in server side changes) rawPropertyValue.toJSON(new JSONStringer(), new DataConversion(), new BrowserConverterContext(wc, PushToServerEnum.allow)); rawPropertyValue.getFoundset().getRecord(0).startEditing(); rawPropertyValue.getFoundset().getRecord(0).setValue("test1", "not test1 any more nor not test1 any more"); rawPropertyValue.getFoundset().getRecord(0).stopEditing(); Assert.assertEquals(0, viewPort.changeMonitor.viewPortDataChangeMonitor.getViewPortChanges().size()); rawPropertyValue.getFoundset().getRecord(1).startEditing(); rawPropertyValue.getFoundset().getRecord(1).setValue("test2", "not test2 any more nor not test2 any more"); rawPropertyValue.getFoundset().getRecord(1).stopEditing(); Assert.assertEquals(1, viewPort.changeMonitor.viewPortDataChangeMonitor.getViewPortChanges().size()); } @Test public void foundsetViewportAllRecordChangedAndDeleted() throws JSONException, ServoyException// change rows in/near viewport { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); Assert.assertNotNull(form); WebFormComponent wc = form.getFormUI().getWebComponent("mycustombean"); FoundsetTypeSabloValue rawPropertyValue = (FoundsetTypeSabloValue)wc.getRawPropertyValue("myfoundset", true); BrowserConverterContext allowBrowserConverterContext = new BrowserConverterContext(wc, PushToServerEnum.allow); FoundsetTypeViewport viewPort = rawPropertyValue.getViewPort(); viewPort.setBounds(0, form.getFormModel().getSize()); StringWriter stringWriter = new StringWriter(); JSONWriter jsonWriter = new JSONWriter(stringWriter); rawPropertyValue.toJSON(jsonWriter, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals( "{\"serverSize\":18,\"selectedRowIndexes\":[0],\"multiSelect\":false,\"hasMoreRows\":false,\"viewPort\":{\"startIndex\":0,\"size\":18,\"rows\":[{\"_svyRowId\":\"1.1;_0\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.2;_1\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.3;_2\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.4;_3\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.5;_4\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.6;_5\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.7;_6\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.8;_7\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.9;_8\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.10;_9\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.11;_10\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.12;_11\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.13;_12\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.14;_13\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.15;_14\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.16;_15\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.17;_16\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.18;_17\",\"lastname\":\"value4\",\"firstname\":\"value3\"}]}}", stringWriter.toString()); form.getFormModel().fireFoundSetChanged(); form.getFormModel().deleteRecord(0); stringWriter = new StringWriter(); jsonWriter = new JSONWriter(stringWriter); rawPropertyValue.toJSON(jsonWriter, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals( "{\"serverSize\":17,\"selectedRowIndexes\":[0],\"multiSelect\":false,\"hasMoreRows\":false,\"viewPort\":{\"startIndex\":0,\"size\":17,\"rows\":[{\"_svyRowId\":\"1.2;_0\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.3;_1\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.4;_2\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.5;_3\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.6;_4\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.7;_5\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.8;_6\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.9;_7\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.10;_8\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.11;_9\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.12;_10\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.13;_11\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.14;_12\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.15;_13\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.16;_14\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.17;_15\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.18;_16\",\"lastname\":\"value4\",\"firstname\":\"value3\"}]}}", stringWriter.toString()); } @Test public void foundsetViewportAddRemove() throws JSONException, ServoyException// add / remove rows in viewport, near viewport { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); Assert.assertNotNull(form); FoundsetTypeSabloValue rawPropertyValue = (FoundsetTypeSabloValue)form.getFormUI().getWebComponent("mycustombean").getRawPropertyValue("myfoundset", true); FoundsetTypeViewport viewPort = rawPropertyValue.getViewPort(); viewPort.setBounds(1, 1); IFoundSetInternal foundSet = rawPropertyValue.getFoundset(); foundSet.newRecord(1, false); Assert.assertEquals(1, viewPort.size); Assert.assertEquals(1, viewPort.startIndex); Assert.assertEquals(19, rawPropertyValue.getFoundset().getSize()); StringWriter stringWriter = new StringWriter(); JSONWriter jsonWriter = new JSONWriter(stringWriter); rawPropertyValue.addViewPort(jsonWriter); Assert.assertEquals("{\"startIndex\":1,\"size\":1,\"rows\":[{\"_svyRowId\":\".null;_1\",\"lastname\":null,\"firstname\":null}]}", stringWriter.toString()); foundSet.deleteRecord(1); Assert.assertEquals(18, rawPropertyValue.getFoundset().getSize()); stringWriter.getBuffer().setLength(0); jsonWriter = new JSONWriter(stringWriter); rawPropertyValue.addViewPort(jsonWriter); Assert.assertEquals("{\"startIndex\":1,\"size\":1,\"rows\":[{\"_svyRowId\":\"1.2;_1\",\"lastname\":\"value4\",\"firstname\":\"value3\"}]}", stringWriter.toString()); foundSet.newRecord(0, false); stringWriter.getBuffer().setLength(0); jsonWriter = new JSONWriter(stringWriter); rawPropertyValue.addViewPort(jsonWriter); Assert.assertEquals("{\"startIndex\":1,\"size\":1,\"rows\":[{\"_svyRowId\":\"1.1;_1\",\"lastname\":\"value2\",\"firstname\":\"value1\"}]}", stringWriter.toString()); foundSet.newRecord(3, false); Assert.assertEquals(20, rawPropertyValue.getFoundset().getSize()); stringWriter.getBuffer().setLength(0); jsonWriter = new JSONWriter(stringWriter); rawPropertyValue.addViewPort(jsonWriter); Assert.assertEquals("{\"startIndex\":1,\"size\":1,\"rows\":[{\"_svyRowId\":\"1.1;_1\",\"lastname\":\"value2\",\"firstname\":\"value1\"}]}", stringWriter.toString()); //delete records added in this test foundSet.deleteRecord(0); foundSet.deleteRecord(2);//last record is now at index 2 Assert.assertEquals(18, rawPropertyValue.getFoundset().getSize()); } @Test public void foundsetChangeMonitorChangeFlags() throws ServoyException { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); Assert.assertNotNull(form); FoundsetTypeSabloValue rawPropertyValue = (FoundsetTypeSabloValue)form.getFormUI().getWebComponent("mycustombean").getRawPropertyValue("myfoundset", true); IFoundSetInternal foundSet = rawPropertyValue.getFoundset(); foundSet.newRecord(0, false); Assert.assertEquals(FoundsetTypeChangeMonitor.SEND_FOUNDSET_SIZE | FoundsetTypeChangeMonitor.SEND_SELECTED_INDEXES, rawPropertyValue.changeMonitor.changeFlags); foundSet.deleteRecord(0); Assert.assertEquals(FoundsetTypeChangeMonitor.SEND_FOUNDSET_SIZE | FoundsetTypeChangeMonitor.SEND_SELECTED_INDEXES, rawPropertyValue.changeMonitor.changeFlags); } @Test public void largeFoundsetUsage() throws JSONException { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); Assert.assertNotNull(form); WebFormComponent wc = form.getFormUI().getWebComponent("mycustomseparatefoundsetbean"); FoundsetTypeSabloValue rawPropertyValue = (FoundsetTypeSabloValue)wc.getRawPropertyValue("myfoundset", true); BrowserConverterContext allowBrowserConverterContext = new BrowserConverterContext(wc, PushToServerEnum.allow); FoundsetTypeViewport viewPort = rawPropertyValue.getViewPort(); viewPort.setBounds(0, 1); StringWriter stringWriter = new StringWriter(); JSONWriter jsonWriter = new JSONWriter(stringWriter); rawPropertyValue.toJSON(jsonWriter, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals( "{\"serverSize\":200,\"selectedRowIndexes\":[0],\"multiSelect\":false,\"hasMoreRows\":true,\"viewPort\":{\"startIndex\":0,\"size\":1,\"rows\":[{\"_svyRowId\":\"1.0;_0\",\"lastname\":\"value01\",\"firstname\":\"value00\"}]}}", stringWriter.toString()); // foundset loads more records due to server side access - client should be aware of new size and hasMoreRows rawPropertyValue.getFoundset().getRecord(200); StringWriter stringWriter2 = new StringWriter(); JSONWriter jsonWriter2 = new JSONWriter(stringWriter2); rawPropertyValue.changesToJSON(jsonWriter2, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals("{\"upd_serverSize\":799}", stringWriter2.toString()); // foundset loads more records due to client side wanting more records viewPort.setBounds(800, 1); StringWriter stringWriter3 = new StringWriter(); JSONWriter jsonWriter3 = new JSONWriter(stringWriter3); rawPropertyValue.changesToJSON(jsonWriter3, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals( "{\"upd_serverSize\":943,\"upd_hasMoreRows\":false,\"upd_viewPort\":{\"startIndex\":800,\"size\":1,\"rows\":[{\"_svyRowId\":\"3.800;_800\",\"lastname\":\"value8001\",\"firstname\":\"value8000\"}]}}", stringWriter3.toString()); } @Test public void foundsetViewportBounds() throws JSONException { IWebFormController form = (IWebFormController)client.getFormManager().showFormInCurrentContainer("test"); Assert.assertNotNull(form); WebFormComponent wc = form.getFormUI().getWebComponent("mycustombean"); FoundsetTypeSabloValue rawPropertyValue = (FoundsetTypeSabloValue)wc.getRawPropertyValue("myfoundset", true); BrowserConverterContext allowBrowserConverterContext = new BrowserConverterContext(wc, PushToServerEnum.allow); FoundsetTypeViewport viewPort = rawPropertyValue.getViewPort(); viewPort.setBounds(0, 2); StringWriter stringWriter = new StringWriter(); JSONWriter jsonWriter = new JSONWriter(stringWriter); rawPropertyValue.toJSON(jsonWriter, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals( "{\"serverSize\":18,\"selectedRowIndexes\":[0],\"multiSelect\":false,\"hasMoreRows\":false,\"viewPort\":{\"startIndex\":0,\"size\":2,\"rows\":[{\"_svyRowId\":\"1.1;_0\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.2;_1\",\"lastname\":\"value4\",\"firstname\":\"value3\"}]}}", stringWriter.toString()); //changes to json //add changes test viewPort.setBounds(1, 1); StringWriter stringWriter2 = new StringWriter(); JSONWriter jsonWriter2 = new JSONWriter(stringWriter2); rawPropertyValue.toJSON(jsonWriter2, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals( "{\"serverSize\":18,\"selectedRowIndexes\":[0],\"multiSelect\":false,\"hasMoreRows\":false,\"viewPort\":{\"startIndex\":1,\"size\":1,\"rows\":[{\"_svyRowId\":\"1.2;_1\",\"lastname\":\"value4\",\"firstname\":\"value3\"}]}}", stringWriter2.toString()); viewPort.loadExtraRecords(-1); StringWriter stringWriter3 = new StringWriter(); JSONWriter jsonWriter3 = new JSONWriter(stringWriter3); rawPropertyValue.changesToJSON(jsonWriter3, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals( "{\"upd_viewPort\":{\"startIndex\":0,\"size\":2,\"upd_rows\":[{\"rows\":[{\"_svyRowId\":\"1.1;_0\",\"lastname\":\"value2\",\"firstname\":\"value1\"}],\"startIndex\":0,\"endIndex\":2,\"type\":1}]}}", stringWriter3.toString()); viewPort.loadExtraRecords(-1); stringWriter3 = new StringWriter(); jsonWriter3 = new JSONWriter(stringWriter3); rawPropertyValue.changesToJSON(jsonWriter3, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals("{\"upd_viewPort\":{\"upd_rows\":[{\"rows\":[],\"startIndex\":0,\"endIndex\":2,\"type\":1}]}}", stringWriter3.toString()); viewPort.loadExtraRecords(16); stringWriter3 = new StringWriter(); jsonWriter3 = new JSONWriter(stringWriter3); rawPropertyValue.changesToJSON(jsonWriter3, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals( "{\"upd_viewPort\":{\"startIndex\":0,\"size\":18,\"upd_rows\":[{\"rows\":[{\"_svyRowId\":\"1.3;_2\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.4;_3\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.5;_4\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.6;_5\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.7;_6\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"1.8;_7\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"1.9;_8\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.10;_9\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.11;_10\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.12;_11\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.13;_12\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.14;_13\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.15;_14\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.16;_15\",\"lastname\":\"value4\",\"firstname\":\"value3\"},{\"_svyRowId\":\"2.17;_16\",\"lastname\":\"value2\",\"firstname\":\"value1\"},{\"_svyRowId\":\"2.18;_17\",\"lastname\":\"value4\",\"firstname\":\"value3\"}],\"startIndex\":2,\"endIndex\":18,\"type\":1}]}}", stringWriter3.toString()); viewPort.loadExtraRecords(1); stringWriter3 = new StringWriter(); jsonWriter3 = new JSONWriter(stringWriter3); rawPropertyValue.changesToJSON(jsonWriter3, new DataConversion(), allowBrowserConverterContext); Assert.assertEquals("{\"n\":true}", stringWriter3.toString()); } }