Java tutorial
package de.metas.ui.web.letter; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.function.UnaryOperator; import org.adempiere.ad.trx.api.ITrx; import org.adempiere.ad.trx.api.ITrxManager; import org.adempiere.exceptions.AdempiereException; import org.adempiere.user.UserId; import org.adempiere.util.lang.impl.TableRecordReference; import org.apache.commons.io.FileUtils; import org.compiere.util.Env; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.google.common.collect.ImmutableSet; import de.metas.bpartner.BPartnerId; import de.metas.bpartner.BPartnerLocationId; import de.metas.document.IDocumentLocationBL; import de.metas.document.model.impl.PlainDocumentLocation; import de.metas.i18n.IMsgBL; import de.metas.letter.BoilerPlateId; import de.metas.letters.api.ITextTemplateBL; import de.metas.letters.model.Letter; import de.metas.letters.model.Letters; import de.metas.letters.model.MADBoilerPlate; import de.metas.letters.model.MADBoilerPlate.BoilerPlateContext; import de.metas.ui.web.config.WebConfig; import de.metas.ui.web.letter.WebuiLetter.WebuiLetterBuilder; import de.metas.ui.web.letter.json.JSONLetter; import de.metas.ui.web.letter.json.JSONLetterRequest; import de.metas.ui.web.session.UserSession; import de.metas.ui.web.window.datatypes.DocumentPath; import de.metas.ui.web.window.datatypes.LookupValue; import de.metas.ui.web.window.datatypes.json.JSONDocumentChangedEvent; import de.metas.ui.web.window.datatypes.json.JSONDocumentPath; import de.metas.ui.web.window.datatypes.json.JSONLookupValue; import de.metas.ui.web.window.datatypes.json.JSONLookupValuesList; import de.metas.ui.web.window.model.DocumentCollection; import de.metas.util.Services; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiOperation; /* * #%L * metasfresh-webui-api * %% * Copyright (C) 2017 metas GmbH * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-2.0.html>. * #L% */ @RestController @RequestMapping(LetterRestController.ENDPOINT) @ApiModel("Letter endpoint") public class LetterRestController { public static final String ENDPOINT = WebConfig.ENDPOINT_ROOT + "/letter"; @Autowired private UserSession userSession; @Autowired private WebuiLetterRepository lettersRepo; @Autowired private DocumentCollection documentCollection; private static final String PATCH_FIELD_Message = "message"; private static final String PATCH_FIELD_TemplateId = "templateId"; private static final Set<String> PATCH_FIELD_ALL = ImmutableSet.of(PATCH_FIELD_Message, PATCH_FIELD_TemplateId); private final void assertReadable(final WebuiLetter letter) { // Make sure current logged in user is the owner final int loggedUserId = userSession.getAD_User_ID(); if (letter.getOwnerUserId() != loggedUserId) { throw new AdempiereException("No credentials to read the letter") .setParameter("letterId", letter.getLetterId()) .setParameter("ownerUserId", letter.getOwnerUserId()) .setParameter("loggedUserId", loggedUserId); } } private final void assertWritable(final WebuiLetter letter) { assertReadable(letter); // Make sure the letter was not already processed if (letter.isProcessed()) { throw new AdempiereException("Cannot change an letter which was already processed") .setParameter("letterId", letter.getLetterId()); } } @PostMapping @ApiOperation("Creates a new letter") public JSONLetter createNewLetter(@RequestBody final JSONLetterRequest request) { userSession.assertLoggedIn(); final DocumentPath contextDocumentPath = JSONDocumentPath.toDocumentPathOrNull(request.getDocumentPath()); // // Extract context BPartner, Location and Contact final BoilerPlateContext context = documentCollection.createBoilerPlateContext(contextDocumentPath); final int bpartnerId = context.getC_BPartner_ID(-1); final int bpartnerLocationId = context.getC_BPartner_Location_ID(-1); final int contactId = context.getAD_User_ID(-1); // // Build BPartnerAddress final PlainDocumentLocation documentLocation = new PlainDocumentLocation(Env.getCtx(), bpartnerId, bpartnerLocationId, contactId, ITrx.TRXNAME_None); Services.get(IDocumentLocationBL.class).setBPartnerAddress(documentLocation); final String bpartnerAddress = documentLocation.getBPartnerAddress(); final WebuiLetter letter = lettersRepo.createNewLetter(WebuiLetter.builder() .contextDocumentPath(contextDocumentPath).ownerUserId(userSession.getAD_User_ID()) .adOrgId(context.getAD_Org_ID(userSession.getAD_Org_ID())).bpartnerId(bpartnerId) .bpartnerLocationId(bpartnerLocationId).bpartnerAddress(bpartnerAddress) .bpartnerContactId(contactId)); return JSONLetter.of(letter); } @GetMapping("/{letterId}") @ApiOperation("Gets letter by ID") public JSONLetter getLetter(@PathVariable("letterId") final String letterId) { userSession.assertLoggedIn(); final WebuiLetter letter = lettersRepo.getLetter(letterId); assertReadable(letter); return JSONLetter.of(letter); } private ResponseEntity<byte[]> createPDFResponseEntry(final byte[] pdfData) { final String pdfFilename = Services.get(IMsgBL.class).getMsg(Env.getCtx(), Letters.MSG_Letter); final HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_PDF); headers.set(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + pdfFilename + "\""); headers.setCacheControl("must-revalidate, post-check=0, pre-check=0"); final ResponseEntity<byte[]> response = new ResponseEntity<>(pdfData, headers, HttpStatus.OK); return response; } @GetMapping("/{letterId}/printPreview") @ApiOperation("Returns letter's printable version (e.g. PDF)") public ResponseEntity<byte[]> getLetterPrintPreview(@PathVariable("letterId") final String letterId) { userSession.assertLoggedIn(); // // Get the letter final WebuiLetter letter = lettersRepo.getLetter(letterId); assertReadable(letter); // // Create and return the printable letter final byte[] pdfData = createPDFData(letter); return createPDFResponseEntry(pdfData); } @PostMapping("/{letterId}/complete") @ApiOperation("Completes the letter and returns it's printable version (e.g. PDF)") public ResponseEntity<byte[]> complete(@PathVariable("letterId") final String letterId) { userSession.assertLoggedIn(); final ITrxManager trxManager = Services.get(ITrxManager.class); final WebuiLetterChangeResult result = changeLetter(letterId, letter -> trxManager.call(() -> complete0(letter))); // // Remove the letter lettersRepo.removeLetterById(letterId); // // Return the printable letter return createPDFResponseEntry(result.getLetter().getTemporaryPDFData()); } private final WebuiLetter complete0(final WebuiLetter letter) { lettersRepo.createC_Letter(letter); // // Create the printable letter final byte[] pdfData = createPDFData(letter); final File pdfFile = createFile(pdfData); // // create the Boilerplate context final BoilerPlateContext context = documentCollection .createBoilerPlateContext(letter.getContextDocumentPath()); // // Create the request final TableRecordReference recordRef = documentCollection .getTableRecordReference(letter.getContextDocumentPath()); MADBoilerPlate.createRequest(pdfFile, recordRef.getAD_Table_ID(), recordRef.getRecord_ID(), context); return letter.toBuilder().processed(true).temporaryPDFData(pdfData).build(); } private byte[] createPDFData(final WebuiLetter letter) { final Letter request = Letter.builder().adLanguage(userSession.getAD_Language()) .boilerPlateId(BoilerPlateId.ofRepoIdOrNull(letter.getTextTemplateId())) .subject(letter.getSubject()).body(letter.getContent()).adOrgId(letter.getAdOrgId()) .bpartnerId(BPartnerId.ofRepoId(letter.getBpartnerId())) .bpartnerLocationId(BPartnerLocationId.ofRepoId(BPartnerId.ofRepoId(letter.getBpartnerId()), letter.getBpartnerLocationId())) .address(letter.getBpartnerAddress()).userId(UserId.ofRepoId(letter.getBpartnerContactId())) .build(); return Services.get(ITextTemplateBL.class).createPDF(request); } private static File createFile(final byte[] pdfData) { final String pdfFilenamePrefix = Services.get(IMsgBL.class).getMsg(Env.getCtx(), Letters.MSG_Letter); try { final File pdfFile = File.createTempFile(pdfFilenamePrefix, ".pdf"); FileUtils.writeByteArrayToFile(pdfFile, pdfData); return pdfFile; } catch (IOException e) { throw AdempiereException.wrapIfNeeded(e); } } @PatchMapping("/{letterId}") @ApiOperation("Changes the letter") public JSONLetter changeLetter(@PathVariable("letterId") final String letterId, @RequestBody final List<JSONDocumentChangedEvent> events) { userSession.assertLoggedIn(); final WebuiLetterChangeResult result = changeLetter(letterId, letterOld -> changeLetter(letterOld, events)); return JSONLetter.of(result.getLetter()); } private WebuiLetterChangeResult changeLetter(final String letterId, final UnaryOperator<WebuiLetter> letterModifier) { final WebuiLetterChangeResult result = lettersRepo.changeLetter(letterId, letterOld -> { assertWritable(letterOld); return letterModifier.apply(letterOld); }); return result; } private WebuiLetter changeLetter(final WebuiLetter letter, final List<JSONDocumentChangedEvent> events) { final WebuiLetterBuilder letterBuilder = letter.toBuilder(); events.forEach(event -> changeLetter(letter, letterBuilder, event)); return letterBuilder.build(); } private void changeLetter(final WebuiLetter letter, final WebuiLetter.WebuiLetterBuilder newLetterBuilder, final JSONDocumentChangedEvent event) { if (!event.isReplace()) { throw new AdempiereException("Unsupported event").setParameter("event", event); } final String fieldName = event.getPath(); if (PATCH_FIELD_Message.equals(fieldName)) { final String message = event.getValueAsString(null); newLetterBuilder.content(message); } else if (PATCH_FIELD_TemplateId.equals(fieldName)) { @SuppressWarnings("unchecked") final LookupValue templateId = JSONLookupValue .integerLookupValueFromJsonMap((Map<String, Object>) event.getValue()); applyTemplate(letter, newLetterBuilder, templateId); } else { throw new AdempiereException("Unsupported event path").setParameter("event", event) .setParameter("fieldName", fieldName).setParameter("availablePaths", PATCH_FIELD_ALL); } } @GetMapping("/templates") @ApiOperation("Available Email templates") public JSONLookupValuesList getTemplates() { return MADBoilerPlate.getAll(Env.getCtx()).stream().map( adBoilerPlate -> JSONLookupValue.of(adBoilerPlate.getAD_BoilerPlate_ID(), adBoilerPlate.getName())) .collect(JSONLookupValuesList.collect()); } private void applyTemplate(final WebuiLetter letter, final WebuiLetterBuilder newLetterBuilder, final LookupValue templateLookupValue) { final Properties ctx = Env.getCtx(); final int textTemplateId = templateLookupValue.getIdAsInt(); final MADBoilerPlate boilerPlate = MADBoilerPlate.get(ctx, textTemplateId); // // Attributes final BoilerPlateContext context = documentCollection .createBoilerPlateContext(letter.getContextDocumentPath()); // // Content and subject newLetterBuilder.textTemplateId(textTemplateId); newLetterBuilder.content(boilerPlate.getTextSnippetParsed(context)); newLetterBuilder.subject(boilerPlate.getSubject()); } }