package com.aperto.magnolia.vanity.app; /* * #%L * magnolia-vanity-url Magnolia Module * %% * Copyright (C) 2013 - 2014 Aperto AG * %% * 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 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 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-3.0.html>. * #L% */ import com.aperto.magnolia.vanity.VanityUrlService; import info.magnolia.cms.beans.runtime.FileProperties; import info.magnolia.cms.core.Path; import info.magnolia.i18nsystem.SimpleTranslator; import info.magnolia.jcr.util.NodeTypes.Resource; import info.magnolia.ui.api.action.ActionExecutionException; import info.magnolia.ui.form.EditorCallback; import info.magnolia.ui.form.EditorValidator; import info.magnolia.ui.form.action.SaveFormAction; import info.magnolia.ui.form.action.SaveFormActionDefinition; import info.magnolia.ui.form.field.upload.UploadReceiver; import info.magnolia.ui.vaadin.integration.jcr.DefaultProperty; import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter; import net.glxn.qrgen.QRCode; import org.apache.jackrabbit.value.ValueFactoryImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.jcr.Binary; import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.RepositoryException; import java.io.*; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.TimeZone; import static com.aperto.magnolia.vanity.VanityUrlService.NN_IMAGE; import static com.aperto.magnolia.vanity.VanityUrlService.PN_VANITY_URL; import static info.magnolia.jcr.util.PropertyUtil.*; import static org.apache.commons.io.IOUtils.closeQuietly; import static org.apache.commons.lang.StringUtils.*; import static org.apache.jackrabbit.JcrConstants.JCR_DATA; /** * Saves additional to the form fields a qr code image as preview image. * * @author frank.sommer * @since 28.05.14 */ public class VanityUrlSaveFormAction extends SaveFormAction { private static final Logger LOGGER = LoggerFactory.getLogger(VanityUrlSaveFormAction.class); private static final int QR_WIDTH = 500; private static final int GR_HEIGHT = 500; private static final String MIME_TYPE = "image/png"; public static final String IMAGE_EXTENSION = ".png"; private SimpleTranslator _simpleTranslator; private VanityUrlService _vanityUrlService; private String _fileName; public VanityUrlSaveFormAction(final SaveFormActionDefinition definition, final JcrNodeAdapter item, final EditorCallback callback, final EditorValidator validator) { super(definition, item, callback, validator); } @Override public void execute() throws ActionExecutionException { if (validator.isValid()) { checkVanityUrl(); savePreviewImage(); } super.execute(); } private void checkVanityUrl() { try { final Node node = item.applyChanges(); String vanityUrl = getString(node, PN_VANITY_URL); vanityUrl = stripStart(trimToEmpty(vanityUrl), "/"); if (isEmpty(vanityUrl)) { vanityUrl = "/untitled"; } else { vanityUrl = "/" + vanityUrl; } item.addItemProperty(PN_VANITY_URL, new DefaultProperty<>(vanityUrl)); node.getSession().save(); } catch (RepositoryException e) { LOGGER.error("Error checking vanity url property.", e); } } private void savePreviewImage() { FileOutputStream outputStream = null; FileInputStream qrCodeInputStream = null; try { final Node node = item.applyChanges(); String url = _vanityUrlService.createVanityUrl(node); _fileName = trim(strip(getString(node, PN_VANITY_URL, ""), "/")).replace("/", "-"); File tmpQrCodeFile = Path.getTempDirectory(); UploadReceiver uploadReceiver = new UploadReceiver(tmpQrCodeFile, _simpleTranslator); outputStream = (FileOutputStream) uploadReceiver.receiveUpload(_fileName + IMAGE_EXTENSION, MIME_TYPE); QRCode.from(url).withSize(QR_WIDTH, GR_HEIGHT).writeTo(outputStream); Node qrNode; if (node.hasNode(NN_IMAGE)) { qrNode = node.getNode(NN_IMAGE); } else { qrNode = node.addNode(NN_IMAGE, Resource.NAME); } qrCodeInputStream = new FileInputStream(uploadReceiver.getFile()); populateItem(qrCodeInputStream, qrNode); outputStream.flush(); } catch (RepositoryException e) { LOGGER.error("Error on saving preview image for vanity url.", e); } catch (IOException e) { LOGGER.error("Error handling qr image file.", e); } finally { closeQuietly(outputStream); closeQuietly(qrCodeInputStream); } } protected void populateItem(InputStream inputStream, Node qrCodeNode) throws RepositoryException { if (inputStream != null) { try { Property data = getPropertyOrNull(qrCodeNode, JCR_DATA); Binary binary = ValueFactoryImpl.getInstance().createBinary(inputStream); if (data == null) { qrCodeNode.setProperty(JCR_DATA, binary); } else { data.setValue(binary); } setProperty(qrCodeNode, FileProperties.PROPERTY_FILENAME, _fileName); setProperty(qrCodeNode, FileProperties.PROPERTY_CONTENTTYPE, MIME_TYPE); Calendar calValue = new GregorianCalendar(TimeZone.getDefault()); setProperty(qrCodeNode, FileProperties.PROPERTY_LASTMODIFIED, calValue); } catch (RepositoryException re) { LOGGER.error("Could not get Binary. Upload will not be performed", re); } } } @Inject public void setVanityUrlService(final VanityUrlService vanityUrlService) { _vanityUrlService = vanityUrlService; } @Inject public void setSimpleTranslator(final SimpleTranslator simpleTranslator) { _simpleTranslator = simpleTranslator; } }