Java tutorial
/* * Copyright 2012 Corpuslinguistic working group Humboldt University Berlin. * * 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 annis.gui.frequency; import annis.gui.components.FrequencyChart; import annis.libgui.Helper; import annis.libgui.PollControl; import annis.service.objects.FrequencyTable; import annis.service.objects.FrequencyTableEntry; import annis.service.objects.FrequencyTableEntryType; import au.com.bytecode.opencsv.CSVWriter; import com.google.common.base.Charsets; import com.google.common.base.Joiner; import com.google.common.collect.Ordering; import com.sun.jersey.api.client.ClientHandlerException; import com.sun.jersey.api.client.UniformInterfaceException; import com.sun.jersey.api.client.WebResource; import com.vaadin.data.Container; import com.vaadin.data.util.AbstractBeanContainer; import com.vaadin.data.util.DefaultItemSorter; import com.vaadin.data.util.IndexedContainer; import com.vaadin.data.util.ItemSorter; import com.vaadin.server.FileDownloader; import com.vaadin.server.FontAwesome; import com.vaadin.server.StreamResource; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Notification; import com.vaadin.ui.ProgressBar; import com.vaadin.ui.Table; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.ValoTheme; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Serializable; import java.io.Writer; import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.ListIterator; import java.util.Locale; import java.util.Set; import java.util.concurrent.Callable; import org.apache.commons.lang3.StringUtils; import org.slf4j.LoggerFactory; /** * * @author Thomas Krause <krauseto@hu-berlin.de> */ public class FrequencyResultPanel extends VerticalLayout { private static final org.slf4j.Logger log = LoggerFactory.getLogger(FrequencyResultPanel.class); public static final int MAX_NUMBER_OF_CHART_ITEMS = 100; private Table tblResult; private final Button btDownloadCSV; private final FrequencyChart chart; private final String aql; private final Set<String> corpora; private final List<FrequencyTableEntry> freqDefinition; private final FrequencyQueryPanel queryPanel; private ProgressBar pbQuery; public FrequencyResultPanel(String aql, Set<String> corpora, final List<FrequencyTableEntry> freqDefinition, FrequencyQueryPanel queryPanel) { this.aql = aql; this.corpora = corpora; this.freqDefinition = freqDefinition; this.queryPanel = queryPanel; setSizeFull(); pbQuery = new ProgressBar(); pbQuery.setCaption("Please wait, the frequencies analysis can take some time"); pbQuery.setIndeterminate(true); pbQuery.setEnabled(true); addComponent(pbQuery); setComponentAlignment(pbQuery, Alignment.TOP_CENTER); chart = new FrequencyChart(this); chart.setHeight("350px"); chart.setVisible(false); addComponent(chart); btDownloadCSV = new Button("Download as CSV"); btDownloadCSV.setDescription("Download as CSV"); btDownloadCSV.setSizeUndefined(); addComponent(btDownloadCSV); setComponentAlignment(btDownloadCSV, Alignment.TOP_RIGHT); btDownloadCSV.setVisible(false); btDownloadCSV.setIcon(FontAwesome.DOWNLOAD); btDownloadCSV.addStyleName(ValoTheme.BUTTON_SMALL); final UI ui = UI.getCurrent(); // actually start query Callable<FrequencyTable> r = new Callable<FrequencyTable>() { @Override public FrequencyTable call() throws Exception { final FrequencyTable t = loadBeans(); ui.access(new Runnable() { @Override public void run() { showResult(t); } }); return t; } }; PollControl.callInBackground(1000, ui, r); } private FrequencyTable loadBeans() { FrequencyTable result = new FrequencyTable(); WebResource annisResource = Helper.getAnnisWebResource(); try { annisResource = annisResource.path("query").path("search").path("frequency").queryParam("q", aql) .queryParam("corpora", StringUtils.join(corpora, ",")) .queryParam("fields", createFieldsString()); result = annisResource.get(FrequencyTable.class); } catch (UniformInterfaceException ex) { String message; if (ex.getResponse().getStatus() == 400) { message = ex.getResponse().getEntity(String.class); } else if (ex.getResponse().getStatus() == 504) // gateway timeout { message = "Timeout: query exeuction took too long"; } else { message = "unknown error: " + ex; log.error(ex.getResponse().getEntity(String.class), ex); } Notification.show(message, Notification.Type.WARNING_MESSAGE); } catch (ClientHandlerException ex) { log.error("could not execute REST call to query frequency", ex); } return result; } private void showResult(FrequencyTable table) { if (queryPanel != null) { queryPanel.notifiyQueryFinished(); } recreateTable(table); btDownloadCSV.setVisible(true); FileDownloader downloader = new FileDownloader( new StreamResource(new CSVResource(table, freqDefinition), "frequency.txt")); downloader.extend(btDownloadCSV); chart.setVisible(true); FrequencyTable clippedTable = table; if (clippedTable.getEntries().size() > MAX_NUMBER_OF_CHART_ITEMS) { List<FrequencyTable.Entry> entries = new ArrayList<>(clippedTable.getEntries()); clippedTable = new FrequencyTable(); clippedTable.setEntries(entries.subList(0, MAX_NUMBER_OF_CHART_ITEMS)); clippedTable.setSum(table.getSum()); chart.setCaption("Showing historgram of top " + MAX_NUMBER_OF_CHART_ITEMS + " results, see table below for complete dataset."); } chart.setFrequencyData(clippedTable); } private String createFieldsString() { StringBuilder sb = new StringBuilder(); ListIterator<FrequencyTableEntry> it = freqDefinition.listIterator(); while (it.hasNext()) { FrequencyTableEntry e = it.next(); sb.append(e.getReferencedNode()).append(":"); if (e.getType() == FrequencyTableEntryType.span) { sb.append("tok"); } else { sb.append(e.getKey()); } if (it.hasNext()) { sb.append(","); } } return sb.toString(); } private void recreateTable(FrequencyTable table) { if (tblResult != null) { removeComponent(tblResult); } tblResult = new Table(); tblResult.setSizeFull(); tblResult.setCaption(table.getEntries().size() + " items with a total sum of " + table.getSum() + " (query on " + Joiner.on(", ").join(this.corpora) + ")"); tblResult.setSelectable(true); tblResult.setMultiSelect(false); tblResult.addStyleName("corpus-font-force"); if (!table.getEntries().isEmpty()) { FrequencyTable.Entry firstEntry = table.getEntries().iterator().next(); int tupelCount = firstEntry.getTupel().length; tblResult.addContainerProperty("rank", Integer.class, -1); for (int i = 1; i <= tupelCount; i++) { tblResult.addContainerProperty("tupel-" + i, String.class, ""); FrequencyTableEntry e = freqDefinition.get(i - 1); String caption = "#" + e.getReferencedNode() + " (" + (e.getType() == FrequencyTableEntryType.span ? "spanned text" : e.getKey()) + ")"; tblResult.setColumnHeader("tupel-" + i, caption); } tblResult.addContainerProperty("count", Long.class, -1l); int line = 0; for (FrequencyTable.Entry e : table.getEntries()) { Object[] cells = new Object[tupelCount + 2]; System.arraycopy(e.getTupel(), 0, cells, 1, tupelCount); cells[0] = line + 1; cells[cells.length - 1] = e.getCount(); tblResult.addItem(cells, "entry-" + line++); } } tblResult.addContainerProperty(pbQuery, null, table); addLexicalSort(tblResult.getContainerDataSource()); addComponent(tblResult); setExpandRatio(tblResult, 1.0f); pbQuery.setEnabled(true); removeComponent(pbQuery); } private void addLexicalSort(Container container) { ItemSorter sorter = new DefaultItemSorter(new IgnoreCaseComparator()); if (container instanceof IndexedContainer) { ((IndexedContainer) container).setItemSorter(sorter); } else if (container instanceof AbstractBeanContainer) { ((AbstractBeanContainer) container).setItemSorter(sorter); } } public static class IgnoreCaseComparator implements Comparator<Object>, Serializable { @Override @SuppressWarnings("unchecked") public int compare(Object o1, Object o2) { if (o1 instanceof String && o2 instanceof String) { String s1 = (String) o1; String s2 = (String) o2; Collator collator = Collator.getInstance(Locale.ENGLISH); collator.setStrength(Collator.PRIMARY); return collator.compare(s1, s2); } else { return Ordering.natural().compare((Comparable) o1, (Comparable) o2); } } } public static class CSVResource implements StreamResource.StreamSource { private final FrequencyTable data; private final List<FrequencyTableEntry> freqDefinition; public CSVResource(FrequencyTable data, List<FrequencyTableEntry> freqDefinition) { this.data = data; this.freqDefinition = freqDefinition; } @Override public InputStream getStream() { try { File tmpFile = File.createTempFile("annis-frequency", ".txt"); tmpFile.deleteOnExit(); try (Writer writer = new OutputStreamWriter(new FileOutputStream(tmpFile), Charsets.UTF_8)) { CSVWriter csv = new CSVWriter(writer, '\t', CSVWriter.NO_QUOTE_CHARACTER, '\\'); // write headers ArrayList<String> header = new ArrayList<>(); if (data.getEntries().size() > 0) { for (int i = 0; i < data.getEntries().iterator().next().getTupel().length; i++) { FrequencyTableEntry e = freqDefinition.get(i); String caption = "#" + e.getReferencedNode() + " (" + (e.getType() == FrequencyTableEntryType.span ? "spanned text" : e.getKey()) + ")"; header.add(caption); } } // add count header.add("count"); csv.writeNext(header.toArray(new String[0])); // write entries for (FrequencyTable.Entry e : data.getEntries()) { ArrayList<String> d = new ArrayList<>(); d.addAll(Arrays.asList(e.getTupel())); d.add("" + e.getCount()); csv.writeNext(d.toArray(new String[0])); } } return new FileInputStream(tmpFile); } catch (IOException ex) { log.error(null, ex); } return new ByteArrayInputStream(new byte[0]); } } public void selectRow(int i) { tblResult.setValue("entry-" + i); tblResult.setCurrentPageFirstItemId("entry-" + i); } }