This is an automated email from the ASF dual-hosted git repository. xxyu pushed a commit to branch kylin5 in repository https://gitbox.apache.org/repos/asf/kylin.git
commit df6ef0a5aee7c6257835cf64f99a06f4b2f6c34c Author: sibingzhang <74443791+sibingzh...@users.noreply.github.com> AuthorDate: Sat Feb 25 00:07:05 2023 +0800 KYLIN-5534 Fix the inconsistent behavior of exporting tds between normal users and admin Co-authored-by: sibing.zhang <sibing.zh...@qq.com> --- .../rest/controller/open/OpenModelController.java | 5 +- .../kylin/rest/controller/NModelController.java | 2 +- .../rest/controller/NModelControllerTest.java | 7 ++- .../apache/kylin/rest/service/ModelTdsService.java | 12 ++-- .../org/apache/kylin/tool/bisync/BISyncTool.java | 4 +- .../apache/kylin/tool/bisync/SyncModelBuilder.java | 5 -- .../service/ModelTdsServiceColumnNameTest.java | 3 +- .../kylin/rest/service/ModelTdsServiceTest.java | 68 +++++++++++++++++++--- .../kylin/tool/bisync/SyncModelBuilderTest.java | 2 +- .../tool/bisync/tableau/TableauDatasourceTest.java | 5 +- 10 files changed, 83 insertions(+), 30 deletions(-) diff --git a/src/metadata-server/src/main/java/io/kyligence/kap/rest/controller/open/OpenModelController.java b/src/metadata-server/src/main/java/io/kyligence/kap/rest/controller/open/OpenModelController.java index 3b10bfc29a..b28319abeb 100644 --- a/src/metadata-server/src/main/java/io/kyligence/kap/rest/controller/open/OpenModelController.java +++ b/src/metadata-server/src/main/java/io/kyligence/kap/rest/controller/open/OpenModelController.java @@ -73,7 +73,6 @@ import org.apache.kylin.rest.service.FusionIndexService; import org.apache.kylin.rest.service.FusionModelService; import org.apache.kylin.rest.service.ModelService; import org.apache.kylin.rest.service.ModelTdsService; -import org.apache.kylin.rest.util.AclPermissionUtil; import org.apache.kylin.tool.bisync.SyncContext; import org.apache.kylin.tool.bisync.model.SyncModel; import org.apache.kylin.util.DataRangeUtils; @@ -414,9 +413,7 @@ public class OpenModelController extends NBasicController { } SyncContext syncContext = tdsService.prepareSyncContext(projectName, modelId, exportAs, element, host, port); - SyncModel syncModel = AclPermissionUtil.isAdmin() - ? tdsService.exportTDSDimensionsAndMeasuresByAdmin(syncContext, dimensions, measures) - : tdsService.exportTDSDimensionsAndMeasuresByNormalUser(syncContext, dimensions, measures); + SyncModel syncModel = tdsService.exportModel(syncContext); tdsService.preCheckNameConflict(syncModel); tdsService.dumpSyncModel(syncContext, syncModel, response); } diff --git a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/NModelController.java b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/NModelController.java index e5029e98f9..f05dd6b9f9 100644 --- a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/NModelController.java +++ b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/NModelController.java @@ -34,8 +34,8 @@ import java.util.Locale; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.kylin.common.exception.KylinException; import org.apache.kylin.metadata.model.NDataModel; import org.apache.kylin.metadata.model.PartitionDesc; diff --git a/src/metadata-server/src/test/java/org/apache/kylin/rest/controller/NModelControllerTest.java b/src/metadata-server/src/test/java/org/apache/kylin/rest/controller/NModelControllerTest.java index ef405752e1..ffe814c4d7 100644 --- a/src/metadata-server/src/test/java/org/apache/kylin/rest/controller/NModelControllerTest.java +++ b/src/metadata-server/src/test/java/org/apache/kylin/rest/controller/NModelControllerTest.java @@ -84,6 +84,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -783,7 +784,8 @@ public class NModelControllerTest extends NLocalFileMetadataTestCase { SyncModel syncModel = Mockito.mock(SyncModel.class); Mockito.doReturn(syncContext).when(tdsService).prepareSyncContext(project, modelName, SyncContext.BI.TABLEAU_CONNECTOR_TDS, SyncContext.ModelElement.CUSTOM_COLS, "localhost", 8080); - Mockito.doReturn(syncModel).when(tdsService).exportModel(syncContext); + Mockito.doReturn(syncModel).when(tdsService).exportTDSDimensionsAndMeasuresByAdmin(syncContext, + ImmutableList.of(), ImmutableList.of()); Mockito.doReturn(Boolean.TRUE).when(tdsService).preCheckNameConflict(syncModel); mockMvc.perform(MockMvcRequestBuilders.get("/api/models/validate_export").param("model", modelName) .param("project", project).contentType(MediaType.APPLICATION_JSON)) @@ -805,7 +807,8 @@ public class NModelControllerTest extends NLocalFileMetadataTestCase { syncContext.setKylinConfig(getTestConfig()); syncContext.setAdmin(true); SyncModel syncModel = Mockito.mock(SyncModel.class); - Mockito.doReturn(syncModel).when(tdsService).exportModel(syncContext); + Mockito.doReturn(syncModel).when(tdsService).exportTDSDimensionsAndMeasuresByAdmin(syncContext, + ImmutableList.of(), ImmutableList.of()); mockMvc.perform(MockMvcRequestBuilders.get("/api/models/{model}/export", modelName).param("project", project) .param("export_as", "TABLEAU_CONNECTOR_TDS").param("element", "AGG_INDEX_AND_TABLE_INDEX_COL") .param("server_host", "localhost").param("server_port", "8080").contentType(MediaType.APPLICATION_JSON) diff --git a/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelTdsService.java b/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelTdsService.java index b28fe7a019..84e611fb96 100644 --- a/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelTdsService.java +++ b/src/modeling-service/src/main/java/org/apache/kylin/rest/service/ModelTdsService.java @@ -69,6 +69,7 @@ import org.apache.kylin.tool.bisync.model.MeasureDef; import org.apache.kylin.tool.bisync.model.SyncModel; import org.springframework.stereotype.Component; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; @@ -111,7 +112,6 @@ public class ModelTdsService extends AbstractModelService { Set<String> measureNames = syncModel.getMetrics().stream().filter(measureDef -> !measureDef.isHidden()) .map(measureDef -> measureDef.getMeasure().getName()).collect(Collectors.toSet()); Map<String, ColumnDef> nameOfColDefMap = syncModel.getColumnDefMap().values().stream() - .filter(columnDef -> !columnDef.isHidden()) .collect(Collectors.toMap(ColumnDef::getAliasDotColumn, Function.identity())); nameOfColDefMap.forEach((aliasColName, columnDef) -> { @@ -129,9 +129,9 @@ public class ModelTdsService extends AbstractModelService { } public SyncModel exportModel(SyncContext syncContext) { - checkModelExportPermission(syncContext.getProjectName(), syncContext.getModelId()); - checkModelPermission(syncContext.getProjectName(), syncContext.getModelId()); - return new SyncModelBuilder(syncContext).buildSourceSyncModel(); + return AclPermissionUtil.isAdmin() + ? exportTDSDimensionsAndMeasuresByAdmin(syncContext, ImmutableList.of(), ImmutableList.of()) + : exportTDSDimensionsAndMeasuresByNormalUser(syncContext, ImmutableList.of(), ImmutableList.of()); } public SyncModel exportTDSDimensionsAndMeasuresByNormalUser(SyncContext syncContext, List<String> dimensions, @@ -162,8 +162,8 @@ public class ModelTdsService extends AbstractModelService { checkTableHasColumnPermission(syncContext.getModelElement(), project, modelId, authorizedCols, dimensions, measures); - return new SyncModelBuilder(syncContext).buildHasPermissionSourceSyncModel(authTables, authColumns, dimensions, - measures); + return new SyncModelBuilder(syncContext).buildHasPermissionSourceSyncModel(authTables, authorizedCols, + dimensions, measures); } public SyncModel exportTDSDimensionsAndMeasuresByAdmin(SyncContext syncContext, List<String> dimensions, diff --git a/src/modeling-service/src/main/java/org/apache/kylin/tool/bisync/BISyncTool.java b/src/modeling-service/src/main/java/org/apache/kylin/tool/bisync/BISyncTool.java index 4834af6595..039ff1dff7 100644 --- a/src/modeling-service/src/main/java/org/apache/kylin/tool/bisync/BISyncTool.java +++ b/src/modeling-service/src/main/java/org/apache/kylin/tool/bisync/BISyncTool.java @@ -25,6 +25,7 @@ import org.apache.kylin.tool.bisync.model.SyncModel; import org.apache.kylin.tool.bisync.tableau.TableauDataSourceConverter; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; public class BISyncTool { @@ -33,7 +34,8 @@ public class BISyncTool { @VisibleForTesting public static BISyncModel dumpToBISyncModel(SyncContext syncContext) { - SyncModel syncModel = new SyncModelBuilder(syncContext).buildSourceSyncModel(); + SyncModel syncModel = new SyncModelBuilder(syncContext).buildSourceSyncModel(ImmutableList.of(), + ImmutableList.of()); return getBISyncModel(syncContext, syncModel); } diff --git a/src/modeling-service/src/main/java/org/apache/kylin/tool/bisync/SyncModelBuilder.java b/src/modeling-service/src/main/java/org/apache/kylin/tool/bisync/SyncModelBuilder.java index fa14d623cd..de00e0ffaf 100644 --- a/src/modeling-service/src/main/java/org/apache/kylin/tool/bisync/SyncModelBuilder.java +++ b/src/modeling-service/src/main/java/org/apache/kylin/tool/bisync/SyncModelBuilder.java @@ -44,7 +44,6 @@ import org.apache.kylin.tool.bisync.model.JoinTreeNode; import org.apache.kylin.tool.bisync.model.MeasureDef; import org.apache.kylin.tool.bisync.model.SyncModel; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -57,10 +56,6 @@ public class SyncModelBuilder { this.syncContext = syncContext; } - public SyncModel buildSourceSyncModel() { - return buildSourceSyncModel(ImmutableList.of(), ImmutableList.of()); - } - public SyncModel buildSourceSyncModel(List<String> dimensions, List<String> measures) { NDataModel dataModelDesc = syncContext.getDataflow().getModel(); IndexPlan indexPlan = syncContext.getDataflow().getIndexPlan(); diff --git a/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelTdsServiceColumnNameTest.java b/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelTdsServiceColumnNameTest.java index db24394952..1047372feb 100644 --- a/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelTdsServiceColumnNameTest.java +++ b/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelTdsServiceColumnNameTest.java @@ -19,6 +19,7 @@ package org.apache.kylin.rest.service; import lombok.extern.slf4j.Slf4j; +import com.google.common.collect.ImmutableList; import org.apache.kylin.common.scheduler.EventBusFactory; import org.apache.kylin.engine.spark.utils.SparkJobFactoryUtils; import org.apache.kylin.junit.rule.TransactionExceptedException; @@ -122,7 +123,7 @@ public class ModelTdsServiceColumnNameTest extends SourceTestCase { syncContext.setAdmin(true); syncContext.setDataflow(NDataflowManager.getInstance(getTestConfig(), getProject()).getDataflow(modelId)); syncContext.setKylinConfig(getTestConfig()); - SyncModel syncModel = tdsService.exportModel(syncContext); + SyncModel syncModel = tdsService.exportTDSDimensionsAndMeasuresByAdmin(syncContext, ImmutableList.of(), ImmutableList.of()); Assert.assertTrue(tdsService.preCheckNameConflict(syncModel)); } } diff --git a/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelTdsServiceTest.java b/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelTdsServiceTest.java index b60753ea7b..885408a725 100644 --- a/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelTdsServiceTest.java +++ b/src/modeling-service/src/test/java/org/apache/kylin/rest/service/ModelTdsServiceTest.java @@ -43,6 +43,7 @@ import org.apache.kylin.metadata.cube.model.NDataflowManager; import org.apache.kylin.metadata.model.ComputedColumnDesc; import org.apache.kylin.metadata.model.NDataModel; import org.apache.kylin.metadata.model.NDataModelManager; +import org.apache.kylin.metadata.model.TableRef; import org.apache.kylin.metadata.model.TblColRef; import org.apache.kylin.metadata.recommendation.candidate.JdbcRawRecStore; import org.apache.kylin.rest.constant.Constant; @@ -160,10 +161,21 @@ public class ModelTdsServiceTest extends SourceTestCase { syncContext.setAdmin(true); syncContext.setDataflow(NDataflowManager.getInstance(getTestConfig(), projectName).getDataflow(modelId)); syncContext.setKylinConfig(getTestConfig()); - SyncModel syncModel = tdsService.exportModel(syncContext); + SyncModel syncModel = tdsService.exportTDSDimensionsAndMeasuresByAdmin(syncContext, ImmutableList.of(), + ImmutableList.of()); Assert.assertThrows( "There are duplicated names among dimension column LO_LINENUMBER and measure name LO_LINENUMBER. Cannot export a valid TDS file. Please correct the duplicated names and try again.", KylinException.class, () -> tdsService.preCheckNameConflict(syncModel)); + + syncContext.setAdmin(false); + prepareBasicPermissionByModel(projectName, syncContext.getDataflow().getModel()); + SecurityContextHolder.getContext() + .setAuthentication(new TestingAuthenticationToken("u1", "ANALYST", Constant.ROLE_ANALYST)); + SyncModel syncModel2 = tdsService.exportTDSDimensionsAndMeasuresByNormalUser(syncContext, ImmutableList.of(), + ImmutableList.of()); + Assert.assertThrows( + "There are duplicated names among dimension column LO_LINENUMBER and measure name LO_LINENUMBER. Cannot export a valid TDS file. Please correct the duplicated names and try again.", + KylinException.class, () -> tdsService.preCheckNameConflict(syncModel2)); } @Test @@ -187,7 +199,16 @@ public class ModelTdsServiceTest extends SourceTestCase { syncContext.setAdmin(true); syncContext.setDataflow(NDataflowManager.getInstance(getTestConfig(), projectName).getDataflow(modelId)); syncContext.setKylinConfig(getTestConfig()); - SyncModel syncModel = tdsService.exportModel(syncContext); + SyncModel syncModel = tdsService.exportTDSDimensionsAndMeasuresByAdmin(syncContext, ImmutableList.of(), + ImmutableList.of()); + Assert.assertTrue(tdsService.preCheckNameConflict(syncModel)); + + syncContext.setAdmin(false); + prepareBasicPermissionByModel(projectName, syncContext.getDataflow().getModel()); + SecurityContextHolder.getContext() + .setAuthentication(new TestingAuthenticationToken("u1", "ANALYST", Constant.ROLE_ANALYST)); + syncModel = tdsService.exportTDSDimensionsAndMeasuresByNormalUser(syncContext, ImmutableList.of(), + ImmutableList.of()); Assert.assertTrue(tdsService.preCheckNameConflict(syncModel)); } @@ -212,8 +233,21 @@ public class ModelTdsServiceTest extends SourceTestCase { syncContext.setDataflow(NDataflowManager.getInstance(getTestConfig(), projectName).getDataflow(modelId)); syncContext.setKylinConfig(getTestConfig()); syncContext.setAdmin(true); - SyncModel syncModel = tdsService.exportModel(syncContext); - Assert.assertTrue(tdsService.preCheckNameConflict(syncModel)); + SyncModel syncModel = tdsService.exportTDSDimensionsAndMeasuresByAdmin(syncContext, ImmutableList.of(), + ImmutableList.of()); + Assert.assertThrows( + "There are duplicated names among model column LO_LINENUMBER and measure name LO_LINENUMBER. Cannot export a valid TDS file. Please correct the duplicated names and try again.", + KylinException.class, () -> tdsService.preCheckNameConflict(syncModel)); + + syncContext.setAdmin(false); + prepareBasicPermissionByModel(projectName, syncContext.getDataflow().getModel()); + SecurityContextHolder.getContext() + .setAuthentication(new TestingAuthenticationToken("u1", "ANALYST", Constant.ROLE_ANALYST)); + SyncModel syncModel2 = tdsService.exportTDSDimensionsAndMeasuresByNormalUser(syncContext, ImmutableList.of(), + ImmutableList.of()); + Assert.assertThrows( + "There are duplicated names among model column LO_LINENUMBER and measure name LO_LINENUMBER. Cannot export a valid TDS file. Please correct the duplicated names and try again.", + KylinException.class, () -> tdsService.preCheckNameConflict(syncModel2)); } @Test @@ -310,7 +344,7 @@ public class ModelTdsServiceTest extends SourceTestCase { thrown.expectMessage("current user does not have full permission on requesting model"); SyncContext syncContext = tdsService.prepareSyncContext(project, modelId, SyncContext.BI.TABLEAU_CONNECTOR_TDS, SyncContext.ModelElement.AGG_INDEX_COL, "localhost", 8080); - tdsService.exportModel(syncContext); + tdsService.exportTDSDimensionsAndMeasuresByAdmin(syncContext, ImmutableList.of(), ImmutableList.of()); } finally { SecurityContextHolder.getContext() .setAuthentication(new TestingAuthenticationToken("ADMIN", "ADMIN", Constant.ROLE_ADMIN)); @@ -359,7 +393,7 @@ public class ModelTdsServiceTest extends SourceTestCase { SyncContext syncContext = tdsService.prepareSyncContext(project, modelId, SyncContext.BI.TABLEAU_CONNECTOR_TDS, SyncContext.ModelElement.AGG_INDEX_COL, "localhost", 8080); - tdsService.exportModel(syncContext); + tdsService.exportTDSDimensionsAndMeasuresByAdmin(syncContext, ImmutableList.of(), ImmutableList.of()); } finally { SecurityContextHolder.getContext() .setAuthentication(new TestingAuthenticationToken("ADMIN", "ADMIN", Constant.ROLE_ADMIN)); @@ -449,7 +483,8 @@ public class ModelTdsServiceTest extends SourceTestCase { prepareBasic(project); SyncContext syncContext = tdsService.prepareSyncContext(project, modelId, SyncContext.BI.TABLEAU_CONNECTOR_TDS, SyncContext.ModelElement.AGG_INDEX_AND_TABLE_INDEX_COL, "localhost", 7070); - SyncModel syncModel = tdsService.exportModel(syncContext); + SyncModel syncModel = tdsService.exportTDSDimensionsAndMeasuresByAdmin(syncContext, ImmutableList.of(), + ImmutableList.of()); TableauDatasourceModel datasource1 = (TableauDatasourceModel) BISyncTool.getBISyncModel(syncContext, syncModel); ByteArrayOutputStream outStream4 = new ByteArrayOutputStream(); datasource1.dump(outStream4); @@ -492,6 +527,25 @@ public class ModelTdsServiceTest extends SourceTestCase { manager.updateAclTCR(g1a1, "g1", false); } + private void prepareBasicPermissionByModel(String project, NDataModel model) { + AclTCRManager manager = AclTCRManager.getInstance(getTestConfig(), project); + AclTCR u1a1 = new AclTCR(); + AclTCR.Table u1t1 = new AclTCR.Table(); + for (TableRef table : model.getAllTables()) { + AclTCR.ColumnRow u1cr1 = new AclTCR.ColumnRow(); + AclTCR.Column u1c1 = new AclTCR.Column(); + List<String> colNames = Lists.newArrayList(); + for (TblColRef col : table.getColumns()) { + colNames.add(col.getName()); + } + u1c1.addAll(colNames); + u1cr1.setColumn(u1c1); + u1t1.put(table.getTableIdentity(), u1cr1); + } + u1a1.setTable(u1t1); + manager.updateAclTCR(u1a1, "u1", true); + } + @Test public void testCheckTablePermission() { val project = "default"; diff --git a/src/modeling-service/src/test/java/org/apache/kylin/tool/bisync/SyncModelBuilderTest.java b/src/modeling-service/src/test/java/org/apache/kylin/tool/bisync/SyncModelBuilderTest.java index d45eb7b97c..6844db70ae 100644 --- a/src/modeling-service/src/test/java/org/apache/kylin/tool/bisync/SyncModelBuilderTest.java +++ b/src/modeling-service/src/test/java/org/apache/kylin/tool/bisync/SyncModelBuilderTest.java @@ -76,7 +76,7 @@ public class SyncModelBuilderTest extends NLocalFileMetadataTestCase { val syncContext = SyncModelTestUtil.createSyncContext(project, modelId, KylinConfig.getInstanceFromEnv()); syncContext.setModelElement(SyncContext.ModelElement.ALL_COLS); syncContext.setAdmin(true); - val syncModel = new SyncModelBuilder(syncContext).buildSourceSyncModel(); + val syncModel = new SyncModelBuilder(syncContext).buildSourceSyncModel(ImmutableList.of(), ImmutableList.of()); val df = NDataflowManager.getInstance(KylinConfig.getInstanceFromEnv(), project).getDataflow(modelId); val model = df.getModel(); diff --git a/src/modeling-service/src/test/java/org/apache/kylin/tool/bisync/tableau/TableauDatasourceTest.java b/src/modeling-service/src/test/java/org/apache/kylin/tool/bisync/tableau/TableauDatasourceTest.java index 43839bcd6d..53bb8b8cd7 100644 --- a/src/modeling-service/src/test/java/org/apache/kylin/tool/bisync/tableau/TableauDatasourceTest.java +++ b/src/modeling-service/src/test/java/org/apache/kylin/tool/bisync/tableau/TableauDatasourceTest.java @@ -36,6 +36,7 @@ import org.junit.Before; import org.junit.Test; import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableList; import com.google.common.io.CharStreams; import lombok.val; @@ -72,7 +73,7 @@ public class TableauDatasourceTest extends NLocalFileMetadataTestCase { val project = "default"; val modelId = "cb596712-3a09-46f8-aea1-988b43fe9b6c"; val syncContext = SyncModelTestUtil.createSyncContext(project, modelId, KylinConfig.getInstanceFromEnv()); - val syncModel = new SyncModelBuilder(syncContext).buildSourceSyncModel(); + val syncModel = new SyncModelBuilder(syncContext).buildSourceSyncModel(ImmutableList.of(), ImmutableList.of()); TableauDatasourceModel datasource = new TableauDataSourceConverter().convert(syncModel, syncContext); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); @@ -86,7 +87,7 @@ public class TableauDatasourceTest extends NLocalFileMetadataTestCase { val project = "default"; val modelId = "cb596712-3a09-46f8-aea1-988b43fe9b6c"; val syncContext = SyncModelTestUtil.createSyncContext(project, modelId, KylinConfig.getInstanceFromEnv()); - val syncModel = new SyncModelBuilder(syncContext).buildSourceSyncModel(); + val syncModel = new SyncModelBuilder(syncContext).buildSourceSyncModel(ImmutableList.of(), ImmutableList.of()); TableauDatasourceModel datasource = new TableauDataSourceConverter().convert(syncModel, syncContext); ByteArrayOutputStream outStream = new ByteArrayOutputStream();