package er.pdf; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Map; import com.webobjects.appserver.WOActionResults; import com.webobjects.appserver.WOApplication; import com.webobjects.appserver.WOAssociation; import com.webobjects.appserver.WOComponent; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WOElement; import com.webobjects.appserver.WOResponse; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSData; import com.webobjects.foundation.NSDictionary; import com.webobjects.foundation.NSMutableDictionary; import er.extensions.appserver.ERXRequest; import er.extensions.appserver.ERXResourceManager; import er.extensions.appserver.ERXResponse; import er.extensions.appserver.ERXWOContext; import er.extensions.components.ERXDynamicElement; /** * ERPDFWrapper will render the containing component content as a PDF document. * The contained content must be valid XHTML markup suitable for processing by * the chosen rendering engine. ERPDFWrapper is intended to be the outer most * element on the page and should not have any trailing content or whitespace after * the closing tag. * * @binding secure <code>true</code> if HTTPS should be used for unqualified URLs * in the HTML, defaults to the request type * @binding enabled <code>true</code> if a PDF should be created instead of HTML * during appendToResponse phase defaults to <code>true</code> * @binding filename the filename on the client, defaults to <i>result.pdf</i> * @binding fonts (optional) array of font filenames to include for PDF generation * @binding framework (optional) framework name where font files are * @binding additionalPDFs (optional) array of PDF filenames to append to the * generated PDF * * @author sharpy * @author q */ public class ERPDFWrapper extends ERXDynamicElement implements WOActionResults { protected WOElement _component; public ERPDFWrapper(String name, NSDictionary<String, WOAssociation> associations, WOElement template) { super(name, associations, template); _component = template; } @Override public void appendToResponse(WOResponse response, WOContext context) { WOComponent component = context.component(); ERXResponse.setXHTML(response, true); boolean enabled = booleanValueForBinding("enabled", true, component); super.appendToResponse(response, context); if (enabled) { NSData data = responseAsPdf(response, context); String filename = stringValueForBinding("filename", "result.pdf", component); response.setHeader("inline; filename=\"" + filename + "\"", "content-disposition"); response.setHeader("application/pdf", "Content-Type"); response.setHeader(String.valueOf(data.length()), "Content-Length"); response.setContent(data); } } protected NSData responseAsPdf(WOResponse response, WOContext context) { WOComponent component = context.component(); boolean secure = booleanValueForBinding("secure", ERXRequest.isRequestSecure(context.request()), component); String resourceUrlPrefix = ERXResourceManager._completeURLForResource("", secure, context); NSMutableDictionary<String, Object> config = new NSMutableDictionary<>(); for (Map.Entry<String, WOAssociation> entry : associations().entrySet()) { Object value = entry.getValue().valueInComponent(component); if (value != null) { config.setObjectForKey(value, entry.getKey()); } } NSData data = ERPDFUtilities.htmlAsPdf(response.contentString(), response.contentEncoding(), resourceUrlPrefix, config); return appendPDFs(data, context); } /** * Appends PDFs that have been denoted by the <i>additionalPDFs</i> binding * to the current PDF data object. * * @param data the current PDF data object * @param context context of the transaction * @return PDF data with appended PDFs or the unaltered data object if no * files were given to append */ protected NSData appendPDFs(NSData data, WOContext context) { WOComponent component = context.component(); NSArray<String> additionalPDFs = arrayValueForBinding("additionalPDFs", component); if (additionalPDFs != null) { try { List<InputStream> pdfs = new ArrayList<>(); pdfs.add(data.stream()); Enumeration<String> e = additionalPDFs.objectEnumerator(); while (e.hasMoreElements()) { pdfs.add(new FileInputStream(e.nextElement())); } ByteArrayOutputStream output = new ByteArrayOutputStream(); ERPDFMerge.concatPDFs(pdfs, output, false); data = new NSData(output.toByteArray()); } catch (Exception e) { log.error(e, e); } } return data; } public WOResponse generateResponse() { WOResponse response; WOContext context = ERXWOContext.currentContext(); if (_component instanceof WOActionResults) { response = ((WOActionResults)_component).generateResponse(); responseAsPdf(response, context); } else { response = WOApplication.application().createResponseInContext(context); WOElement currentElement = context._pageElement(); context._setPageElement(_component); appendToResponse(response, context); context._setPageElement(currentElement); } return response; } }