package jnpf.elnService.impl;
|
|
import feign.Request;
|
import feign.Response;
|
import jnpf.base.ActionResult;
|
import jnpf.elnEntity.field.ElnFieldVersionEntity;
|
import jnpf.elnEntity.runtime.ElnRecordEntity;
|
import jnpf.elnEntity.runtime.ElnRecordFieldValueEntity;
|
import jnpf.elnEntity.runtime.ElnRecordForms;
|
import jnpf.elnEntity.runtime.ElnRecordRevisionEntity;
|
import jnpf.elnEntity.runtime.ElnRecordVos;
|
import jnpf.elnEntity.template.ElnTemplateBindingEntity;
|
import jnpf.elnMapper.ElnFieldVersionMapper;
|
import jnpf.elnMapper.ElnRecordFieldValueMapper;
|
import jnpf.elnMapper.ElnRecordMapper;
|
import jnpf.elnMapper.ElnRecordRevisionMapper;
|
import jnpf.elnMapper.ElnTemplateBindingMapper;
|
import jnpf.elnService.ElnTestWorkItemSnapshotProvider;
|
import jnpf.elnService.ElnRecordFormulaCalculationService;
|
import jnpf.elnService.template.docx.DocxContentControlReader;
|
import jnpf.elnService.template.docx.DocxContentControlWriter;
|
import jnpf.elnService.template.docx.DocxControlSnapshot;
|
import jnpf.exception.DataException;
|
import jnpf.file.FileApi;
|
import jnpf.file.FileUploadApi;
|
import jnpf.lims.api.model.TestWorkItemSnapshotBatch;
|
import jnpf.lims.api.model.TestWorkItemSnapshot;
|
import jnpf.model.upload.UploadFileModel;
|
import jnpf.onlyoffice.RecordRevisionFenceApi;
|
import org.junit.Test;
|
import org.springframework.transaction.support.TransactionSynchronization;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.web.multipart.MultipartFile;
|
|
import java.io.ByteArrayInputStream;
|
import java.io.IOException;
|
import java.lang.reflect.InvocationHandler;
|
import java.lang.reflect.Proxy;
|
import java.nio.charset.Charset;
|
import java.nio.charset.StandardCharsets;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.Collection;
|
import java.util.Collections;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipOutputStream;
|
import java.io.ByteArrayOutputStream;
|
|
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertArrayEquals;
|
|
public class ElnRecordSharedFillDocumentIntegrationTest {
|
|
@Test
|
public void executeWritesPrimaryAndReferencesAndRotatesOnlyOfficeDocumentKey() throws Exception {
|
Fixture fixture = new Fixture(false);
|
|
ElnRecordVos.SharedFilled result = fixture.service.execute(fixture.command());
|
|
assertEquals(result.getTargets().get(0).getErrorMessage(),
|
"COMMITTED", result.getTargets().get(0).getStatus());
|
assertEquals(Arrays.asList("acquire", "release-updated"), fixture.fenceEvents);
|
List<DocxControlSnapshot> controls = new DocxContentControlReader().read(
|
new ByteArrayInputStream(fixture.files.get("record-1.docx")));
|
assertEquals(3, controls.size());
|
for (DocxControlSnapshot control : controls) {
|
assertEquals("20.50", control.getCurrentValue());
|
assertNotNull(control.getAlias());
|
assertEquals("sdtLocked", control.getLock());
|
}
|
assertTrue(controls.get(0).getTag().startsWith("eln.field."));
|
}
|
|
@Test
|
public void executeRestoresOriginalDocxWhenTheTargetTransactionRollsBack() throws Exception {
|
Fixture fixture = new Fixture(true);
|
byte[] original = fixture.files.get("record-1.docx").clone();
|
|
ElnRecordVos.SharedFilled result = fixture.service.execute(fixture.command());
|
|
assertEquals("REJECTED", result.getTargets().get(0).getStatus());
|
assertEquals(Arrays.asList("acquire", "release"), fixture.fenceEvents);
|
assertArrayEquals(original, fixture.files.get("record-1.docx"));
|
}
|
|
@Test
|
public void executeRejectsTheTargetWhenAnActiveReferenceTagIsMissing() throws Exception {
|
Fixture fixture = new Fixture(false);
|
fixture.files.put("record-1.docx", docxWithoutFooter("old"));
|
byte[] original = fixture.files.get("record-1.docx").clone();
|
|
ElnRecordVos.SharedFilled result = fixture.service.execute(fixture.command());
|
|
assertEquals("REJECTED", result.getTargets().get(0).getStatus());
|
assertEquals("DOCX 缺少目标字段控件: eln.ref.environment_temperature.footer",
|
result.getTargets().get(0).getErrorMessage());
|
assertEquals(Arrays.asList("acquire", "release"), fixture.fenceEvents);
|
assertArrayEquals(original, fixture.files.get("record-1.docx"));
|
}
|
|
@Test
|
public void executeRejectsADocxWithAPathTraversalZipEntry() throws Exception {
|
Fixture fixture = new Fixture(false);
|
fixture.files.put("record-1.docx", docxWithUnsafeEntry("old"));
|
byte[] original = fixture.files.get("record-1.docx").clone();
|
|
ElnRecordVos.SharedFilled result = fixture.service.execute(fixture.command());
|
|
assertEquals("REJECTED", result.getTargets().get(0).getStatus());
|
assertEquals("DOCX ZIP 条目不允许路径跳转",
|
result.getTargets().get(0).getErrorMessage());
|
assertEquals(Arrays.asList("acquire", "release"), fixture.fenceEvents);
|
assertArrayEquals(original, fixture.files.get("record-1.docx"));
|
}
|
|
@Test
|
public void executeRejectsADocxXmlPartContainingADoctype() throws Exception {
|
Fixture fixture = new Fixture(false);
|
fixture.files.put("record-1.docx", docxWithDoctype("old"));
|
byte[] original = fixture.files.get("record-1.docx").clone();
|
|
ElnRecordVos.SharedFilled result = fixture.service.execute(fixture.command());
|
|
assertEquals("REJECTED", result.getTargets().get(0).getStatus());
|
assertTrue(result.getTargets().get(0).getErrorMessage()
|
.startsWith("DOCX 内容控件写入失败"));
|
assertEquals(Arrays.asList("acquire", "release"), fixture.fenceEvents);
|
assertArrayEquals(original, fixture.files.get("record-1.docx"));
|
}
|
|
@Test
|
public void executeClearsAnEmptyFormulaResultAndItsReferences() throws Exception {
|
Fixture fixture = new Fixture(false, true);
|
|
ElnRecordVos.SharedFilled result = fixture.service.execute(fixture.command());
|
|
assertEquals(result.getTargets().get(0).getErrorMessage(),
|
"COMMITTED", result.getTargets().get(0).getStatus());
|
List<DocxControlSnapshot> controls = new DocxContentControlReader().read(
|
new ByteArrayInputStream(fixture.files.get("record-1.docx")));
|
Map<String, String> values = new LinkedHashMap<>();
|
for (DocxControlSnapshot control : controls) {
|
values.put(control.getTag(), control.getCurrentValue());
|
}
|
assertEquals(null, values.get("eln.field.formula_result"));
|
assertEquals(null, values.get("eln.ref.formula_result"));
|
}
|
|
private static ElnRecordVos.SharedFillTargetResult completeTransaction(
|
java.util.function.Supplier<ElnRecordVos.SharedFillTargetResult> action,
|
boolean rollback) {
|
TransactionSynchronizationManager.initSynchronization();
|
try {
|
ElnRecordVos.SharedFillTargetResult result = action.get();
|
for (TransactionSynchronization synchronization
|
: TransactionSynchronizationManager.getSynchronizations()) {
|
synchronization.afterCompletion(rollback
|
? TransactionSynchronization.STATUS_ROLLED_BACK
|
: TransactionSynchronization.STATUS_COMMITTED);
|
}
|
if (rollback) throw new DataException("模拟目标事务提交失败");
|
return result;
|
} finally {
|
TransactionSynchronizationManager.clearSynchronization();
|
}
|
}
|
|
private static final class Fixture {
|
private final Map<String, byte[]> files = new LinkedHashMap<>();
|
private final List<String> fenceEvents = new ArrayList<>();
|
private final ElnRecordSharedFillServiceImpl service;
|
|
private Fixture(boolean rollback) throws IOException {
|
this(rollback, false);
|
}
|
|
private Fixture(boolean rollback, boolean emptyFormula) throws IOException {
|
Map<String, ElnRecordEntity> records = new LinkedHashMap<>();
|
records.put("item-1", record("record-1", "item-1", "revision-1", 3));
|
records.put("item-2", record("record-2", "item-2", "revision-2", 5));
|
Map<String, ElnRecordRevisionEntity> revisions = new LinkedHashMap<>();
|
revisions.put("record-1", revision(
|
"revision-1", "record-1", "record-1.docx"));
|
revisions.put("record-2", revision(
|
"revision-2", "record-2", "record-2.docx"));
|
Map<String, List<ElnRecordFieldValueEntity>> values = new LinkedHashMap<>();
|
values.put("record-1", Collections.singletonList(value(
|
"value-1", "record-1", "revision-1")));
|
values.put("record-2", Collections.singletonList(value(
|
"value-2", "record-2", "revision-2")));
|
final String[] currentItem = new String[1];
|
ElnRecordMapper recordMapper = proxy(
|
ElnRecordMapper.class, (ignored, method, args) -> {
|
if ("selectLiveByTestWorkItem".equals(method.getName())) {
|
currentItem[0] = (String) args[1];
|
return records.get(currentItem[0]);
|
}
|
if ("advanceVersion".equals(method.getName())) return 1;
|
return null;
|
});
|
ElnRecordRevisionMapper revisionMapper = proxy(
|
ElnRecordRevisionMapper.class, (ignored, method, args) ->
|
"selectOne".equals(method.getName())
|
? revisions.get(records.get(currentItem[0]).getId()) : null);
|
ElnRecordFieldValueMapper valueMapper = proxy(
|
ElnRecordFieldValueMapper.class, (ignored, method, args) -> {
|
if ("selectList".equals(method.getName())) {
|
return values.get(records.get(currentItem[0]).getId());
|
}
|
if ("updateById".equals(method.getName())) return 1;
|
return null;
|
});
|
ElnFieldVersionMapper versionMapper = proxy(
|
ElnFieldVersionMapper.class, (ignored, method, args) ->
|
"selectOne".equals(method.getName()) ? sharedVersion() : null);
|
ElnTemplateBindingMapper bindingMapper = proxy(
|
ElnTemplateBindingMapper.class, (ignored, method, args) ->
|
"selectList".equals(method.getName())
|
? bindings(emptyFormula) : null);
|
files.put("record-1.docx", docx("old", emptyFormula));
|
files.put("record-2.docx", docx("old", emptyFormula));
|
FileApi fileApi = proxy(FileApi.class, (ignored, method, args) ->
|
"getPath".equals(method.getName()) ? "WebAnnexFile/" : null);
|
FileUploadApi uploadApi = proxy(
|
FileUploadApi.class, (ignored, method, args) -> {
|
if ("downFile".equals(method.getName())) {
|
UploadFileModel model = (UploadFileModel) args[0];
|
return response(files.get(model.getObjectName()));
|
}
|
if ("replaceFile".equals(method.getName())) {
|
MultipartFile multipart = (MultipartFile) args[0];
|
files.put((String) args[2], multipart.getBytes());
|
return true;
|
}
|
return null;
|
});
|
RecordRevisionFenceApi fenceApi = proxy(
|
RecordRevisionFenceApi.class, (ignored, method, args) -> {
|
if ("acquire".equals(method.getName())) {
|
fenceEvents.add("acquire");
|
return ActionResult.success("fence acquired", "fence-token");
|
}
|
if ("releaseAfterDocumentUpdate".equals(method.getName())) {
|
fenceEvents.add("release-updated");
|
return ActionResult.success("fence released", true);
|
}
|
if ("release".equals(method.getName())) {
|
fenceEvents.add("release");
|
return ActionResult.success("fence released", true);
|
}
|
return null;
|
});
|
ElnRecordSharedFillDocumentService documentService =
|
new ElnRecordSharedFillDocumentService(bindingMapper, fileApi, uploadApi,
|
fenceApi, new DocxContentControlWriter());
|
service = new ElnRecordSharedFillServiceImpl(
|
recordMapper, revisionMapper, valueMapper, versionMapper,
|
snapshots(), calculation(emptyFormula), ignored -> { },
|
(action, failureAudit) -> completeTransaction(action, rollback),
|
documentService::synchronize,
|
() -> new ElnRecordSharedFillServiceImpl.UserContext(
|
"tenant-a", "user-1"));
|
}
|
|
private ElnRecordForms.SharedFillExecute command() {
|
ElnRecordForms.SharedFillPreview previewCommand =
|
new ElnRecordForms.SharedFillPreview();
|
previewCommand.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
ElnRecordVos.SharedFillPreview preview = service.preview(previewCommand);
|
ElnRecordForms.SharedFillExecute command =
|
new ElnRecordForms.SharedFillExecute();
|
command.setTestWorkItemIds(Arrays.asList("item-1", "item-2"));
|
command.setPreviewToken(preview.getPreviewToken());
|
command.setOperationCode("shared-fill-1");
|
command.setFieldVersionId("version-shared");
|
command.setValue("20.50");
|
ElnRecordForms.SharedFillTarget target =
|
new ElnRecordForms.SharedFillTarget();
|
target.setTestWorkItemId("item-1");
|
target.setRecordId("record-1");
|
target.setExpectedRecordVersion(3);
|
command.setTargets(Collections.singletonList(target));
|
return command;
|
}
|
}
|
|
private static ElnRecordFormulaCalculationService calculation(boolean emptyFormula) {
|
return new ElnRecordFormulaCalculationService() {
|
@Override
|
public List<ElnRecordFieldValueEntity> recalculateAffected(
|
String tenantId, ElnRecordEntity record, ElnRecordRevisionEntity revision,
|
List<ElnRecordFieldValueEntity> currentValues, Set<String> changedBindingIds,
|
String operationCode, String operatorUserId) {
|
return emptyFormula
|
? Collections.singletonList(emptyFormulaValue(record, revision))
|
: Collections.emptyList();
|
}
|
|
@Override
|
public List<ElnRecordFieldValueEntity> recalculateAll(
|
String tenantId, ElnRecordEntity record, ElnRecordRevisionEntity revision,
|
List<ElnRecordFieldValueEntity> currentValues, String operationCode,
|
String operatorUserId) {
|
return Collections.emptyList();
|
}
|
};
|
}
|
|
private static List<ElnTemplateBindingEntity> bindings(boolean includeFormula) {
|
ElnTemplateBindingEntity primary = binding(
|
"binding-shared", "eln.field.environment_temperature", "PRIMARY", null);
|
ElnTemplateBindingEntity header = binding(
|
"reference-header", "eln.ref.environment_temperature.header",
|
"REFERENCE", primary.getId());
|
ElnTemplateBindingEntity footer = binding(
|
"reference-footer", "eln.ref.environment_temperature.footer",
|
"REFERENCE", primary.getId());
|
List<ElnTemplateBindingEntity> result = new ArrayList<>(
|
Arrays.asList(primary, header, footer));
|
if (includeFormula) {
|
ElnTemplateBindingEntity formula = binding(
|
"binding-formula", "eln.field.formula_result", "PRIMARY", null);
|
formula.setZiduanDingyiId("definition-formula");
|
formula.setZiduanBianma("formula_result");
|
formula.setZiduanBanbenId("version-formula");
|
ElnTemplateBindingEntity formulaReference = binding(
|
"reference-formula", "eln.ref.formula_result",
|
"REFERENCE", formula.getId());
|
formulaReference.setZiduanDingyiId("definition-formula");
|
formulaReference.setZiduanBianma("formula_result");
|
formulaReference.setZiduanBanbenId("version-formula");
|
result.add(formula);
|
result.add(formulaReference);
|
}
|
return result;
|
}
|
|
private static ElnRecordFieldValueEntity emptyFormulaValue(
|
ElnRecordEntity record, ElnRecordRevisionEntity revision) {
|
ElnRecordFieldValueEntity value = new ElnRecordFieldValueEntity();
|
value.setId("value-formula");
|
value.setDianziJiluId(record.getId());
|
value.setXiudingId(revision.getId());
|
value.setMubanId("template-1");
|
value.setMubanBangdingId("binding-formula");
|
value.setZiduanDingyiId("definition-formula");
|
value.setZiduanBianma("formula_result");
|
value.setZiduanBanbenId("version-formula");
|
value.setBangdingJuese("PRIMARY");
|
value.setBangdingZhuangtai("ACTIVE");
|
value.setJisuanZhuangtai("MISSING_INPUT");
|
value.setFTenantId("tenant-a");
|
value.setFDeleteMark(0);
|
return value;
|
}
|
|
private static ElnTemplateBindingEntity binding(
|
String id, String tag, String role, String primaryId) {
|
ElnTemplateBindingEntity value = new ElnTemplateBindingEntity();
|
value.setId(id);
|
value.setMubanId("template-1");
|
value.setZiduanDingyiId("definition-shared");
|
value.setZiduanBianma("environment_temperature");
|
value.setZiduanBanbenId("version-shared");
|
value.setKongjianBiaoqian(tag);
|
value.setKongjianLeixing("TEXT");
|
value.setKongjianJuese(role);
|
value.setYinyongShiliId(primaryId);
|
value.setBangdingZhuangtai("ACTIVE");
|
value.setFTenantId("tenant-a");
|
value.setFDeleteMark(0);
|
return value;
|
}
|
|
private static ElnRecordEntity record(
|
String id, String itemId, String revisionId, int version) {
|
ElnRecordEntity value = new ElnRecordEntity();
|
value.setId(id);
|
value.setJianyanXiangId(itemId);
|
value.setMubanId("template-1");
|
value.setMubanBianhao("TPL-1");
|
value.setDangqianXiudingId(revisionId);
|
value.setFVersion(version);
|
value.setFTenantId("tenant-a");
|
value.setFDeleteMark(0);
|
return value;
|
}
|
|
private static ElnRecordRevisionEntity revision(
|
String id, String recordId, String fileId) {
|
ElnRecordRevisionEntity value = new ElnRecordRevisionEntity();
|
value.setId(id);
|
value.setDianziJiluId(recordId);
|
value.setJiluWendang(fileId);
|
value.setBizStatus("DRAFT");
|
value.setFTenantId("tenant-a");
|
value.setFDeleteMark(0);
|
return value;
|
}
|
|
private static ElnRecordFieldValueEntity value(
|
String id, String recordId, String revisionId) {
|
ElnRecordFieldValueEntity value = new ElnRecordFieldValueEntity();
|
value.setId(id);
|
value.setDianziJiluId(recordId);
|
value.setXiudingId(revisionId);
|
value.setMubanId("template-1");
|
value.setMubanBangdingId("binding-shared");
|
value.setZiduanDingyiId("definition-shared");
|
value.setZiduanBianma("environment_temperature");
|
value.setZiduanBanbenId("version-shared");
|
value.setBangdingJuese("PRIMARY");
|
value.setBangdingZhuangtai("ACTIVE");
|
value.setZhiLaiyuan("MANUAL");
|
value.setFTenantId("tenant-a");
|
value.setFDeleteMark(0);
|
return value;
|
}
|
|
private static ElnFieldVersionEntity sharedVersion() {
|
ElnFieldVersionEntity value = new ElnFieldVersionEntity();
|
value.setId("version-shared");
|
value.setZiduanDingyiId("definition-shared");
|
value.setZiduanMingcheng("环境温度");
|
value.setShujuLeixing("DECIMAL");
|
value.setPiciMoshi("BATCH_SHARED");
|
value.setBangdingPeizhi(
|
"{\"read\":{\"source\":\"NONE\"},\"write\":{\"target\":\"ELN_RECORD\"}}");
|
value.setFTenantId("tenant-a");
|
value.setFDeleteMark(0);
|
return value;
|
}
|
|
private static ElnTestWorkItemSnapshotProvider snapshots() {
|
return new ElnTestWorkItemSnapshotProvider() {
|
@Override
|
public TestWorkItemSnapshotBatch resolve(
|
List<String> testWorkItemIds, List<String> properties) {
|
throw new AssertionError("must use actor snapshot");
|
}
|
|
@Override
|
public TestWorkItemSnapshotBatch resolveAsActor(
|
String tenantId, String userId, List<String> testWorkItemIds,
|
List<String> properties) {
|
TestWorkItemSnapshotBatch batch = new TestWorkItemSnapshotBatch();
|
List<TestWorkItemSnapshot> items = new ArrayList<>();
|
for (String itemId : testWorkItemIds) {
|
TestWorkItemSnapshot item = new TestWorkItemSnapshot();
|
item.setTestWorkItemId(itemId);
|
item.setTestDefinitionId("project-1");
|
item.setTestDefinitionCode("HD_jyxm_0008");
|
item.setTestDefinitionName("pH值");
|
item.setOutcomeCode("SUCCESS");
|
item.setTaskStatus("pending_test");
|
items.add(item);
|
}
|
batch.setItems(items);
|
return batch;
|
}
|
};
|
}
|
|
private static byte[] docx(String text) throws IOException {
|
return docx(text, true, false);
|
}
|
|
private static byte[] docxWithoutFooter(String text) throws IOException {
|
return docx(text, false, false);
|
}
|
|
private static byte[] docx(String text, boolean includeFormula) throws IOException {
|
return docx(text, true, includeFormula);
|
}
|
|
private static byte[] docx(
|
String text, boolean includeFooter, boolean includeFormula) throws IOException {
|
Map<String, String> parts = standardParts(text, includeFormula);
|
if (!includeFooter) parts.remove("word/footer1.xml");
|
return zip(parts);
|
}
|
|
private static byte[] docxWithUnsafeEntry(String text) throws IOException {
|
Map<String, String> parts = standardParts(text, false);
|
parts.put("../outside.xml", "unsafe");
|
return zip(parts);
|
}
|
|
private static byte[] docxWithDoctype(String text) throws IOException {
|
Map<String, String> parts = standardParts(text, false);
|
parts.put("word/document.xml",
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
+ "<!DOCTYPE w:document [<!ENTITY xxe SYSTEM \"file:///etc/passwd\">]>"
|
+ documentPart("eln.field.environment_temperature",
|
"Primary", "&xxe;", "document")
|
.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", ""));
|
return zip(parts);
|
}
|
|
private static Map<String, String> standardParts(
|
String text, boolean includeFormula) {
|
Map<String, String> parts = new LinkedHashMap<>();
|
parts.put("[Content_Types].xml",
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><Types "
|
+ "xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\"/>");
|
parts.put("word/document.xml", documentPart(
|
"eln.field.environment_temperature", "Primary", text, "document"));
|
parts.put("word/header1.xml", documentPart(
|
"eln.ref.environment_temperature.header", "Header", text, "hdr"));
|
parts.put("word/footer1.xml", documentPart(
|
"eln.ref.environment_temperature.footer", "Footer", text, "ftr"));
|
if (includeFormula) {
|
parts.put("word/footnotes.xml", documentPart(
|
"eln.field.formula_result", "Formula", "stale", "footnotes"));
|
parts.put("word/endnotes.xml", documentPart(
|
"eln.ref.formula_result", "Formula reference", "stale", "endnotes"));
|
}
|
return parts;
|
}
|
|
private static byte[] zip(Map<String, String> parts) throws IOException {
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
try (ZipOutputStream zip = new ZipOutputStream(output)) {
|
for (Map.Entry<String, String> part : parts.entrySet()) {
|
zip.putNextEntry(new ZipEntry(part.getKey()));
|
zip.write(part.getValue().getBytes(StandardCharsets.UTF_8));
|
zip.closeEntry();
|
}
|
}
|
return output.toByteArray();
|
}
|
|
private static String documentPart(
|
String tag, String alias, String text, String root) {
|
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
+ "<w:" + root + " xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">"
|
+ "<w:sdt><w:sdtPr><w:alias w:val=\"" + alias + "\"/>"
|
+ "<w:tag w:val=\"" + tag + "\"/><w:lock w:val=\"sdtLocked\"/>"
|
+ "<w:text/></w:sdtPr><w:sdtContent><w:p><w:r><w:t>" + text
|
+ "</w:t></w:r></w:p></w:sdtContent></w:sdt></w:" + root + ">";
|
}
|
|
private static Response response(byte[] bytes) {
|
return Response.builder().status(bytes == null ? 404 : 200)
|
.reason(bytes == null ? "Not Found" : "OK")
|
.request(Request.create(Request.HttpMethod.GET, "http://file/download",
|
Collections.<String, Collection<String>>emptyMap(), null,
|
Charset.defaultCharset()))
|
.body(bytes).build();
|
}
|
|
@SuppressWarnings("unchecked")
|
private static <T> T proxy(Class<T> type, InvocationHandler handler) {
|
return (T) Proxy.newProxyInstance(
|
type.getClassLoader(), new Class<?>[]{type}, handler);
|
}
|
}
|