/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xwiki.office.viewer.script; import java.util.Collections; import java.util.Map; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import org.artofsolving.jodconverter.document.DocumentFormat; import org.slf4j.Logger; import org.xwiki.bridge.DocumentAccessBridge; import org.xwiki.component.annotation.Component; import org.xwiki.component.manager.ComponentManager; import org.xwiki.context.Execution; import org.xwiki.model.reference.AttachmentReference; import org.xwiki.model.reference.DocumentReference; import org.xwiki.office.viewer.OfficeViewer; import org.xwiki.office.viewer.OfficeViewerScriptService; import org.xwiki.officeimporter.converter.OfficeConverter; import org.xwiki.officeimporter.server.OfficeServer; import org.xwiki.rendering.block.XDOM; import org.xwiki.rendering.renderer.BlockRenderer; import org.xwiki.rendering.renderer.printer.DefaultWikiPrinter; import org.xwiki.rendering.renderer.printer.WikiPrinter; import org.xwiki.rendering.syntax.Syntax; import org.xwiki.rendering.transformation.TransformationContext; import org.xwiki.rendering.transformation.TransformationManager; /** * Default implementation of {@link OfficeViewerScriptService}. * * @since 2.5M2 * @version $Id: 0a81aa23de705f4f4a680efa5600362f5c506f9b $ */ @Component @Named("officeviewer") @Singleton public class DefaultOfficeViewerScriptService implements OfficeViewerScriptService { /** * The key used to save on the execution context the exception caught during office document view. */ private static final String OFFICE_VIEW_EXCEPTION = "officeView.caughtException"; /** * The component used to view office documents. */ @Inject private OfficeViewer officeViewer; /** * The component used to retrieve the office document converter, which knows the supported media types. * * @see #isMimeTypeSupported(String) */ @Inject private OfficeServer officeServer; /** * Used to lookup various {@link BlockRenderer} implementations based on the output syntax. */ @Inject private ComponentManager componentManager; /** * Reference to the current execution context, used to save the exception caught during office document view. */ @Inject private Execution execution; /** * The component used to check access rights on the document holding the office attachment to be viewed. */ @Inject private DocumentAccessBridge documentAccessBridge; /** * The component used to perform the XDOM transformations. */ @Inject private TransformationManager transformationManager; /** * The logger to log. */ @Inject private Logger logger; @Override public Exception getCaughtException() { return (Exception) this.execution.getContext().getProperty(OFFICE_VIEW_EXCEPTION); } @Override public String view(AttachmentReference attachmentReference) { Map<String, String> parameters = Collections.emptyMap(); return view(attachmentReference, parameters); } @Override public String view(AttachmentReference attachmentReference, Map<String, String> parameters) { // Clear previous caught exception. this.execution.getContext().removeProperty(OFFICE_VIEW_EXCEPTION); try { DocumentReference documentReference = attachmentReference.getDocumentReference(); // Check whether current user has view rights on the document containing the attachment. if (!this.documentAccessBridge.isDocumentViewable(documentReference)) { throw new RuntimeException("Inadequate privileges."); } // Create the view and render the result. Syntax fromSyntax = this.documentAccessBridge.getDocument(documentReference).getSyntax(); Syntax toSyntax = Syntax.XHTML_1_0; return render(this.officeViewer.createView(attachmentReference, parameters), fromSyntax, toSyntax); } catch (Exception e) { // Save caught exception. this.execution.getContext().setProperty(OFFICE_VIEW_EXCEPTION, e); this.logger.error("Failed to view office document: " + attachmentReference, e); return null; } } @Override public boolean isMimeTypeSupported(String mimeType) { return isConversionSupported(mimeType, "text/html"); } /** * Use this method to check if the unidirectional conversion from a document format (input media type) to another * document format (output media type) is supported by this converter. * * @param inputMediaType the media type of the input document * @param outputMediaType the media type of the output document * @return {@code true} if a document can be converted from the input media type to the output media type, * {@code false} otherwise */ private boolean isConversionSupported(String inputMediaType, String outputMediaType) { OfficeConverter converter = this.officeServer.getConverter(); if (converter != null) { DocumentFormat inputFormat = converter.getFormatRegistry().getFormatByMediaType(inputMediaType); DocumentFormat outputFormat = converter.getFormatRegistry().getFormatByMediaType(outputMediaType); return inputFormat != null && outputFormat != null && outputFormat.getStoreProperties(inputFormat.getInputFamily()) != null; } else { return false; } } /** * Renders the given XDOM into specified syntax. * * @param xdom the {@link XDOM} to be rendered * @param fromSyntax the syntax for which to perform the transformations * @param toSyntax expected output syntax * @return string holding the result of rendering * @throws Exception if an error occurs during rendering */ private String render(XDOM xdom, Syntax fromSyntax, Syntax toSyntax) throws Exception { // Perform the transformations. This is required for office presentations which use the gallery macro to display // the slide images. TransformationContext context = new TransformationContext(xdom, fromSyntax); context.setTargetSyntax(toSyntax); this.transformationManager.performTransformations(xdom, context); WikiPrinter printer = new DefaultWikiPrinter(); BlockRenderer renderer = this.componentManager.getInstance(BlockRenderer.class, toSyntax.toIdString()); renderer.render(xdom, printer); return printer.toString(); } }