/** * Copyright 2012 Universitat Pompeu Fabra. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * */ package org.onexus.website.api.widgets.download; import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.event.IEvent; import org.apache.wicket.markup.head.CssHeaderItem; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.JavaScriptHeaderItem; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.request.resource.AbstractResource; import org.apache.wicket.request.resource.ContentDisposition; import org.apache.wicket.request.resource.CssResourceReference; import org.apache.wicket.request.resource.IResource; import org.apache.wicket.request.resource.JavaScriptResourceReference; import org.apache.wicket.request.resource.ResourceReference; import org.onexus.collection.api.ICollectionManager; import org.onexus.collection.api.IEntityTable; import org.onexus.collection.api.query.Query; import org.onexus.website.api.WebsiteApplication; import org.onexus.website.api.events.EventQueryUpdate; import org.onexus.website.api.pages.browser.BrowserPageStatus; import org.onexus.website.api.widgets.Widget; import org.onexus.website.api.widgets.download.formats.ExcelFormat; import org.onexus.website.api.widgets.download.formats.IDownloadFormat; import org.onexus.website.api.widgets.download.formats.TsvFormat; import org.onexus.website.api.widgets.download.scripts.BashScript; import org.onexus.website.api.widgets.download.scripts.IQueryScript; import org.onexus.website.api.widgets.download.scripts.PerlScript; import org.onexus.website.api.widgets.download.scripts.Python2Script; import org.onexus.website.api.widgets.download.scripts.Python3Script; import org.onexus.website.api.widgets.download.scripts.RScript; import javax.inject.Inject; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; public class DownloadWidget extends Widget<DownloadWidgetConfig, DownloadWidgetStatus> { public static final ResourceReference CSS = new CssResourceReference(DownloadWidget.class, "prettify/prettify.css"); public static final ResourceReference JS = new JavaScriptResourceReference(DownloadWidget.class, "prettify/prettify.js"); private static final Pattern COMMA_PATTERN = Pattern.compile(","); @Inject private ICollectionManager collectionManager; public static final Map<String, IQueryScript> SCRIPTS_MAP = new LinkedHashMap<String, IQueryScript>(); static { addScript(new RScript()); addScript(new Python2Script()); addScript(new Python3Script()); addScript(new PerlScript()); addScript(new BashScript()); } private static void addScript(IQueryScript queryScript) { SCRIPTS_MAP.put(queryScript.getLabel().toLowerCase(), queryScript); } private static final Map<String, IDownloadFormat> FORMATS_MAP = new LinkedHashMap<String, IDownloadFormat>(); static { addFormat(new TsvFormat()); addFormat(new ExcelFormat()); } private static void addFormat(IDownloadFormat format) { FORMATS_MAP.put(format.getLabel().toLowerCase(), format); } private String webserviceUrl; private IDownloadFormat format; public DownloadWidget(String componentId, IModel<DownloadWidgetStatus> statusModel) { super(componentId, statusModel); onEventFireUpdate(EventQueryUpdate.class); // Get query final StringBuilder oql = new StringBuilder(); Query query = getQuery(); query.toString(oql, true); // Webservice URL String serviceMount = collectionManager.getMount(); webserviceUrl = WebsiteApplication.toAbsolutePath('/' + serviceMount); // Download form final Form<String> downloadForm = new Form<String>("form"); downloadForm.setOutputMarkupId(true); List<IDownloadFormat> formats = getFormats(); if (formats.isEmpty()) { throw new UnsupportedOperationException("Download widget: At least one format is needed."); } setFormat(formats.get(0)); downloadForm.add(new DropDownChoice<IDownloadFormat>("format", new PropertyModel<IDownloadFormat>(this, "format"), formats)); add(downloadForm); final AjaxDownloadBehavior ajaxDownloadBehavior = new AjaxDownloadBehavior() { @Override protected String getFileName() { return DownloadWidget.this.getFileName(); } @Override protected IResource getResource() { return new DownloadResource(); } }; downloadForm.add(ajaxDownloadBehavior); AjaxButton link = new AjaxButton("download") { @Override protected void onSubmit(AjaxRequestTarget target, Form<?> form) { ajaxDownloadBehavior.initiate(target); target.add(form); } }; downloadForm.add(link); List<IQueryScript> scripts = getScripts(); // Add scripts ListView scriptsView = new ListView<IQueryScript>("scripts", scripts) { @Override protected void populateItem(ListItem<IQueryScript> item) { IQueryScript script = item.getModelObject(); // Code body WebMarkupContainer body = new WebMarkupContainer("body"); body.setMarkupId(item.getMarkupId() + "-body"); item.add(body); body.add(new Label("code", script.getContent(oql.toString(), webserviceUrl)).setEscapeModelStrings(false)); // Code toggle Label toggle = new Label("toggle", "Use in " + script.getLabel() + " script"); toggle.add(new AttributeModifier("href", "#" + body.getMarkupId())); item.add(toggle); } }; if (scripts.isEmpty()) { scriptsView.setVisible(false); } add(scriptsView); } private String getFileName() { BrowserPageStatus status = DownloadWidget.this.findParentStatus(BrowserPageStatus.class); if (status == null) { return getFormat().getFileName("datafile"); } return getFormat().getFileName(status.getCurrentTabId()); } private List<IDownloadFormat> getFormats() { List<IDownloadFormat> formats = new ArrayList<IDownloadFormat>(); String formatsStr = getConfig().getFormats(); if (formatsStr == null) { formats.addAll(FORMATS_MAP.values()); } else { String[] values = COMMA_PATTERN.split(formatsStr); for (String value : values) { IDownloadFormat format = FORMATS_MAP.get(value.trim().toLowerCase()); if (format != null) { formats.add(format); } } } return formats; } private List<IQueryScript> getScripts() { List<IQueryScript> scripts = new ArrayList<IQueryScript>(); String scriptsStr = getConfig().getScripts(); if (scriptsStr == null) { scripts.addAll(SCRIPTS_MAP.values()); } else { String[] values = COMMA_PATTERN.split(scriptsStr); for (String value : values) { IQueryScript script = SCRIPTS_MAP.get(value.trim().toLowerCase()); if (script != null) { scripts.add(script); } } } return scripts; } @Override public void onEvent(IEvent<?> event) { if (event.getPayload() instanceof AjaxRequestTarget) { AjaxRequestTarget target = (AjaxRequestTarget) event.getPayload(); target.appendJavaScript("prettyPrint();"); } } @Override public void renderHead(IHeaderResponse response) { response.render(CssHeaderItem.forReference(CSS)); response.render(JavaScriptHeaderItem.forReference(JS)); } public IDownloadFormat getFormat() { return format; } public void setFormat(IDownloadFormat format) { this.format = format; } private ICollectionManager getCollectionManager() { if (collectionManager == null) { WebsiteApplication.inject(this); } return collectionManager; } private class DownloadResource extends AbstractResource { @Override protected ResourceResponse newResourceResponse(Attributes attributes) { ResourceResponse resourceResponse = new ResourceResponse(); resourceResponse.setContentDisposition(ContentDisposition.ATTACHMENT); resourceResponse.setContentType(getFormat().getContentType()); resourceResponse.setFileName(getFileName()); resourceResponse.setWriteCallback(new WriteCallback() { @Override public void writeData(Attributes attributes) throws IOException { Query query = getQuery(); IDownloadFormat format = getFormat(); if (format.getMaxRowsLimit() != null && (query.getCount() == null || format.getMaxRowsLimit() < query.getCount())) { query.setCount(format.getMaxRowsLimit()); } IEntityTable table = getCollectionManager().load(query); OutputStream out = attributes.getResponse().getOutputStream(); getFormat().write(table, out); } }); return resourceResponse; } } }