diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index c7b81da..979883b 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -1,5 +1,7 @@ - + + + @@ -29,7 +31,9 @@ - + + + @@ -59,7 +63,9 @@ - + + + @@ -89,7 +95,9 @@ - + + + @@ -128,7 +136,9 @@ uses - + + + @@ -158,7 +168,9 @@ - + + + @@ -188,7 +200,9 @@ - + + + @@ -218,7 +232,9 @@ - + + + diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java index 3e296fb..358d7da 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/GeoPortalDataEntryApp.java @@ -403,7 +403,7 @@ public class GeoPortalDataEntryApp implements EntryPoint { treemapOrderedGNAProfiles.put(order, geonaForm); } - if (getNumberOfCards() == expectedCards) { + if (getNumberOfCards() >= expectedCards) { mainTabPanel.setLoaderVisible("Loading...", false); // ordered values Collection gnaCardsModels = treemapOrderedGNAProfiles.values(); diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.java index 8ae272b..1b198bc 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/GeonaMainTabPanel.java @@ -25,7 +25,6 @@ import org.gcube.portlets.user.geoportaldataentry.client.ui.utils.LoaderIcon; import com.github.gwtbootstrap.client.ui.Alert; import com.github.gwtbootstrap.client.ui.Button; import com.github.gwtbootstrap.client.ui.Dropdown; -import com.github.gwtbootstrap.client.ui.Heading; import com.github.gwtbootstrap.client.ui.Hero; import com.github.gwtbootstrap.client.ui.NavLink; import com.github.gwtbootstrap.client.ui.PageHeader; diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/form/GeonaDataEntryMainForm.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/form/GeonaDataEntryMainForm.java index 468503a..50448d8 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/form/GeonaDataEntryMainForm.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/client/ui/form/GeonaDataEntryMainForm.java @@ -168,7 +168,7 @@ public class GeonaDataEntryMainForm extends Composite { listGDB.add(form.getFormDataBean()); } - listGeonaFormObjects.add(new GeoNaFormDataObject(listGDB, card.getGeonaFormModel().getFormCard())); + listGeonaFormObjects.add(new GeoNaFormDataObject(listGDB, card.getGeonaFormModel().getGcubeProfile())); } appManagerBus.fireEvent(new SaveGeonaDataFormsEvent(listGeonaFormObjects)); } else { diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java index 9a1e463..27336f3 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/server/GeoportalDataEntryServiceImpl.java @@ -1,12 +1,14 @@ package org.gcube.portlets.user.geoportaldataentry.server; +import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.gcube.application.geoportal.common.model.legacy.Concessione; -import org.gcube.application.geoportal.common.model.legacy.report.ValidationReport; import org.gcube.application.geoportal.common.model.rest.AddSectionToConcessioneRequest; import org.gcube.application.geoportal.common.model.rest.TempFile; import org.gcube.application.geoportal.common.rest.MongoConcessioni; @@ -25,9 +27,9 @@ import org.gcube.application.geoportalcommon.shared.config.RoleRights; import org.gcube.application.geoportalcommon.shared.config.RoleRights.OPERATION_TYPE; import org.gcube.application.geoportalcommon.shared.exception.GNAConfigException; import org.gcube.application.geoportalcommon.shared.geoportalconfig.DocumentConfigDV; +import org.gcube.application.geoportalcommon.shared.geoportalconfig.GcubeProfileDV; import org.gcube.application.geoportalcommon.shared.products.ConcessioneDV; import org.gcube.application.geoportalcommon.shared.products.content.WorkspaceContentDV; -import org.gcube.application.geoportalcommon.shared.products.model.ValidationReportDV; import org.gcube.application.geoportalcommon.shared.products.paths.FileSetPathsDV; import org.gcube.common.portal.PortalContext; import org.gcube.portlets.user.geoportaldataentry.client.ConstantsGeoPortalDataEntryApp.RECORD_TYPE; @@ -46,6 +48,9 @@ import org.gcube.vomanagement.usermanagement.exception.UserRetrievalFault; import org.gcube.vomanagement.usermanagement.impl.LiferayRoleManager; import org.gcube.vomanagement.usermanagement.model.GCubeRole; import org.gcube.vomanagement.usermanagement.model.GCubeUser; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -86,6 +91,77 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen return profile; } + + private JSONObject genericDatasetBeanToJSON(GenericDatasetBean gdb) throws JSONException { + + JSONObject sectJSONObject = JSONObjecOrdered.instance(); + + LinkedHashMap> mapFields = gdb.getFormDataEntryFields(); + System.out.println("Map ordered: "+mapFields); + for (String key : mapFields.keySet()) { + List listValues = mapFields.get(key); + if (listValues == null || listValues.isEmpty()) { + continue; + } + + // key/value as string + if (listValues.size() == 1) { + sectJSONObject.put(key, listValues.get(0)); + continue; + } + + // value is a list + JSONArray array = new JSONArray(); + for (String value : listValues) { + array.put(value); + } + + sectJSONObject.put(key, array); + } + + return sectJSONObject; + + } + + /** + * Merge "source" into "target". If fields have equal name, merge them recursively. + * @return the merged object (target). + */ + public static JSONObject deepMerge(JSONObject source, JSONObject target) throws JSONException { + for (String key: JSONObject.getNames(source)) { + Object value = source.get(key); + if (!target.has(key)) { + // new value for "key": + target.put(key, value); + } else { + // existing value for "key" - recursively deep merge: + if (value instanceof JSONObject) { + JSONObject valueJson = (JSONObject)value; + deepMerge(valueJson, target.getJSONObject(key)); + } else { + target.put(key, value); + } + } + } + return target; + } + + public static class JSONObjecOrdered { + + public static JSONObject instance() { + JSONObject jsonObject = new JSONObject(); + try { + Field changeMap = jsonObject.getClass().getDeclaredField("map"); + changeMap.setAccessible(true); + changeMap.set(jsonObject, new LinkedHashMap<>()); + changeMap.setAccessible(false); + } catch (IllegalAccessException | NoSuchFieldException e) { + } + return jsonObject; + } + } + + /** * Save geona data forms. @@ -98,36 +174,83 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen public CommitReport saveGeonaDataForms(List listGeonaFormObjects) throws Exception { LOG.info("saveGeonaDataForms called"); - HashMap> toMap = new HashMap>(); - - for (GeoNaFormDataObject geoNaFormDataObject : listGeonaFormObjects) { - - ProjectFormCard theType = geoNaFormDataObject.getTheType(); - List listForm = toMap.get(theType); - if (listForm == null) { - listForm = new ArrayList(); - } - - listForm.add(geoNaFormDataObject); - toMap.put(theType, listForm); - } - if (LOG.isDebugEnabled()) - prettyPrintClientDataEntryMap(toMap); - - LOG.debug("Built map with form data: " + toMap); - GCubeUser user = SessionUtil.getCurrentUser(this.getThreadLocalRequest()); - - Concessione concessioneNew; + String mongoId = null; MongoServiceUtil serviceUtil = new MongoServiceUtil(); MongoConcessioni clientMongo = null; try { - + GCubeUser user = SessionUtil.getCurrentUser(this.getThreadLocalRequest()); + SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); clientMongo = serviceUtil.getInstanceMongoConcessioni(); + + JSONObject rootDocument = JSONObjecOrdered.instance(); + for (GeoNaFormDataObject geoNaFormDataObject : listGeonaFormObjects) { + List listGDB = geoNaFormDataObject.getListGDB(); + + GcubeProfileDV profile = geoNaFormDataObject.getGcubeProfileDV(); + LOG.debug("The profile is: " + profile); + + String jsonPathExp = String.format("%s%s", profile.getParentName(), profile.getSectionName()); + LOG.debug("The json path to build: " + jsonPathExp); + //jsonPathExp = "$.chidl1.child2.child3"; + + String toJsonPathExp = jsonPathExp.replaceFirst("\\$", ""); + + JSONObject sectRootObject = JSONObjecOrdered.instance(); + for (GenericDatasetBean gdb : listGDB) { + + JSONObject jsonObject = genericDatasetBeanToJSON(gdb); + LOG.debug("Adding section : " + jsonObject); + String[] jsonPathDeep = toJsonPathExp.split("\\."); + LOG.trace("jsonPathDeep: " + Arrays.asList(jsonPathDeep) + " size: " + jsonPathDeep.length); + + // ROOT $. + if (jsonPathDeep.length == 0) { + sectRootObject = deepMerge(jsonObject, sectRootObject); + //System.out.println("jsonPathDeep.length==0: " + sectRootObject.toString(4)); + //rootDocument.put(jsonPathDeep[0], sectRootObject); + rootDocument = deepMerge(sectRootObject, rootDocument); + } + + // DEPTH >= 1 + if (jsonPathDeep.length > 1) { + sectRootObject.put(jsonPathDeep[jsonPathDeep.length - 1], jsonObject); + JSONObject deepJSON = sectRootObject; + System.out.println("sectRootObject: " + sectRootObject.toString()); + for (int i = jsonPathDeep.length - 2; i > 0; i--) { + JSONObject newOne = JSONObjecOrdered.instance(); + newOne.put(jsonPathDeep[i], deepJSON); + deepJSON = newOne; + } + System.out.println("ext deepJSON: " + deepJSON); + rootDocument = deepMerge(deepJSON, rootDocument); + } + + } + + System.out.println("Partial Root Document is: "+rootDocument); + } + + System.out.println("Final Document is: "+rootDocument); + + return null; +// for (ProjectFormCard geoNaFormDataObject : toMap.keySet()) { +// +// List list = toMap.get(geoNaFormDataObject); +// List listGDB = list.get(0).getListGDB(); +// GenericDatasetBean idp = listGDB.get(0); +// +// idp.getFormDataEntryFields(); +// +// geoNaFormDataObject. +// } +// + /* + // Saving Data // Informazioni di Progetto List list = toMap.get(ProjectFormCard.INFORMAZIONI_DI_PROGETTO); @@ -141,9 +264,11 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen LOG.debug(ProjectFormCard.INFORMAZIONI_DI_PROGETTO + " building with client obj: " + idp); Concessione concessione = ConvertToServiceModel.toConcessione(idp, user); LOG.debug("Built " + ProjectFormCard.INFORMAZIONI_DI_PROGETTO + " as server obj: " + concessione); - + // Register New Concessione concessioneNew = clientMongo.createNew(concessione); + + // ABSTRACT_RELAZIONE_DI_SCAVO list = toMap.get(ProjectFormCard.ABSTRACT_RELAZIONE_DI_SCAVO); @@ -359,40 +484,40 @@ public class GeoportalDataEntryServiceImpl extends RemoteServiceServlet implemen "Error occurred on saving data, try again or contact the support. Error: " + e.getMessage()); } - try { - - Concessione concessione; - if (clientMongo != null && mongoId != null) { - SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); - concessione = clientMongo.publish(mongoId); - // server report - ValidationReport report = concessione.getReport(); - LOG.info("ValidationReport: " + report); - - // to client - CommitReport cRep = new CommitReport(); - // cRep.setRecordId(concessione.getId()); - cRep.setMongoId(concessione.getMongo_id()); - ValidationReportDV vr = ConvertToDataViewModel.toValidationReport(report); - cRep.setValidationReportDV(vr); - - return cRep; - } else - throw new Exception("MongoId or Client not found"); - - } catch (Exception e) { - LOG.error("Error on commiting data: ", e); - throw new Exception("Error occurred on saving data. Error: " + e.getMessage()); - } finally { -// if(manager!=null) { -// try { -// manager.shutdown(); -// }catch (Exception e) { -// //silent -// } -// -// } - } +// try { +// +// Concessione concessione; +// if (clientMongo != null && mongoId != null) { +// SessionUtil.getCurrentContext(this.getThreadLocalRequest(), true); +// concessione = clientMongo.publish(mongoId); +// // server report +// ValidationReport report = concessione.getReport(); +// LOG.info("ValidationReport: " + report); +// +// // to client +// CommitReport cRep = new CommitReport(); +// // cRep.setRecordId(concessione.getId()); +// cRep.setMongoId(concessione.getMongo_id()); +// ValidationReportDV vr = ConvertToDataViewModel.toValidationReport(report); +// cRep.setValidationReportDV(vr); +// +// return cRep; +// } else +// throw new Exception("MongoId or Client not found"); +// +// } catch (Exception e) { +// LOG.error("Error on commiting data: ", e); +// throw new Exception("Error occurred on saving data. Error: " + e.getMessage()); +// } finally { +//// if(manager!=null) { +//// try { +//// manager.shutdown(); +//// }catch (Exception e) { +//// //silent +//// } +//// +//// } +// } } diff --git a/src/main/java/org/gcube/portlets/user/geoportaldataentry/shared/GeoNaFormDataObject.java b/src/main/java/org/gcube/portlets/user/geoportaldataentry/shared/GeoNaFormDataObject.java index 45479c2..a229581 100644 --- a/src/main/java/org/gcube/portlets/user/geoportaldataentry/shared/GeoNaFormDataObject.java +++ b/src/main/java/org/gcube/portlets/user/geoportaldataentry/shared/GeoNaFormDataObject.java @@ -3,27 +3,26 @@ package org.gcube.portlets.user.geoportaldataentry.shared; import java.io.Serializable; import java.util.List; -import org.gcube.portlets.user.geoportaldataentry.client.ProjectFormCard; +import org.gcube.application.geoportalcommon.shared.geoportalconfig.GcubeProfileDV; import org.gcube.portlets.widgets.mpformbuilder.shared.GenericDatasetBean; -public class GeoNaFormDataObject implements Serializable{ - +public class GeoNaFormDataObject implements Serializable { + /** * */ - private static final long serialVersionUID = 3620244260086172039L; - + private static final long serialVersionUID = 1084036362952974474L; private List listGDB; - private ProjectFormCard theType; - - public GeoNaFormDataObject(){ - + private GcubeProfileDV gcubeProfileDV; + + public GeoNaFormDataObject() { + } - public GeoNaFormDataObject(List listGDB, ProjectFormCard theType) { + public GeoNaFormDataObject(List listGDB, GcubeProfileDV gcubeProfileDV) { super(); this.listGDB = listGDB; - this.theType = theType; + this.gcubeProfileDV = gcubeProfileDV; } public List getListGDB() { @@ -33,17 +32,24 @@ public class GeoNaFormDataObject implements Serializable{ public void setListGDB(List listGDB) { this.listGDB = listGDB; } - public ProjectFormCard getTheType() { - return theType; + + public GcubeProfileDV getGcubeProfileDV() { + return gcubeProfileDV; } - public void setTheType(ProjectFormCard theType) { - this.theType = theType; + + public void setGcubeProfileDV(GcubeProfileDV gcubeProfileDV) { + this.gcubeProfileDV = gcubeProfileDV; } @Override public String toString() { - return "GeoNaFormDataObject [listGDB=" + listGDB + ", theType=" + theType + "]"; + StringBuilder builder = new StringBuilder(); + builder.append("GeoNaFormDataObject [listGDB="); + builder.append(listGDB); + builder.append(", gcubeProfileDV="); + builder.append(gcubeProfileDV); + builder.append("]"); + return builder.toString(); } - } diff --git a/src/test/java/org/gcube/portlets/user/geoportaldataentry/client/TestClass.java b/src/test/java/org/gcube/portlets/user/geoportaldataentry/TestClass.java similarity index 98% rename from src/test/java/org/gcube/portlets/user/geoportaldataentry/client/TestClass.java rename to src/test/java/org/gcube/portlets/user/geoportaldataentry/TestClass.java index 4119769..f6146bc 100644 --- a/src/test/java/org/gcube/portlets/user/geoportaldataentry/client/TestClass.java +++ b/src/test/java/org/gcube/portlets/user/geoportaldataentry/TestClass.java @@ -1,4 +1,4 @@ -package org.gcube.portlets.user.geoportaldataentry.client; +package org.gcube.portlets.user.geoportaldataentry; import static org.gcube.application.geoportal.client.GeoportalAbstractPlugin.mongoConcessioni; diff --git a/src/test/java/org/gcube/portlets/user/geoportaldataentry/WriteDocument.java b/src/test/java/org/gcube/portlets/user/geoportaldataentry/WriteDocument.java new file mode 100644 index 0000000..5f60afb --- /dev/null +++ b/src/test/java/org/gcube/portlets/user/geoportaldataentry/WriteDocument.java @@ -0,0 +1,196 @@ +package org.gcube.portlets.user.geoportaldataentry; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.gcube.application.geoportalcommon.MockDocumentConfigurationReader; +import org.gcube.application.geoportalcommon.shared.geoportalconfig.GcubeProfileDV; +import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.portlets.user.geoportaldataentry.shared.GeoNaFormDataObject; +import org.gcube.portlets.widgets.mpformbuilder.shared.GenericDatasetBean; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Test; + +import com.google.gwt.dev.util.collect.HashMap; + +public class WriteDocument { + + private static String TOKEN = ""; + private static String CONTEXT = "/gcube/devsec/devVRE"; + private static String USERNAME = "francesco.mangiacrapa"; + + // @Before + public void init() { + ScopeProvider.instance.set(CONTEXT); + } + + //@Test + public void writeMockJson() throws Exception { + + List listGeonaFormObjects = new ArrayList(); + MockDocumentConfigurationReader mock = new MockDocumentConfigurationReader(); + System.out.println(mock.getListDocumentConfig()); + + LinkedHashMap> formDataEntryFields = new LinkedHashMap>(); + formDataEntryFields.put("Title", Arrays.asList("My Title")); + formDataEntryFields.put("My Desr", Arrays.asList("My Descr Value")); + formDataEntryFields.put("Field1", Arrays.asList("Field1 Value")); + + List listGDC = new ArrayList(); + GenericDatasetBean genericDatasetBean = new GenericDatasetBean(); + genericDatasetBean.setFormDataEntryFields(formDataEntryFields); + listGDC.add(genericDatasetBean); +// GenericDatasetBean gdb = new GenericDatasetBean(null, formDataEntryFields, null); +// +// for (GenericDatasetBean genericDatasetBean : listGDC) { +// genericDatasetBean +// } + + GeoNaFormDataObject gnform = new GeoNaFormDataObject(listGDC, + mock.getListDocumentConfig().get(0).getConfiguration().getGcubeProfiles().get(1)); + System.out.println(gnform); + + listGeonaFormObjects.add(gnform); + + JSONObject rootDocument = JSONObjecOrdered.instance(); + for (GeoNaFormDataObject geoNaFormDataObject : listGeonaFormObjects) { + + List listGDB = geoNaFormDataObject.getListGDB(); + + GcubeProfileDV profile = geoNaFormDataObject.getGcubeProfileDV(); + System.out.println("The profile is: " + profile); + + String jsonPathExp = String.format("%s%s", profile.getParentName(), profile.getSectionName()); + //jsonPathExp = "$.chidl1.child2.child3"; + + jsonPathExp = jsonPathExp.replaceFirst("\\$", ""); + System.out.println("The json path to build: " + jsonPathExp); + + JSONObject sectRootObject = JSONObjecOrdered.instance(); + + for (GenericDatasetBean gdb : listGDB) { + + JSONObject jsonObject = genericDatasetBeanToJSON(gdb); + String sectionToString = jsonObject.toString(); + System.out.println("Adding section : " + sectionToString); + + String[] jsonPathDeep = jsonPathExp.split("\\."); + + System.out.println("jsonPathDeep: " + Arrays.asList(jsonPathDeep) + " size: " + jsonPathDeep.length); + + // ROOT $. + if (jsonPathDeep.length == 0) { + sectRootObject = deepMerge(jsonObject, sectRootObject); + System.out.println("JSON:"+sectRootObject); + //rootDocument.put(jsonPathDeep[0], sectRootObject); + rootDocument = deepMerge(sectRootObject, rootDocument); + } + + // DEPTH >= 1 + if (jsonPathDeep.length > 1) { + sectRootObject.put(jsonPathDeep[jsonPathDeep.length - 1], jsonObject); + JSONObject deepJSON = sectRootObject; + System.out.println("sectRootObject: " + sectRootObject); + for (int i = jsonPathDeep.length - 2; i > 0; i--) { + JSONObject newOne = JSONObjecOrdered.instance(); + newOne.put(jsonPathDeep[i], deepJSON); + deepJSON = newOne; + } + System.out.println("ext deepJSON: " + deepJSON); + rootDocument = deepMerge(deepJSON, rootDocument); + } + + } + System.out.println("Document: " + rootDocument); // Print it with specified indentation + + } + } + + + public static class JSONObjecOrdered { + + public static JSONObject instance() { + JSONObject jsonObject = new JSONObject(); + try { + Field changeMap = jsonObject.getClass().getDeclaredField("map"); + changeMap.setAccessible(true); + changeMap.set(jsonObject, new LinkedHashMap<>()); + changeMap.setAccessible(false); + } catch (IllegalAccessException | NoSuchFieldException e) { + } + return jsonObject; + } + } + + private JSONObject innerJSONBuilder(JSONObject source, String key, JSONObject jsonValue) throws JSONException { + + source.put(key, jsonValue); + System.out.println("innerJSONBuilder: " + source.toString(4)); + return source.getJSONObject(key); + } + + private JSONObject genericDatasetBeanToJSON(GenericDatasetBean gdb) throws JSONException { + + JSONObject sectJSONObject = JSONObjecOrdered.instance(); + + Map> mapFields = gdb.getFormDataEntryFields(); + System.out.println("Map is: "+mapFields); + for (String key : mapFields.keySet()) { + List listValues = mapFields.get(key); + if (listValues == null || listValues.isEmpty()) { + continue; + } + + // key/value as string + if (listValues.size() == 1) { + sectJSONObject.put(key, listValues.get(0)); + continue; + } + + // value is a list + JSONArray array = new JSONArray(); + for (String value : listValues) { + array.put(value); + } + + sectJSONObject.put(key, array); + } + + System.out.println("sectJSONObject: "+sectJSONObject); + return sectJSONObject; + + } + + /** + * Merge "source" into "target". If fields have equal name, merge them + * recursively. + * + * @return the merged object (target). + */ + public static JSONObject deepMerge(JSONObject source, JSONObject target) throws JSONException { + for (String key : JSONObject.getNames(source)) { + System.out.println("key: "+key); + Object value = source.get(key); + if (!target.has(key)) { + // new value for "key": + target.put(key, value); + } else { + // existing value for "key" - recursively deep merge: + if (value instanceof JSONObject) { + JSONObject valueJson = (JSONObject) value; + deepMerge(valueJson, target.getJSONObject(key)); + } else { + target.put(key, value); + } + } + } + return target; + } + +}